Compare commits

..

139 Commits

Author SHA1 Message Date
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
Jason Turner
d2aba2ef56 Eliminate boost::lexical_cast usage completely #39 2012-06-03 09:20:15 -06:00
Jason Turner
832df7f9e8 Remove offending boost code which causes warnings in some cases #39 2012-06-02 17:45:10 -06:00
Jason Turner
6c53e08e9b Fix compiler warning in snow leopard 2012-06-01 15:07:53 -06:00
Jason Turner
254d176266 Set CMakeLists.txt to version 4.0.0 for release 2012-06-01 14:00:20 -06:00
Jason Turner
a5f29e93f5 Eliminate all VC++10 64bit Warnings. 2012-06-01 12:21:14 -06:00
Jason Turner
7f253bd6c1 Catch a few things found with more aggressive g++ warnings 2012-06-01 08:47:40 -06:00
Jason Turner
7cbd494123 It seems boost dropped the BOOST_GCC define? 2012-05-28 11:35:53 -06:00
Jason Turner
ed15cc1730 Clean up a few warnings found in Windows. 2012-05-28 10:48:19 -06:00
Jason Turner
db8863c736 Merge branch 'master' of https://github.com/ChaiScript/ChaiScript 2012-05-25 07:10:32 -06:00
Jason Turner
4233d21e5b Correct scope of operator calls
- Enhance reflection module to indicate inheritance
  - Add ability to catch errors thrown from a eval
    inside of a script
2012-05-24 19:25:29 -06:00
Jason Turner
f65e095e4d Update release notes 2012-05-24 15:45:52 -06:00
Jason Turner
7ad58c7bcd Apply cpo path from vim mailing list 2012-05-21 12:09:39 -06:00
Jason Turner
433905b33c Merge branch 'master' of https://github.com/ChaiScript/ChaiScript 2012-05-21 10:17:33 -06:00
Jason Turner
3a7eff1478 Move to a bit smarter stack based object management
- we store all function parameters until the f
    outer function call exits

  - this results in more values being stored longer than
    they need to be, but the results are predictable
    and no leaks
2012-05-21 10:16:16 -06:00
Jason Turner
ef46d1bf60 Remove Boxed_Value dependencies, they are not a solution 2012-05-21 08:18:33 -06:00
Jason Turner
654f7e6b01 Add unit test exposing how scope can leak into operator calls 2012-05-21 07:56:38 -06:00
Jonathan Turner
4aec12c68f Allow operator exprs to span lines 2012-05-20 10:47:50 -07:00
Jonathan Turner
a818e7b185 Merge branch 'master' of github.com:ChaiScript/ChaiScript 2012-05-20 10:17:43 -07:00
Jonathan Turner
5aed00dd0b Add ternary condition (?:) operator 2012-05-20 10:17:21 -07:00
Jason Turner
349425fe8a Make vector inplace construction consistent with map
- Clone elements into both vector and map
  - Be sure to drop dependencies after elements are cloned in
2012-05-20 07:04:22 -06:00
Jason Turner
6c57729779 Add unit test for pass_by_preference 2012-05-19 21:42:02 -06:00
Jason Turner
56757973b6 Actually reenable function 2012-05-19 18:05:41 -06:00
Jason Turner
f1f4aeb4be Add test and reenable function I accidentally commented out 2012-05-19 18:04:51 -06:00
Jason Turner
804de05a0a Fix object_lifetime_test which was broken by last perfomance fix 2012-05-19 09:50:49 -06:00
Jason Turner
0fd4b828f2 Fix some minor issues found by clang's static analyzer 2012-05-19 09:16:21 -06:00
Jason Turner
ae02706c71 Approx 12% speedup for function call heavy profile.chai 2012-05-19 07:09:55 -06:00
Jason Turner
c386af6813 Merge branch 'master' of https://github.com/ChaiScript/ChaiScript 2012-05-18 16:58:33 -06:00
Jason Turner
08c153abea Clean up some additional exception handling with new stack handler 2012-05-18 16:37:39 -06:00
Jason Turner
897ad7007f Get system introspection functions fully working 2012-05-18 16:25:13 -06:00
Jason Turner
13fb930676 First part of system introspection for objs and funcs added 2012-05-18 15:31:42 -06:00
Jonathan Turner
8af41b1d3c Add unit test for ignoring hash bang. 2012-05-18 08:43:03 -07:00
Jonathan Turner
025db4ce3a Oops. Properly handle empty switch statements. 2012-05-17 13:20:15 -07:00
Jonathan Turner
78f02c375e Add syntax support for switch/case/default. 2012-05-17 12:48:57 -07:00
Jonathan Turner
4e14a57016 Add support for switch/case/default statements. 2012-05-17 12:43:25 -07:00
Jason Turner
af1e02b0bb Update copyrights to 2012 #23 2012-05-16 11:55:51 -06:00
Jason Turner
4bcaa75fa4 Throw eval exception if a variable or function is redefined #28 2012-05-16 11:40:43 -06:00
Jason Turner
7deb2311f5 Restore CMakeLists.txt on head to working version
Reverted to revision: 277b4eec9a
2012-05-15 19:48:46 -06:00
Jonathan Turner
730bad9728 Adding support for building with clang/libcxx. 2012-05-15 14:58:38 -07:00
Jason Turner
437f6a03a9 Slight cleanup of the boxed_number cleanups from mgee 2012-05-14 18:09:55 -06:00
Jason Turner
94fefa0690 Fix broken example.cpp 2012-05-14 18:09:36 -06:00
Jason Turner
91dc3604f5 Merge pull request #27 from mgee/master
Improve Boxed_Number
2012-05-14 16:55:03 -07:00
Markus Groß
59dfc847ae Make Boxed_Number assignable from Boxed_Value. 2012-05-14 21:34:28 +02:00
Markus Groß
cdfefed385 Add default constructor for Boxed_Number 2012-05-14 20:13:39 +02:00
Jason Turner
b0b1549503 Fix cast for unsigned short #26 2012-05-14 09:33:35 -06:00
Jason Turner
277b4eec9a Add failing test for short comparisons #26 2012-05-14 09:22:03 -06:00
Jonathan Turner
41b0c7768c Adding header files to CMakeLists.txt. Hopefully this will help them
show up in IDEs (works for Qt Creator so far).
2012-03-11 14:06:18 -06:00
Jason Turner
3b95931973 Fixup some documentation 2012-01-30 11:53:12 -07:00
Jason Turner
13f98fa8ce Move "use" function to be public 2012-01-30 11:26:46 -07:00
Jason Turner
b0953fb466 Minor cleanup releated to attribute fix 2012-01-30 08:55:12 -07:00
Jason Turner
1186926f30 Fix duplicate object attribute name problem 2012-01-30 08:48:01 -07:00
Jason Turner
70db5d67ff Add failing unit test for dynamic object attributes with the same name 2012-01-30 07:55:54 -07:00
Jason Turner
d9727973c1 Add files missing from last checkin 2011-09-09 17:08:51 -06:00
Jason Turner
0293762904 Add ability to provide global consts in Module objects. Issue #14 2011-09-09 16:52:32 -06:00
Jason Turner
95c6131ce7 Add missing unit test file 2011-09-09 16:01:29 -06:00
Jason Turner
e326fe6f2d Add test for constructing from a pointer return value and fix test so it works. Task #13 2011-09-09 14:38:55 -06:00
Jason Turner
2b64c90a0e Merge branch 'master' of https://github.com/ChaiScript/ChaiScript
Conflicts:
	CMakeLists.txt

Fixed conflicted CMakeLists.txt
2011-09-09 13:58:19 -06:00
Jason Turner
dd0d91c7e3 Merge pull request #10 from svenstaro/master
Consistency fixes
2011-09-09 12:42:48 -07:00
Jason Turner
a386142fa6 Get chaiscript compiling with -pedantic. Closes issue #9 2011-09-09 13:40:50 -06:00
Sven-Hendrik Haase
cacc744411 More consistency fixes 2011-08-03 19:25:02 +02:00
Sven-Hendrik Haase
2d23578e0b Removing unused variables 2011-08-03 19:22:18 +02:00
Sven-Hendrik Haase
f8880066ea Consistency fix 2011-08-03 16:10:13 +02:00
Jason Turner
a85423869f Edited releasenotes.txt via GitHub 2011-06-18 15:41:27 -07:00
Jason Turner
469c02ad14 Edited releasenotes.txt via GitHub 2011-06-18 15:35:26 -07:00
Jason Turner
a549e41558 Merge branch 'master' of https://github.com/ChaiScript/ChaiScript 2011-06-11 17:05:53 -06:00
Jason Turner
a82c892a4e Merge branch 'master' of https://github.com/ChaiScript/ChaiScript 2011-06-11 07:15:02 -06:00
Jason Turner
c839e4bc21 Handle unnecessary MSVC compiler warnings. 2011-06-08 19:19:59 -06:00
93 changed files with 4182 additions and 1232 deletions

View File

@@ -13,11 +13,11 @@ 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 3)
set(CPACK_PACKAGE_VERSION_MINOR 1)
set(CPACK_PACKAGE_VERSION_MAJOR 4)
set(CPACK_PACKAGE_VERSION_MINOR 3)
set(CPACK_PACKAGE_VERSION_PATCH 0)
set(CPACK_PACKAGE_EXECUTABLES "chai;ChaiScript Eval")
set(CPACK_PACKAGE_VENDOR "ChaiScript.com")
@@ -39,62 +39,71 @@ configure_file(Doxyfile.in ${CMAKE_BINARY_DIR}/Doxyfile)
include(CTest)
include(CPack)
FIND_LIBRARY(READLINE_LIBRARY NAMES readline PATH /usr/lib /usr/local/lib /opt/local/lib)
find_library(READLINE_LIBRARY NAMES readline PATH /usr/lib /usr/local/lib /opt/local/lib)
enable_testing()
MESSAGE(STATUS "Detecting readline support")
message(STATUS "Detecting readline support")
if (READLINE_LIBRARY)
MESSAGE(STATUS "Found: ${READLINE_LIBRARY}")
SET (READLINE_LIB readline)
ADD_DEFINITIONS(/DREADLINE_AVAILABLE)
message(STATUS "Found: ${READLINE_LIBRARY}")
set (READLINE_LIB readline)
add_definitions(/DREADLINE_AVAILABLE)
else(READLINE_LIBRARY)
MESSAGE(STATUS "Not Found")
SET (READLINE_LIB )
SET (READLINE_FLAG )
message(STATUS "Not Found")
set (READLINE_LIB )
set (READLINE_FLAG )
endif(READLINE_LIBRARY)
IF(MSVC)
ADD_DEFINITIONS(/W4)
IF(CMAKE_CL_64)
ADD_DEFINITIONS(/bigobj)
ENDIF()
ELSE()
ADD_DEFINITIONS(-Wall -Wextra -Wshadow)
if(MSVC)
add_definitions(/W4)
if(CMAKE_CL_64)
add_definitions(/bigobj)
endif()
else()
add_definitions(-Wall -Wextra -Wshadow -pedantic)
IF (APPLE)
if (APPLE)
# -Wno-missing-field-initializers is for boost on macos
ADD_DEFINITIONS(-Wno-missing-field-initializers -Wno-sign-compare)
ENDIF()
ENDIF()
add_definitions(-Wno-missing-field-initializers -Wno-sign-compare)
endif()
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(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)
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)
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()
if (MSVC)
list(APPEND LIBS ${READLINE_LIB})
if (NOT MSVC)
# Boost on MSVC does automatic linking
SET(LIBS ${DYNAMIC_LOADER} ${READLINE_LIB})
else()
SET(LIBS ${DYNAMIC_LOADER} ${Boost_LIBRARIES} ${READLINE_LIB})
list(APPEND LIBS ${Boost_LIBRARIES})
endif()
if (CMAKE_COMPILER_2005)
@@ -104,7 +113,7 @@ endif()
include_directories(${Boost_INCLUDE_DIRS})
include_directories(${Boost_INCLUDE_DIR})
add_executable(chai src/main.cpp)
add_executable(chai src/main.cpp ${Chai_INCLUDES})
target_link_libraries(chai ${LIBS})
if (BUILD_SAMPLES)
@@ -128,7 +137,7 @@ file(GLOB UNIT_TESTS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/unittests/ ${CMAKE_CUR
list(SORT UNIT_TESTS)
IF(BUILD_TESTING)
if(BUILD_TESTING)
option(UNIT_TEST_LIGHT "Unit tests light (expect module loading failures)" FALSE)
foreach(filename ${UNIT_TESTS})
@@ -136,13 +145,13 @@ IF(BUILD_TESTING)
add_test(${filename} chai ${CMAKE_CURRENT_SOURCE_DIR}/unittests/unit_test.inc ${CMAKE_CURRENT_SOURCE_DIR}/unittests/${filename})
endforeach(filename)
SET_PROPERTY(TEST ${UNIT_TESTS}
set_property(TEST ${UNIT_TESTS}
PROPERTY ENVIRONMENT
"CHAI_USE_PATH=${CMAKE_CURRENT_SOURCE_DIR}/unittests/"
"CHAI_MODULE_PATH=${CMAKE_CURRENT_BINARY_DIR}/"
)
IF (NOT UNIT_TEST_LIGHT)
if (NOT UNIT_TEST_LIGHT)
add_executable(utility_test unittests/utility_test.cpp)
target_link_libraries(utility_test ${LIBS})
add_test(NAME Utility_Test COMMAND utility_test)
@@ -179,6 +188,47 @@ IF(BUILD_TESTING)
target_link_libraries(eval_catch_exception_test ${LIBS})
add_test(NAME Eval_Catch_Exception_Test COMMAND eval_catch_exception_test)
add_executable(short_comparison_test unittests/short_comparison_test.cpp)
target_link_libraries(short_comparison_test ${LIBS})
add_test(NAME Short_Comparison_Test COMMAND short_comparison_test)
add_executable(expected_eval_errors_test unittests/expected_eval_errors_test.cpp)
target_link_libraries(expected_eval_errors_test ${LIBS})
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})
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})
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})
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})
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})
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})
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
unittests/multifile_test_module.cpp)
target_link_libraries(multifile_test ${LIBS})
@@ -188,10 +238,11 @@ IF(BUILD_TESTING)
target_link_libraries(test_module ${LIBS})
install(TARGETS test_module RUNTIME DESTINATION bin LIBRARY DESTINATION lib/chaiscript)
ENDIF()
ENDIF(BUILD_TESTING)
endif()
endif(BUILD_TESTING)
install(TARGETS chai ${MODULES} RUNTIME DESTINATION bin LIBRARY DESTINATION lib/chaiscript )
install(DIRECTORY include/chaiscript DESTINATION include
PATTERN "*.hpp"
PATTERN "*/.svn*" EXCLUDE
@@ -209,8 +260,7 @@ install(DIRECTORY samples DESTINATION share/chaiscript
PATTERN "*/.git*" EXCLUDE
PATTERN "*~" EXCLUDE)
configure_file(contrib/pkgconfig/chaiscript.pc.in lib/pkgconfig/chaiscript.pc @ONLY)
install(FILES "${chaiscript_BINARY_DIR}/lib/pkgconfig/chaiscript.pc"
DESTINATION lib/pkgconfig)
DESTINATION lib/pkgconfig)

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

@@ -48,7 +48,7 @@ $language_data = array (
'ESCAPE_CHAR' => '\\',
'KEYWORDS' => array(
1 => array(
'break', 'else', 'else if', 'eval', 'for', 'if', 'return', 'while', 'try', 'catch', 'finally',
'break', 'else', 'else if', 'eval', 'for', 'if', 'return', 'while', 'try', 'catch', 'finally', 'case', 'switch', 'default',
),
2 => array(
'def', 'false', 'fun', 'true', 'var', 'attr',

View File

@@ -7,6 +7,9 @@ if exists("b:current_syntax")
finish
end
let s:cpo_save = &cpo
set cpo&vim
syn case match
" syncing method
@@ -42,7 +45,7 @@ syn match chaiscriptNumber "\<0b[01]\+\>"
" Various language features
syn keyword chaiscriptCond if else
syn keyword chaiscriptRepeat while for do
syn keyword chaiscriptStatement break continue return
syn keyword chaiscriptStatement break continue return switch case default
syn keyword chaiscriptExceptions try catch throw
"Keyword
@@ -91,4 +94,6 @@ hi def link chaiscriptEval Special
let b:current_syntax = "chaiscript"
let &cpo = s:cpo_save
unlet s:cpo_save
" vim: nowrap sw=2 sts=2 ts=8 noet

View File

@@ -1,7 +1,7 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2011, Jonathan Turner (jonathan@emptycrate.com)
// and Jason Turner (jason@emptycrate.com)
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_HPP_
@@ -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;
@@ -192,8 +195,8 @@
/// Overloaded methods will need some help, to hint the compiler as to which overload you want:
///
/// \code
/// chai.add(fun<void (MyClass::*)()>(&MyClass::overloadedmethod), "overloadedmethod"));
/// chai.add(fun<void (MyClass::*)(const std::string &)>(&MyClass::overloadedmethod, "overloadedmethod"));
/// chai.add(fun<void (MyClass::*)()>(&MyClass::overloadedmethod), "overloadedmethod");
/// chai.add(fun<void (MyClass::*)(const std::string &)>(&MyClass::overloadedmethod), "overloadedmethod");
/// \endcode
///
/// There are also shortcuts built into chaiscript::fun for binding up to the first two parameters of the function.

View File

@@ -1,14 +1,23 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2011, Jonathan Turner (jonathan@emptycrate.com)
// and Jason Turner (jason@emptycrate.com)
// Copyright 2009-2012, Jonathan Turner (jonathan@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
#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
@@ -75,6 +84,8 @@ namespace chaiscript
{
public:
unique_lock(T &) {}
void lock() {}
void unlock() {}
};
template<typename T>
@@ -82,6 +93,7 @@ namespace chaiscript
{
public:
shared_lock(T &) {}
void lock() {}
void unlock() {}
};

View File

@@ -1,7 +1,7 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2011, Jonathan Turner (jonathan@emptycrate.com)
// and Jason Turner (jason@emptycrate.com)
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_BAD_BOXED_CAST_HPP_
@@ -33,7 +33,7 @@ namespace chaiscript
}
bad_boxed_cast(const std::string &t_what) throw()
: m_what(t_what)
: to(0), m_what(t_what)
{
}

View File

@@ -1,7 +1,7 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2011, Jonathan Turner (jonathan@emptycrate.com)
// and Jason Turner (jason@emptycrate.com)
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#include <boost/preprocessor.hpp>
@@ -89,5 +89,6 @@ namespace chaiscript
#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-2011, 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_BOOTSTRAP_HPP_
@@ -13,6 +13,7 @@
#include "operators.hpp"
#include "boxed_number.hpp"
#include <boost/function_types/result_type.hpp>
#include <sstream>
namespace chaiscript
{
@@ -93,24 +94,31 @@ namespace chaiscript
/**
* to_string function for internal use. Uses ostream operator<<
*/
* to_string function for internal use. Uses ostream operator<<
*/
template<typename Input>
std::string to_string(Input i)
{
return boost::lexical_cast<std::string>(i);
}
std::string to_string(Input i)
{
std::stringstream ss;
ss << i;
return ss.str();
}
/**
* Internal function for converting from a string to a value
* uses ostream operator >> to perform the conversion
*/
* Internal function for converting from a string to a value
* uses ostream operator >> to perform the conversion
*/
template<typename Input>
Input parse_string(const std::string &i)
{
return boost::lexical_cast<Input>(i);
}
Input parse_string(const std::string &i)
{
std::stringstream ss(i);
Input t;
ss >> t;
return t;
}
@@ -265,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)
{
boost::shared_ptr<const dispatch::Dynamic_Proxy_Function> pf = boost::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(t_pf);
if (pf)
{
return pf->get_guard();
if (pf->get_guard()) {
return true;
} else {
return false;
}
} else {
return false;
}
@@ -375,7 +372,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==), "==");
@@ -419,12 +415,10 @@ 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");
typedef bool (Type_Info::*typeinfocompare)(const Type_Info &) const;
m->add(fun(typeinfocompare(&Type_Info::operator==)), "==");
m->add(fun(&Type_Info::bare_equal), "bare_equal");
basic_constructors<bool>("bool", m);
@@ -441,6 +435,7 @@ 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);
@@ -469,9 +464,6 @@ namespace chaiscript
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(boost::bind(&call_exists, _1))),
"call_exists");
m->add(fun(&type_match), "type_match");
return m;

View File

@@ -1,16 +1,13 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2011, Jonathan Turner (jonathan@emptycrate.com)
// and Jason Turner (jason@emptycrate.com)
// Copyright 2009-2012, Jonathan Turner (jonathan@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_
@@ -25,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
{
@@ -147,9 +143,106 @@ namespace chaiscript
};
namespace detail {
/**
* Add Bidir_Range support for the given ContainerType
*/
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
}
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()))
{
@@ -168,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)
{
@@ -186,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)
{
@@ -214,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()))
{
@@ -236,10 +326,9 @@ namespace chaiscript
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()))
{
@@ -248,24 +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(boost::function<int (const ContainerType *)>(boost::mem_fn(&ContainerType::size))), "size");
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()))
{
@@ -275,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()))
{
@@ -296,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()))
{
@@ -322,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()))
{
@@ -348,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()))
{
@@ -371,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()))
{
@@ -383,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(boost::function<int (const ContainerType *, const typename ContainerType::key_type &)>(boost::mem_fn(&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()))
{
@@ -417,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()))
{
@@ -437,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()))
{
@@ -483,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()))
{
@@ -497,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);
@@ -511,19 +631,19 @@ namespace chaiscript
}
m->add(fun(&String::push_back), push_back_name);
typedef typename String::size_type (String::*find_func_ptr)(const String &, typename String::size_type) const;
typedef boost::function<int (const String *, const String &, int)> find_func;
m->add(fun(find_func(boost::mem_fn(static_cast<find_func_ptr>(&String::find)))), "find");
m->add(fun(find_func(boost::mem_fn(static_cast<find_func_ptr>(&String::rfind)))), "rfind");
m->add(fun(find_func(boost::mem_fn(static_cast<find_func_ptr>(&String::find_first_of)))), "find_first_of");
m->add(fun(find_func(boost::mem_fn(static_cast<find_func_ptr>(&String::find_last_of)))), "find_last_of");
m->add(fun(find_func(boost::mem_fn(static_cast<find_func_ptr>(&String::find_first_not_of)))), "find_first_not_of");
m->add(fun(find_func(boost::mem_fn(static_cast<find_func_ptr>(&String::find_last_not_of)))), "find_last_not_of");
m->add(fun(&String::c_str), "c_str");
m->add(fun(&String::data), "data");
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,11 +1,11 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2011, Jonathan Turner (jonathan@emptycrate.com)
// and Jason Turner (jason@emptycrate.com)
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef __boxed_cast_hpp__
#define __boxed_cast_hpp__
#ifndef CHAISCRIPT_BOXED_CAST_HPP_
#define CHAISCRIPT_BOXED_CAST_HPP_
#include "type_info.hpp"
#include "boxed_value.hpp"
@@ -68,10 +68,10 @@ namespace chaiscript
/// 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);
return detail::Cast_Helper<Type>::cast(bv, t_conversions);
} catch (const boost::bad_any_cast &) {
#ifdef BOOST_MSVC
@@ -81,12 +81,12 @@ namespace chaiscript
#pragma warning(disable : 4127)
#endif
if (boost::is_polymorphic<typename detail::Stripped_Type<Type>::type>::value)
if (boost::is_polymorphic<typename detail::Stripped_Type<Type>::type>::value && t_conversions)
{
try {
// We will not catch any bad_boxed_dynamic_cast that is thrown, let the user get it
// either way, we are not responsible if it doesn't work
return detail::Cast_Helper<Type>::cast(detail::boxed_dynamic_cast<Type>(bv));
return detail::Cast_Helper<Type>::cast(t_conversions->boxed_dynamic_cast<Type>(bv), t_conversions);
} catch (const boost::bad_any_cast &) {
throw exception::bad_boxed_cast(bv.get_type_info(), typeid(Type));
}

View File

@@ -1,7 +1,7 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2011, Jonathan Turner (jonathan@emptycrate.com)
// and Jason Turner (jason@emptycrate.com)
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_BOXED_CAST_HELPER_HPP_
@@ -17,6 +17,8 @@
namespace chaiscript
{
class Dynamic_Cast_Conversions;
namespace detail
{
// Cast_Helper_Inner helper classes
@@ -29,7 +31,7 @@ namespace chaiscript
{
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())
{
@@ -71,7 +73,7 @@ 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())
{
@@ -100,7 +102,7 @@ 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())
{
@@ -119,7 +121,7 @@ namespace chaiscript
{
typedef typename boost::reference_wrapper<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())
{
@@ -138,7 +140,7 @@ namespace chaiscript
{
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 boost::any_cast<boost::shared_ptr<Result> >(ob.get());
}
@@ -152,7 +154,7 @@ namespace chaiscript
{
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())
{
@@ -200,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;
}
@@ -261,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-2011, 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_BOXED_NUMERIC_HPP_
@@ -10,17 +10,26 @@
#include "boxed_value.hpp"
#include "../language/chaiscript_algebraic.hpp"
#include <boost/cstdint.hpp>
#include <sstream>
namespace chaiscript
{
#ifdef BOOST_MSVC
#pragma warning(push)
#pragma warning(disable : 4244 4018 4389 4146)
#endif
/// \brief Represents any numeric type, generically. Used internally for generic operations between POD values
class Boxed_Number
{
private:
struct boolean
{
#ifdef __GNUC__
#pragma GCC diagnostic ignored "-Wsign-compare"
#endif
template<typename T, typename U>
static Boxed_Value go(Operators::Opers t_oper, const T &t, const U &u, const Boxed_Value &)
{
@@ -41,7 +50,6 @@ namespace chaiscript
default:
throw boost::bad_any_cast();
}
throw boost::bad_any_cast();
}
};
@@ -137,7 +145,6 @@ namespace chaiscript
default:
throw boost::bad_any_cast();
}
throw boost::bad_any_cast();
}
};
@@ -163,7 +170,6 @@ namespace chaiscript
default:
throw boost::bad_any_cast();
}
throw boost::bad_any_cast();
}
};
@@ -276,7 +282,7 @@ namespace chaiscript
} 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::int32_t, false>(t_oper, t_lhs, t_rhs);
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)) {
@@ -294,24 +300,160 @@ namespace chaiscript
}
}
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>
std::string to_string_aux(const Boxed_Value &v) const
{
std::ostringstream oss;
oss << *static_cast<const Source *>(v.get_const_ptr());
return oss.str();
}
public:
Boxed_Number()
: bv(Boxed_Value(0))
{
}
Boxed_Number(const Boxed_Value &v)
: bv(v)
{
const Type_Info &inp_ = v.get_type_info();
if (inp_ == typeid(bool))
{
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();
}
if (!inp_.is_arithmetic())
{
}
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
{
@@ -378,6 +520,27 @@ namespace chaiscript
return oper(Operators::assign_bitwise_and, this->bv, t_rhs.bv);
}
void validate_boxed_number(const Boxed_Value &v)
{
const Type_Info &inp_ = v.get_type_info();
if (inp_ == typeid(bool))
{
throw boost::bad_any_cast();
}
if (!inp_.is_arithmetic())
{
throw boost::bad_any_cast();
}
}
Boxed_Number operator=(const Boxed_Value &v)
{
validate_boxed_number(v);
bv = v;
return *this;
}
Boxed_Number operator=(const Boxed_Number &t_rhs) const
{
return oper(Operators::assign, this->bv, t_rhs.bv);
@@ -658,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);
}
@@ -681,6 +844,10 @@ namespace chaiscript
};
}
#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-2011, 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_BOXED_VALUE_HPP_
@@ -13,6 +13,19 @@
#include <map>
#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>
@@ -71,19 +84,17 @@ namespace chaiscript
void *m_data_ptr;
const void *m_const_data_ptr;
bool m_is_ref;
std::vector<boost::shared_ptr<Data> > m_dependencies;
};
struct Object_Data
{
static boost::shared_ptr<Data> get(Boxed_Value::Void_Type)
{
return boost::shared_ptr<Data> (new Data(
return boost::make_shared<Data>(
detail::Get_Type_Info<void>::get(),
boost::any(),
false,
0)
);
static_cast<void *>(0));
}
template<typename T>
@@ -95,12 +106,11 @@ namespace chaiscript
template<typename T>
static boost::shared_ptr<Data> get(const boost::shared_ptr<T> &obj)
{
return boost::shared_ptr<Data>(new Data(
return boost::make_shared<Data>(
detail::Get_Type_Info<T>::get(),
boost::any(obj),
false,
obj.get())
);
obj.get());
}
template<typename T>
@@ -112,34 +122,31 @@ namespace chaiscript
template<typename T>
static boost::shared_ptr<Data> get(boost::reference_wrapper<T> obj)
{
return boost::shared_ptr<Data>(new Data(
return boost::make_shared<Data>(
detail::Get_Type_Info<T>::get(),
boost::any(obj),
true,
obj.get_pointer())
);
obj.get_pointer());
}
template<typename T>
static boost::shared_ptr<Data> get(const T& t)
{
boost::shared_ptr<T> p(new T(t));
return boost::shared_ptr<Data>(new Data(
return boost::make_shared<Data>(
detail::Get_Type_Info<T>::get(),
boost::any(p),
false,
p.get())
);
p.get());
}
static boost::shared_ptr<Data> get()
{
return boost::shared_ptr<Data> (new Data(
return boost::make_shared<Data>(
Type_Info(),
boost::any(),
false,
0)
);
static_cast<void *>(0));
}
};
@@ -242,24 +249,6 @@ namespace chaiscript
return !is_ref();
}
void clear_dependencies()
{
m_data->m_dependencies.clear();
}
template<typename InItr>
void add_dependencies(InItr begin, const InItr &end)
{
while (begin != end)
{
if (begin->m_data != m_data)
{
m_data->m_dependencies.push_back(begin->m_data);
}
++begin;
}
}
void *get_ptr() const
{
return m_data->m_data_ptr;

View File

@@ -1,7 +1,7 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2011, Jonathan Turner (jonathan@emptycrate.com)
// and Jason Turner (jason@emptycrate.com)
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_DISPATCHKIT_HPP_
@@ -12,12 +12,11 @@
#include <map>
#include <set>
#include <boost/shared_ptr.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/tuple/tuple.hpp>
#include <stdexcept>
#include <vector>
#include <iostream>
#include <deque>
#include <list>
#include "boxed_value.hpp"
#include "type_info.hpp"
@@ -32,6 +31,93 @@
namespace chaiscript
{
namespace exception
{
/**
* Exception thrown in the case that an object name is invalid because it is a reserved word
*/
class reserved_word_error : public std::runtime_error
{
public:
reserved_word_error(const std::string &t_word) throw()
: std::runtime_error("Reserved word not allowed in object name: " + t_word), m_word(t_word)
{
}
virtual ~reserved_word_error() throw() {}
std::string word() const
{
return m_word;
}
private:
std::string m_word;
};
/**
* Exception thrown in the case that 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
*/
class name_conflict_error : public std::runtime_error
{
public:
name_conflict_error(const std::string &t_name) throw()
: std::runtime_error("Name already exists in current context " + t_name), m_name(t_name)
{
}
virtual ~name_conflict_error() throw() {}
std::string name() const
{
return m_name;
}
private:
std::string m_name;
};
/**
* Exception thrown in the case that a non-const object was added as a shared object
*/
class global_non_const : public std::runtime_error
{
public:
global_non_const() throw()
: std::runtime_error("a global object must be const")
{
}
virtual ~global_non_const() throw() {}
};
}
/// \brief Holds a collection of ChaiScript settings which can be applied to the ChaiScript runtime.
/// Used to implement loadable module support.
class Module
@@ -55,6 +141,17 @@ namespace chaiscript
return *this;
}
Module &add_global_const(const Boxed_Value &t_bv, const std::string &t_name)
{
if (!t_bv.is_const())
{
throw exception::global_non_const();
}
m_globals.push_back(std::make_pair(t_bv, t_name));
return *this;
}
//Add a bit of chaiscript to eval during module implementation
Module &eval(const std::string &str)
@@ -76,11 +173,13 @@ namespace chaiscript
apply(m_funcs.begin(), m_funcs.end(), t_engine);
apply_eval(m_evals.begin(), m_evals.end(), t_eval);
apply_single(m_conversions.begin(), m_conversions.end(), t_engine);
apply_globals(m_globals.begin(), m_globals.end(), t_engine);
}
private:
std::vector<std::pair<Type_Info, std::string> > m_typeinfos;
std::vector<std::pair<Proxy_Function, std::string> > m_funcs;
std::vector<std::pair<Boxed_Value, std::string> > m_globals;
std::vector<std::string> m_evals;
std::vector<Dynamic_Cast_Conversion> m_conversions;
@@ -89,7 +188,22 @@ namespace chaiscript
{
while (begin != end)
{
t.add(begin->first, begin->second);
try {
t.add(begin->first, begin->second);
} catch (const exception::name_conflict_error &) {
/// \todo Should we throw an error if there's a name conflict
/// while applying a module?
}
++begin;
}
}
template<typename T, typename InItr>
void apply_globals(InItr begin, InItr end, T &t) const
{
while (begin != end)
{
t.add_global_const(begin->first, begin->second);
++begin;
}
}
@@ -130,9 +244,9 @@ namespace chaiscript
public:
Dispatch_Function(const std::vector<Proxy_Function> &t_funcs)
: Proxy_Function_Base(build_type_infos(t_funcs)),
m_funcs(t_funcs)
{
}
m_funcs(t_funcs)
{
}
virtual bool operator==(const dispatch::Proxy_Function_Base &rhs) const
{
@@ -182,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;
@@ -191,7 +305,7 @@ namespace chaiscript
while (begin != end)
{
if ((*begin)->call_match(vals))
if ((*begin)->call_match(vals, t_conversions))
{
return true;
} else {
@@ -208,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:
@@ -266,48 +380,6 @@ namespace chaiscript
};
}
namespace exception
{
/**
* Exception thrown in the case that a multi method dispatch fails
* because no matching function was found
* at runtime due to either an arity_error, a guard_error or a bad_boxed_cast
* exception
*/
class reserved_word_error : public std::runtime_error
{
public:
reserved_word_error(const std::string &t_word) throw()
: std::runtime_error("Reserved word not allowed in object name: " + t_word), m_word(t_word)
{
}
virtual ~reserved_word_error() throw() {}
std::string word() const
{
return m_word;
}
private:
std::string m_word;
};
/**
* Exception thrown in the case that a non-const object was added as a shared object
*/
class global_non_const : public std::runtime_error
{
public:
global_non_const() throw()
: std::runtime_error("a global object must be const")
{
}
virtual ~global_non_const() throw() {}
};
}
namespace detail
{
@@ -326,6 +398,7 @@ namespace chaiscript
struct State
{
std::map<std::string, std::vector<Proxy_Function> > m_functions;
std::map<std::string, Proxy_Function> m_function_objects;
std::map<std::string, Boxed_Value> m_global_objects;
Type_Name_Map m_types;
std::set<std::string> m_reserved_words;
@@ -338,25 +411,30 @@ namespace chaiscript
~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);
}
/**
* Add a new conversion for upcasting to a base class
*/
void add(const Dynamic_Cast_Conversion &d)
{
m_conversions.push_back(d);
return detail::Dynamic_Conversions::get().add_conversion(d);
m_conversions.add_conversion(d);
}
/**
* Add a new named Proxy_Function to the system
*/
bool add(const Proxy_Function &f, const std::string &name)
void add(const Proxy_Function &f, const std::string &name)
{
validate_object_name(name);
return add_function(f, name);
add_function(f, name);
}
/**
@@ -381,6 +459,7 @@ namespace chaiscript
add_object(name, obj);
}
/**
* Adds a named object to the current scope
*/
@@ -388,7 +467,15 @@ namespace chaiscript
{
StackData &stack = get_stack_data();
validate_object_name(name);
stack.back()[name] = obj;
Scope &scope = stack.back();
Scope::iterator itr = scope.find(name);
if (itr != stack.back().end())
{
throw exception::name_conflict_error(name);
} else {
stack.back().insert(std::make_pair(name, obj));
}
}
/**
@@ -404,9 +491,33 @@ namespace chaiscript
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l(m_global_object_mutex);
m_state.m_global_objects[name] = obj;
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 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
*/
@@ -430,28 +541,24 @@ namespace chaiscript
}
}
/**
* Swaps out the stack with a new stack
* \returns the old stack
* \param[in] s The new stack
*/
Stack set_stack(const Stack &s)
{
Stack old = m_stack_holder->stack;
m_stack_holder->stack = s;
return old;
}
Stack new_stack() const
/// Pushes a new stack on to the list of stacks
void new_stack()
{
Stack s(new Stack::element_type());
s->push_back(Scope());
return s;
m_stack_holder->stacks.push_back(s);
}
void pop_stack()
{
m_stack_holder->stacks.pop_back();
}
/// \returns the current stack
Stack get_stack() const
{
return m_stack_holder->stack;
return m_stack_holder->stacks.back();
}
/**
@@ -491,21 +598,7 @@ namespace chaiscript
}
// If all that failed, then check to see if it's a function
std::vector<Proxy_Function> funcs = get_function(name);
if (funcs.empty())
{
throw std::range_error("Object not known: " + name);
} else {
if (funcs.size() == 1)
{
// Return the first item if there is only one,
// no reason to take the cast of the extra level of dispatch
return const_var(*funcs.begin());
} else {
return Boxed_Value(Const_Proxy_Function(new Dispatch_Function(funcs)));
}
}
return get_function_object(name);
}
/**
@@ -588,9 +681,26 @@ namespace chaiscript
} else {
return std::vector<Proxy_Function>();
}
}
/// \returns a function object (Boxed_Value wrapper) if it exists
/// \throws std::range_error if it does not
Boxed_Value get_function_object(const std::string &t_name) const
{
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
const std::map<std::string, Proxy_Function> &funs = get_function_objects_int();
std::map<std::string, Proxy_Function>::const_iterator itr = funs.find(t_name);
if (itr != funs.end())
{
return const_var(itr->second);
} else {
throw std::range_error("Object not found: " + t_name);
}
}
/**
* Return true if a function exists
*/
@@ -602,6 +712,78 @@ 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
///
std::map<std::string, Boxed_Value> get_scripting_objects() const
{
// We don't want the current context, but one up if it exists
StackData &stack = (m_stack_holder->stacks.size()==1)?(*(m_stack_holder->stacks.back())):(*m_stack_holder->stacks[m_stack_holder->stacks.size()-2]);
std::map<std::string, Boxed_Value> retval;
// note: map insert doesn't overwrite existing values, which is why this works
for (StackData::reverse_iterator itr = stack.rbegin(); itr != stack.rend(); ++itr)
{
retval.insert(itr->begin(), itr->end());
}
// add the global values
{
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_global_object_mutex);
retval.insert(m_state.m_global_objects.begin(), m_state.m_global_objects.end());
}
return retval;
}
///
/// Get a map of all functions that can be seen from a scripting context
///
std::map<std::string, Boxed_Value> get_function_objects() const
{
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
const std::map<std::string, Proxy_Function> &funs = get_function_objects_int();
std::map<std::string, Boxed_Value> objs;
for (std::map<std::string, Proxy_Function>::const_iterator itr = funs.begin();
itr != funs.end();
++itr)
{
objs.insert(std::make_pair(itr->first, const_var(itr->second)));
}
return objs;
}
/**
* Get a vector of all registered functions
*/
@@ -635,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
@@ -665,10 +852,9 @@ namespace chaiscript
/**
* Dump object info to stdout
*/
void dump_object(Boxed_Value o) const
void dump_object(const Boxed_Value &o) const
{
Type_Info ti = o.get_type_info();
std::cout << (ti.is_const()?"const ":"") << get_type_name(ti) << std::endl;
std::cout << (o.is_const()?"const ":"") << type_name(o) << std::endl;
}
/**
@@ -709,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
*/
@@ -760,7 +962,7 @@ namespace chaiscript
return false;
}
std::string type_name(Boxed_Value obj) const
std::string type_name(const Boxed_Value &obj) const
{
return get_type_name(obj.get_type_info());
}
@@ -781,6 +983,29 @@ namespace chaiscript
m_state = t_state;
}
void save_function_params(const std::vector<Boxed_Value> &t_params)
{
m_stack_holder->call_params.insert(m_stack_holder->call_params.begin(), t_params.begin(), t_params.end());
}
void new_function_call()
{
++m_stack_holder->call_depth;
}
void pop_function_call()
{
--m_stack_holder->call_depth;
assert(m_stack_holder->call_depth >= 0);
if (m_stack_holder->call_depth == 0)
{
/// \todo Critical: this needs to be smarter, memory can expand quickly
/// in tight loops involving function calls
m_stack_holder->call_params.clear();
}
}
private:
/**
@@ -789,7 +1014,17 @@ namespace chaiscript
*/
StackData &get_stack_data() const
{
return *(m_stack_holder->stack);
return *(m_stack_holder->stacks.back());
}
const std::map<std::string, Proxy_Function> &get_function_objects_int() const
{
return m_state.m_function_objects;
}
std::map<std::string, Proxy_Function> &get_function_objects_int()
{
return m_state.m_function_objects;
}
const std::map<std::string, std::vector<Proxy_Function> > &get_functions_int() const
@@ -902,6 +1137,10 @@ 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())
@@ -911,11 +1150,10 @@ namespace chaiscript
}
/**
* Implementation detail for adding a function. Returns
* true if the function was added, false if a function with the
* same signature and name already exists.
* Implementation detail for adding a function.
* \throws exception::name_conflict_error if there's a function matching the given one being added
*/
bool add_function(const Proxy_Function &t_f, const std::string &t_name)
void add_function(const Proxy_Function &t_f, const std::string &t_name)
{
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
@@ -924,6 +1162,8 @@ namespace chaiscript
std::map<std::string, std::vector<Proxy_Function> >::iterator itr
= funcs.find(t_name);
std::map<std::string, Proxy_Function> &func_objs = get_function_objects_int();
if (itr != funcs.end())
{
std::vector<Proxy_Function> &vec = itr->second;
@@ -933,19 +1173,29 @@ namespace chaiscript
{
if ((*t_f) == *(*itr2))
{
return false;
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);
funcs.insert(std::make_pair(t_name, vec));
func_objs[t_name] = t_f;
}
return true;
}
mutable chaiscript::detail::threading::shared_mutex m_mutex;
@@ -954,15 +1204,20 @@ namespace chaiscript
struct Stack_Holder
{
Stack_Holder()
: stack(new StackData())
: call_depth(0)
{
stack->push_back(Scope());
Stack s(new StackData());
s->push_back(Scope());
stacks.push_back(s);
}
Stack stack;
std::deque<Stack> stacks;
std::list<Boxed_Value> call_params;
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-2011, 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_DYNAMIC_CAST_CONVERSION_HPP_
@@ -47,7 +47,8 @@ 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;
const Type_Info &base()
{
return m_base;
@@ -63,6 +64,8 @@ namespace chaiscript
{
}
virtual ~Dynamic_Conversion() {}
private:
Type_Info m_base;
Type_Info m_derived;
@@ -70,7 +73,7 @@ namespace chaiscript
};
template<typename Base, typename Derived>
class Dynamic_Conversion_Impl : public Dynamic_Conversion
class Dynamic_Conversion_Impl : public Dynamic_Conversion
{
public:
Dynamic_Conversion_Impl()
@@ -78,7 +81,7 @@ namespace chaiscript
{
}
virtual Boxed_Value convert(const Boxed_Value &t_derived)
virtual Boxed_Value convert(const Boxed_Value &t_derived) const
{
if (t_derived.get_type_info().bare_equal(user_type<Derived>()))
{
@@ -88,7 +91,7 @@ namespace chaiscript
if (t_derived.is_const())
{
boost::shared_ptr<const Base> data
= boost::dynamic_pointer_cast<const Base>(detail::Cast_Helper<boost::shared_ptr<const Derived> >::cast(t_derived));
= boost::dynamic_pointer_cast<const Base>(detail::Cast_Helper<boost::shared_ptr<const Derived> >::cast(t_derived, 0));
if (!data)
{
throw std::bad_cast();
@@ -97,7 +100,7 @@ namespace chaiscript
return Boxed_Value(data);
} else {
boost::shared_ptr<Base> data
= boost::dynamic_pointer_cast<Base>(detail::Cast_Helper<boost::shared_ptr<Derived> >::cast(t_derived));
= boost::dynamic_pointer_cast<Base>(detail::Cast_Helper<boost::shared_ptr<Derived> >::cast(t_derived, 0));
if (!data)
{
@@ -110,11 +113,11 @@ namespace chaiscript
// Pull the reference out of the contained boxed value, which we know is the type we want
if (t_derived.is_const())
{
const Derived &d = detail::Cast_Helper<const Derived &>::cast(t_derived);
const Derived &d = detail::Cast_Helper<const Derived &>::cast(t_derived, 0);
const Base &data = dynamic_cast<const Base &>(d);
return Boxed_Value(boost::cref(data));
} else {
Derived &d = detail::Cast_Helper<Derived &>::cast(t_derived);
Derived &d = detail::Cast_Helper<Derived &>::cast(t_derived, 0);
Base &data = dynamic_cast<Base &>(d);
return Boxed_Value(boost::ref(data));
}
@@ -124,101 +127,98 @@ namespace chaiscript
}
}
};
class Dynamic_Conversions
{
public:
static inline Dynamic_Conversions &get()
{
static Dynamic_Conversions obj;
return obj;
}
template<typename Base, typename Derived>
static boost::shared_ptr<Dynamic_Conversion> create()
{
boost::shared_ptr<Dynamic_Conversion> conversion(new Dynamic_Conversion_Impl<Base, Derived>());
/// \todo this is a hack and a kludge. The idea is to make sure that
/// the conversion is registered both in the module's notion of the static conversion object
/// and in the global notion of the static conversion object
/// someday this will almost certainly have to change. Maybe it is time for ChaiScript
/// to become a library?
Dynamic_Conversions::get().add_conversion(conversion);
return conversion;
}
template<typename InItr>
void cleanup(InItr begin, const InItr &end)
{
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
while (begin != end)
{
if (begin->unique())
{
m_conversions.erase(begin->get());
}
++begin;
}
}
void add_conversion(const boost::shared_ptr<Dynamic_Conversion> &conversion)
{
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
m_conversions.insert(conversion.get());
}
bool has_conversion(const Type_Info &base, const Type_Info &derived) const
{
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
return find(base, derived) != m_conversions.end();
}
Dynamic_Conversion *get_conversion(const Type_Info &base, const Type_Info &derived) const
{
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
std::set<Dynamic_Conversion *>::const_iterator itr =
find(base, derived);
if (itr != m_conversions.end())
{
return *itr;
} else {
throw std::out_of_range("No such conversion exists from " + derived.bare_name() + " to " + base.bare_name());
}
}
private:
Dynamic_Conversions() {}
std::set<Dynamic_Conversion *>::const_iterator find(
const Type_Info &base, const Type_Info &derived) const
{
for (std::set<Dynamic_Conversion *>::const_iterator itr = m_conversions.begin();
itr != m_conversions.end();
++itr)
{
if ((*itr)->base().bare_equal(base) && (*itr)->derived().bare_equal(derived))
{
return itr;
}
}
return m_conversions.end();
}
mutable chaiscript::detail::threading::shared_mutex m_mutex;
std::set<Dynamic_Conversion *> m_conversions;
};
}
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>
bool dynamic_cast_converts() const
{
return dynamic_cast_converts(user_type<Base>(), user_type<Derived>());
}
bool dynamic_cast_converts(const Type_Info &base, const Type_Info &derived) const
{
return has_conversion(base, derived);
}
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");
}
}
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();
}
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<boost::shared_ptr<detail::Dynamic_Conversion> >::const_iterator itr =
find(base, derived);
if (itr != m_conversions.end())
{
return *itr;
} else {
throw std::out_of_range("No such conversion exists from " + derived.bare_name() + " to " + base.bare_name());
}
}
private:
std::set<boost::shared_ptr<detail::Dynamic_Conversion> >::const_iterator find(
const Type_Info &base, const Type_Info &derived) const
{
for (std::set<boost::shared_ptr<detail::Dynamic_Conversion> >::const_iterator itr = m_conversions.begin();
itr != m_conversions.end();
++itr)
{
if ((*itr)->base().bare_equal(base) && (*itr)->derived().bare_equal(derived))
{
return itr;
}
}
return m_conversions.end();
}
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;
}
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
@@ -245,42 +245,17 @@ namespace chaiscript
/// \todo Move share static type registration code into a mechanism that allows it to be properly
/// shared by all modules
template<typename Base, typename Derived>
Dynamic_Cast_Conversion base_class()
{
//Can only be used with related polymorphic types
//may be expanded some day to support conversions other than child -> parent
BOOST_STATIC_ASSERT((boost::is_base_of<Base,Derived>::value));
BOOST_STATIC_ASSERT(boost::is_polymorphic<Base>::value);
BOOST_STATIC_ASSERT(boost::is_polymorphic<Derived>::value);
return detail::Dynamic_Conversions::create<Base, Derived>();
}
namespace detail
{
template<typename Base, typename Derived>
bool dynamic_cast_converts()
{
return dynamic_cast_converts(user_type<Base>(), user_type<Derived>());
}
static bool dynamic_cast_converts(const Type_Info &base, const Type_Info &derived)
Dynamic_Cast_Conversion base_class()
{
return detail::Dynamic_Conversions::get().has_conversion(base, derived);
//Can only be used with related polymorphic types
//may be expanded some day to support conversions other than child -> parent
BOOST_STATIC_ASSERT((boost::is_base_of<Base,Derived>::value));
BOOST_STATIC_ASSERT(boost::is_polymorphic<Base>::value);
BOOST_STATIC_ASSERT(boost::is_polymorphic<Derived>::value);
return boost::shared_ptr<detail::Dynamic_Conversion>(new detail::Dynamic_Conversion_Impl<Base, Derived>());
}
template<typename Base>
Boxed_Value boxed_dynamic_cast(const Boxed_Value &derived)
{
try {
return detail::Dynamic_Conversions::get().get_conversion(user_type<Base>(), derived.get_type_info())->convert(derived);
} catch (const std::out_of_range &) {
throw exception::bad_boxed_dynamic_cast(derived.get_type_info(), typeid(Base), "No known conversion");
} catch (const std::bad_cast &) {
throw exception::bad_boxed_dynamic_cast(derived.get_type_info(), typeid(Base), "Unable to perform dynamic_cast operation");
}
}
}
}

View File

@@ -1,7 +1,7 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2011, Jonathan Turner (jonathan@emptycrate.com)
// and Jason Turner (jason@emptycrate.com)
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_DYNAMIC_OBJECT_HPP_
@@ -44,20 +44,6 @@ namespace chaiscript
namespace detail
{
struct Dynamic_Object_Attribute
{
static Boxed_Value func(const std::string &t_type_name, const std::string &t_attr_name,
Dynamic_Object &t_do)
{
if (t_do.get_type_name() != t_type_name)
{
throw exception::bad_boxed_cast("Dynamic object type mismatch");
}
return t_do.get_attr(t_attr_name);
}
};
/**
* A Proxy_Function implementation designed for calling a function
* that is automatically guarded based on the first param based on the
@@ -71,11 +57,11 @@ namespace chaiscript
const Proxy_Function &t_func,
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(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)");
}
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)");
}
virtual ~Dynamic_Object_Function() {}
@@ -90,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;
}
@@ -120,19 +106,19 @@ 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:
@@ -153,13 +139,13 @@ namespace chaiscript
}
static bool dynamic_object_typename_match(const Boxed_Value &bv, const std::string &name,
const boost::optional<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;
@@ -176,11 +162,11 @@ namespace chaiscript
}
static bool dynamic_object_typename_match(const std::vector<Boxed_Value> &bvs, const std::string &name,
const boost::optional<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;
}
@@ -206,11 +192,11 @@ namespace chaiscript
const std::string &t_type_name,
const Proxy_Function &t_func)
: Proxy_Function_Base(build_type_list(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)");
}
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)");
}
static std::vector<Type_Info> build_type_list(const std::vector<Type_Info> &tl)
{
@@ -238,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);
}
@@ -260,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-2011, 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_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 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);
}
};
}

View File

@@ -1,7 +1,7 @@
// 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_
@@ -32,10 +32,10 @@ namespace chaiscript
*/
template<typename FunctionType>
boost::function<FunctionType>
functor(const std::vector<Const_Proxy_Function> &funcs)
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);
}
/**
@@ -53,11 +53,11 @@ namespace chaiscript
*/
template<typename FunctionType>
boost::function<FunctionType>
functor(Const_Proxy_Function func)
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);
}
/**
@@ -66,9 +66,9 @@ namespace chaiscript
*/
template<typename FunctionType>
boost::function<FunctionType>
functor(const Boxed_Value &bv)
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);
}
}
@@ -81,13 +81,13 @@ namespace chaiscript
{
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 boost::function<Signature> &>::cast(ob);
return Cast_Helper_Inner<const boost::function<Signature> &>::cast(ob, t_conversions);
}
}
};
@@ -100,13 +100,13 @@ namespace chaiscript
{
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<boost::function<Signature> >::cast(ob);
return Cast_Helper_Inner<boost::function<Signature> >::cast(ob, t_conversions);
}
}
};
@@ -119,13 +119,13 @@ namespace chaiscript
{
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 boost::function<Signature> >::cast(ob);
return Cast_Helper_Inner<const boost::function<Signature> >::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-2011, 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 <boost/preprocessor.hpp>
@@ -36,9 +36,9 @@ namespace chaiscript
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));
}
};
@@ -49,9 +49,9 @@ namespace chaiscript
struct Function_Caller_Ret<void>
{
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);
}
};
}
@@ -76,14 +76,14 @@ namespace chaiscript
* used internally for unwrapping a function call's types
*/
template<typename Ret BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param) >
Ret function_caller(const std::vector<Const_Proxy_Function> &funcs
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, ~)
BOOST_PP_REPEAT(n, addparam, ~);
return Function_Caller_Ret<Ret>::call(funcs, params);
return Function_Caller_Ret<Ret>::call(funcs, params, t_conversions);
}
/**
@@ -91,7 +91,8 @@ namespace chaiscript
*/
template<typename Ret BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param) >
boost::function<Ret (BOOST_PP_ENUM_PARAMS(n, Param)) >
build_function_caller_helper(Ret (BOOST_PP_ENUM_PARAMS(n, Param)), const std::vector<Const_Proxy_Function> &funcs)
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)
{
@@ -107,13 +108,15 @@ namespace chaiscript
// we cannot make any other guesses or assumptions really, so continuing
}
return boost::bind(&function_caller<Ret BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, Param)>, funcs
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-2011, 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_HANDLE_RETURN_HPP_
@@ -34,6 +34,15 @@ namespace chaiscript
}
};
template<typename Ret>
struct Handle_Return<Ret *>
{
static Boxed_Value handle(Ret *p)
{
return Boxed_Value(p);
}
};
template<typename Ret>
struct Handle_Return<boost::shared_ptr<Ret> &>
{

View File

@@ -1,7 +1,7 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2011, Jonathan Turner (jonathan@emptycrate.com)
// and Jason Turner (jason@emptycrate.com)
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_OPERATORS_HPP_

View File

@@ -1,7 +1,7 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2011, Jonathan Turner (jonathan@emptycrate.com)
// and Jason Turner (jason@emptycrate.com)
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#include <boost/preprocessor.hpp>

View File

@@ -1,7 +1,7 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2011, Jonathan Turner (jonathan@emptycrate.com)
// and Jason Turner (jason@emptycrate.com)
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
@@ -25,7 +25,6 @@ namespace chaiscript
typedef boost::shared_ptr<struct AST_Node> AST_NodePtr;
namespace dispatch
{
/**
@@ -71,10 +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);
bv.add_dependencies(params.begin(), params.end());
Boxed_Value bv = do_call(params, t_conversions);
return bv;
}
@@ -85,7 +83,12 @@ namespace chaiscript
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;
bool has_arithmetic_param() const
{
return m_has_arithmetic_param;
}
virtual std::vector<boost::shared_ptr<const Proxy_Function_Base> > get_contained_functions() const
{
@@ -95,7 +98,7 @@ namespace chaiscript
//! 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();
@@ -107,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;
@@ -119,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<boost::shared_ptr<const Proxy_Function_Base> >())
|| t_conversions.dynamic_cast_converts(ti, bv.get_type_info())
)
)
)
@@ -152,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())
{
@@ -172,6 +190,8 @@ namespace chaiscript
}
std::vector<Type_Info> m_types;
bool m_has_arithmetic_param;
};
}
@@ -219,13 +239,18 @@ namespace chaiscript
virtual bool operator==(const Proxy_Function_Base &rhs) const
{
return this == &rhs;
const Dynamic_Proxy_Function *prhs = dynamic_cast<const Dynamic_Proxy_Function *>(&rhs);
return this == &rhs
|| (prhs
&& this->m_arity == prhs->m_arity
&& !this->m_guard && !prhs->m_guard);
}
virtual bool call_match(const std::vector<Boxed_Value> &vals) const
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() {}
@@ -252,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 {
@@ -270,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 &) {
@@ -331,7 +356,7 @@ namespace chaiscript
Bound_Function(const Const_Proxy_Function &t_f,
const std::vector<Boxed_Value> &t_args)
: Proxy_Function_Base(build_param_type_info(t_f, t_args)),
m_f(t_f), m_args(t_args), m_arity(t_f->get_arity()<0?-1:static_cast<int>(get_param_types().size())-1)
m_f(t_f), m_args(t_args), m_arity(t_f->get_arity()<0?-1:static_cast<int>(get_param_types().size())-1)
{
assert(m_f->get_arity() < 0 || m_f->get_arity() == static_cast<int>(m_args.size()));
}
@@ -343,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
@@ -427,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:
@@ -450,8 +470,8 @@ namespace chaiscript
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)
{
}
{
}
virtual ~Proxy_Function_Impl() {}
@@ -468,14 +488,14 @@ 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 (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
@@ -489,9 +509,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 detail::Do_Call<typename boost::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:
@@ -509,8 +529,8 @@ namespace chaiscript
Attribute_Access(T Class::* t_attr)
: Proxy_Function_Base(param_types()),
m_attr(t_attr)
{
}
{
}
virtual ~Attribute_Access() {}
@@ -531,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)
{
@@ -547,17 +567,17 @@ 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);
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);
Class *o = boxed_cast<Class *>(bv, &t_conversions);
return detail::Handle_Return<typename boost::add_reference<T>::type>::handle(o->*m_attr);
}
} else {
@@ -587,22 +607,109 @@ namespace chaiscript
class dispatch_error : public std::runtime_error
{
public:
dispatch_error() throw()
: std::runtime_error("No matching function to dispatch to")
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)
{
}
dispatch_error(bool is_const) throw()
: std::runtime_error(std::string("No matching function to dispatch to") + (is_const?", parameter is const":""))
{
}
virtual ~dispatch_error() 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
@@ -610,15 +717,16 @@ namespace chaiscript
* function is found or throw dispatch_error if no matching function is found
*/
template<typename InItr>
Boxed_Value dispatch(InItr begin, InItr end,
const std::vector<Boxed_Value> &plist)
Boxed_Value dispatch(InItr begin, const InItr &end,
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
@@ -631,7 +739,7 @@ namespace chaiscript
++begin;
}
throw exception::dispatch_error(plist.empty()?false:plist[0].is_const());
return detail::dispatch_with_conversions(orig, end, plist, t_conversions);
}
/**
@@ -641,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,14 +1,14 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2011, Jonathan Turner (jonathan@emptycrate.com)
// and Jason Turner (jason@emptycrate.com)
// Copyright 2009-2012, Jonathan Turner (jonathan@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])
#define trycast(z,n,text) chaiscript::boxed_cast<Param ## n>(params[n]);
#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_
@@ -21,7 +21,6 @@
#include <string>
#include <boost/function.hpp>
#include <boost/bind.hpp>
#include <boost/lexical_cast.hpp>
#include <stdexcept>
#include <vector>
@@ -87,9 +86,23 @@ namespace chaiscript
* if any unboxing fails the execution of the function fails and
* the bad_boxed_cast is passed up to the caller.
*/
#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 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() != n)
{
@@ -99,16 +112,37 @@ namespace chaiscript
}
}
#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
*/
template<typename Ret BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param)>
#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, ))
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;
@@ -116,11 +150,20 @@ namespace chaiscript
return true;
}
#ifdef BOOST_MSVC
#pragma warning(pop)
#endif
}
}
}
#undef n
#undef gettypeinfo
#undef casthelper
#undef trycast
#endif
@@ -137,9 +180,9 @@ namespace chaiscript
struct Do_Call
{
template<typename Fun>
static Boxed_Value go(const boost::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));
}
};
@@ -147,9 +190,9 @@ namespace chaiscript
struct Do_Call<void>
{
template<typename Fun>
static Boxed_Value go(const boost::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-2011, 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_REGISTER_FUNCTION_HPP_

View File

@@ -1,7 +1,7 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2011, Jonathan Turner (jonathan@emptycrate.com)
// and Jason Turner (jason@emptycrate.com)
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_TYPE_INFO_HPP_
@@ -39,39 +39,40 @@ namespace chaiscript
public:
Type_Info(bool t_is_const, bool t_is_reference, bool t_is_pointer, bool t_is_void,
bool t_is_arithmetic, const std::type_info *t_ti, const std::type_info *t_bareti)
: m_is_const(t_is_const), m_is_reference(t_is_reference), m_is_pointer(t_is_pointer),
: m_type_info(t_ti), m_bare_type_info(t_bareti),
m_is_const(t_is_const), m_is_reference(t_is_reference), m_is_pointer(t_is_pointer),
m_is_void(t_is_void), m_is_arithmetic(t_is_arithmetic),
m_type_info(t_ti), m_bare_type_info(t_bareti),
m_is_undef(false)
{
}
Type_Info()
: m_is_const(false), m_is_reference(false), m_is_pointer(false),
m_is_void(false), m_is_arithmetic(false), m_type_info(0), m_bare_type_info(0),
: m_type_info(0), m_bare_type_info(0),
m_is_const(false), m_is_reference(false), m_is_pointer(false),
m_is_void(false), m_is_arithmetic(false),
m_is_undef(true)
{
}
Type_Info(const Type_Info &ti)
: m_is_const(ti.m_is_const), m_is_reference(ti.m_is_reference),
: m_type_info(ti.m_type_info),
m_bare_type_info(ti.m_bare_type_info),
m_is_const(ti.m_is_const), m_is_reference(ti.m_is_reference),
m_is_pointer(ti.m_is_pointer),
m_is_void(ti.m_is_void), m_is_arithmetic(ti.m_is_arithmetic),
m_type_info(ti.m_type_info),
m_bare_type_info(ti.m_bare_type_info),
m_is_undef(ti.m_is_undef)
{
}
Type_Info &operator=(const Type_Info &ti)
{
m_type_info = ti.m_type_info;
m_bare_type_info = ti.m_bare_type_info;
m_is_const = ti.m_is_const;
m_is_reference = ti.m_is_reference;
m_is_pointer = ti.m_is_pointer;
m_is_void = ti.m_is_void;
m_is_arithmetic = ti.m_is_arithmetic;
m_type_info = ti.m_type_info;
m_bare_type_info = ti.m_bare_type_info;
m_is_undef = ti.m_is_undef;
return *this;
}
@@ -98,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; }
@@ -126,13 +133,13 @@ namespace chaiscript
}
private:
const std::type_info *m_type_info;
const std::type_info *m_bare_type_info;
bool m_is_const;
bool m_is_reference;
bool m_is_pointer;
bool m_is_void;
bool m_is_arithmetic;
const std::type_info *m_type_info;
const std::type_info *m_bare_type_info;
bool m_is_undef;
};

View File

@@ -1,7 +1,7 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2011, Jonathan Turner (jonathan@emptycrate.com)
// and Jason Turner (jason@emptycrate.com)
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_ALGEBRAIC_HPP_

View File

@@ -1,7 +1,7 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2011, Jonathan Turner (jonathan@emptycrate.com)
// and Jason Turner (jason@emptycrate.com)
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_COMMON_HPP_
@@ -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
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"};
"Logical_And", "Logical_Or", "Switch", "Case", "Default", "Ternary Condition", "Noop"};
return ast_node_types[ast_node_type];
}
@@ -61,35 +60,323 @@ namespace chaiscript
/// \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) throw() :
std::runtime_error("Error: \"" + t_why + "\" " +
(t_fname != "__EVAL__" ? ("in '" + t_fname + "' ") : "during evaluation ") +
+ "at (" + boost::lexical_cast<std::string>(t_where.line) + ", " +
boost::lexical_cast<std::string>(t_where.column) + ")"),
eval_error(const std::string &t_why, const File_Position &t_where, const std::string &t_fname,
const std::vector<Boxed_Value> &t_parameters, const std::vector<chaiscript::Const_Proxy_Function> &t_functions,
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 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) :
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) throw()
: std::runtime_error("Error: \"" + t_why + "\" "),
reason(t_why)
{}
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_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;
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 (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 += ", ";
}
} else {
paramstr += ", ";
}
}
ss << paramstr.substr(0, paramstr.size() - 2);
}
ss << ")";
return ss.str();
}
static std::string format_filename(const std::string &t_fname)
{
std::stringstream ss;
if (t_fname != "__EVAL__")
{
ss << "in '" << t_fname << "' ";
} else {
ss << "during evaluation ";
}
return ss.str();
}
static std::string format_location(const File_Position &t_where)
{
std::stringstream ss;
ss << "at (" << t_where.line << ", " << t_where.column << ")";
return ss.str();
}
static std::string format(const std::string &t_why, const File_Position &t_where, const std::string &t_fname,
const std::vector<Boxed_Value> &t_parameters, bool t_dot_notation, const chaiscript::detail::Dispatch_Engine &t_ss)
{
std::stringstream ss;
ss << format_why(t_why);
ss << " ";
ss << "With parameters: " << format_parameters(t_parameters, t_dot_notation, t_ss);
ss << " ";
ss << format_filename(t_fname);
ss << " ";
ss << format_location(t_where);
return ss.str();
}
static std::string format(const std::string &t_why,
const std::vector<Boxed_Value> &t_parameters,
bool t_dot_notation,
const chaiscript::detail::Dispatch_Engine &t_ss)
{
std::stringstream ss;
ss << format_why(t_why);
ss << " ";
ss << "With parameters: " << format_parameters(t_parameters, t_dot_notation, t_ss);
ss << " ";
return ss.str();
}
static std::string format(const std::string &t_why, const File_Position &t_where, const std::string &t_fname)
{
std::stringstream ss;
ss << format_why(t_why);
ss << " ";
ss << format_filename(t_fname);
ss << " ";
ss << format_location(t_where);
return ss.str();
}
};
/**
* Errors generated when loading a file
*/
/// Errors generated when loading a file
struct file_not_found_error : public std::runtime_error {
file_not_found_error(const std::string &t_filename) throw()
: std::runtime_error("File Not Found: " + t_filename)
@@ -111,9 +398,21 @@ namespace chaiscript
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;
@@ -175,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
{
@@ -213,6 +517,57 @@ namespace chaiscript
chaiscript::detail::Dispatch_Engine &m_de;
};
/// Creates a new functon call and pops it on destruction
struct Function_Push_Pop
{
Function_Push_Pop(chaiscript::detail::Dispatch_Engine &t_de)
: m_de(t_de)
{
m_de.new_function_call();
}
~Function_Push_Pop()
{
m_de.pop_function_call();
}
void save_params(const std::vector<Boxed_Value> &t_params)
{
m_de.save_function_params(t_params);
}
private:
// explicitly unimplemented copy and assignment
Function_Push_Pop(const Function_Push_Pop &);
Function_Push_Pop& operator=(const Function_Push_Pop &);
chaiscript::detail::Dispatch_Engine &m_de;
};
/// Creates a new scope then pops it on destruction
struct Stack_Push_Pop
{
Stack_Push_Pop(chaiscript::detail::Dispatch_Engine &t_de)
: m_de(t_de)
{
m_de.new_stack();
}
~Stack_Push_Pop()
{
m_de.pop_stack();
}
private:
// explicitly unimplemented copy and assignment
Stack_Push_Pop(const Stack_Push_Pop &);
Stack_Push_Pop& operator=(const Stack_Push_Pop &);
chaiscript::detail::Dispatch_Engine &m_de;
};
}
}
}

View File

@@ -1,7 +1,7 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2011, Jonathan Turner (jonathan@emptycrate.com)
// and Jason Turner (jason@emptycrate.com)
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_ENGINE_HPP_
@@ -10,7 +10,7 @@
#include <exception>
#include <fstream>
#include <chaiscript/language/chaiscript_common.hpp>
#include "chaiscript_common.hpp"
#ifdef _POSIX_VERSION
#include <dlfcn.h>
@@ -23,8 +23,8 @@
#endif
#include <chaiscript/language/chaiscript_prelude.hpp>
#include <chaiscript/language/chaiscript_parser.hpp>
#include "chaiscript_prelude.hpp"
#include "chaiscript_parser.hpp"
#include "../dispatchkit/exception_specification.hpp"
namespace chaiscript
@@ -76,7 +76,7 @@ namespace chaiscript
struct DLSym
{
DLSym(DLModule &t_mod, const std::string &t_symbol)
: m_symbol(reinterpret_cast<T>(dlsym(t_mod.m_data, t_symbol.c_str())))
: m_symbol(cast_symbol(dlsym(t_mod.m_data, t_symbol.c_str())))
{
if (!m_symbol)
{
@@ -84,6 +84,19 @@ namespace chaiscript
}
}
static T cast_symbol(void *p)
{
union cast_union
{
T func_ptr;
void *in_ptr;
};
cast_union c;
c.in_ptr = p;
return c.func_ptr;
}
T m_symbol;
};
@@ -238,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 {
@@ -261,57 +273,36 @@ namespace chaiscript
const Boxed_Value internal_eval_ast(const AST_NodePtr &t_ast)
{
return t_ast->eval(m_engine);
}
/**
* Evaluates the given string, used during eval() inside of a script
*/
const Boxed_Value internal_eval(const std::string &t_e) {
return do_eval(t_e, "__EVAL__", true);
}
void use(const std::string &t_filename)
{
for (size_t i = 0; i < m_usepaths.size(); ++i)
{
try {
const std::string appendedpath = m_usepaths[i] + t_filename;
chaiscript::detail::threading::lock_guard<chaiscript::detail::threading::recursive_mutex> l(m_use_mutex);
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l2(m_mutex);
if (m_used_files.count(appendedpath) == 0)
{
m_used_files.insert(appendedpath);
l2.unlock();
eval_file(appendedpath);
}
} catch (const exception::file_not_found_error &) {
if (i == m_usepaths.size() - 1)
{
throw exception::file_not_found_error(t_filename);
}
// failed to load, try the next path
}
try {
return t_ast->eval(m_engine);
} catch (const exception::eval_error &t_ee) {
throw Boxed_Value(t_ee);
}
}
/**
* Returns the current evaluation m_engine
*/
/// 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);
} catch (const exception::eval_error &t_ee) {
throw Boxed_Value(t_ee);
}
}
/// 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.
*/
/// 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");
@@ -336,6 +327,15 @@ namespace chaiscript
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(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");
@@ -358,9 +358,8 @@ 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 );
@@ -404,6 +403,41 @@ namespace chaiscript
build_eval_system();
}
/// \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.
///
/// \param[in] t_filename Filename to load and evaluate
void use(const std::string &t_filename)
{
for (size_t i = 0; i < m_usepaths.size(); ++i)
{
try {
const std::string appendedpath = m_usepaths[i] + t_filename;
chaiscript::detail::threading::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)
{
l2.unlock();
eval_file(appendedpath);
l2.lock();
m_used_files.insert(appendedpath);
}
return; // return, we loaded it, or it was already loaded
} catch (const exception::file_not_found_error &) {
if (i == m_usepaths.size() - 1)
{
throw exception::file_not_found_error(t_filename);
}
// failed to load, try the next path
}
}
}
/// \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
@@ -415,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
@@ -425,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:
///
@@ -447,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:
@@ -466,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
@@ -610,7 +679,7 @@ namespace chaiscript
return do_eval(t_script);
} catch (Boxed_Value &bv) {
if (t_handler) {
t_handler->handle(bv);
t_handler->handle(bv, m_engine);
}
throw bv;
}
@@ -621,6 +690,8 @@ 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
///
@@ -628,33 +699,43 @@ namespace chaiscript
/// \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;
}
}
/// \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 exception::eval_error In the case that evaluation fails.
Boxed_Value eval(const std::string &t_input, const Exception_Handler &t_handler = Exception_Handler())
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;
}
@@ -670,7 +751,7 @@ namespace chaiscript
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;
}
@@ -687,10 +768,10 @@ namespace chaiscript
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;
}

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-2011, 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_PARSER_HPP_
@@ -33,6 +33,8 @@ namespace chaiscript
, bin_alphabet
, id_alphabet
, white_alphabet
, int_suffix_alphabet
, float_suffix_alphabet
, max_alphabet
, lengthof_alphabet = 256
};
@@ -66,6 +68,11 @@ namespace chaiscript
void setup_operators()
{
m_operators.push_back(AST_Node_Type::Ternary_Cond);
std::vector<std::string> ternary_cond;
ternary_cond.push_back("?");
m_operator_matches.push_back(ternary_cond);
m_operators.push_back(AST_Node_Type::Logical_Or);
std::vector<std::string> logical_or;
logical_or.push_back("||");
@@ -131,6 +138,7 @@ namespace chaiscript
m_alphabet[a][c]=false;
}
}
m_alphabet[detail::symbol_alphabet][static_cast<int>('?')]=true;
m_alphabet[detail::symbol_alphabet][static_cast<int>('+')]=true;
m_alphabet[detail::symbol_alphabet][static_cast<int>('-')]=true;
m_alphabet[detail::symbol_alphabet][static_cast<int>('*')]=true;
@@ -169,6 +177,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;
}
/**
@@ -322,7 +341,6 @@ namespace chaiscript
*/
bool Float_() {
bool retval = false;
std::string::const_iterator start = m_input_pos;
if (has_more_input() && char_in_alphabet(*m_input_pos,detail::float_alphabet) ) {
while (has_more_input() && char_in_alphabet(*m_input_pos,detail::int_alphabet) ) {
@@ -338,6 +356,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;
@@ -366,6 +390,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;
@@ -381,6 +410,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
*/
@@ -414,6 +451,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
*/
@@ -430,19 +634,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))) {
@@ -453,32 +652,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;
@@ -548,13 +751,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;
}
@@ -587,7 +790,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;
}
@@ -662,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);
}
@@ -688,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);
@@ -756,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;
@@ -854,7 +1057,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;
}
@@ -893,7 +1096,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;
}
@@ -945,7 +1148,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;
@@ -993,7 +1196,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);
}
@@ -1033,7 +1236,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;
}
@@ -1303,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;
@@ -1371,18 +1574,40 @@ 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 (Char(';') && Operator() && Char(';') && Equation()) {
return true;
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);
}
}
else {
throw exception::eval_error("Incomplete conditions in 'for' loop", File_Position(m_line, m_col), *m_filename);
if (!Equation())
{
AST_NodePtr t(new eval::Noop_AST_Node());
m_match_stack.push_back(t);
}
return true;
}
/**
@@ -1416,6 +1641,90 @@ namespace chaiscript
return retval;
}
/**
* Reads a case block from input
*/
bool Case() {
bool retval = false;
size_t prev_stack_top = m_match_stack.size();
if (Keyword("case")) {
retval = true;
if (!Char('(')) {
throw exception::eval_error("Incomplete 'case' expression", File_Position(m_line, m_col), *m_filename);
}
if (!(Operator() && Char(')'))) {
throw exception::eval_error("Incomplete 'case' expression", File_Position(m_line, m_col), *m_filename);
}
while (Eol()) {}
if (!Block()) {
throw exception::eval_error("Incomplete 'case' block", File_Position(m_line, m_col), *m_filename);
}
build_match(AST_NodePtr(new eval::Case_AST_Node()), prev_stack_top);
}
else if (Keyword("default")) {
while (Eol()) {}
if (!Block()) {
throw exception::eval_error("Incomplete 'default' block", File_Position(m_line, m_col), *m_filename);
}
build_match(AST_NodePtr(new eval::Default_AST_Node()), prev_stack_top);
}
return retval;
}
/**
* Reads a switch statement from input
*/
bool Switch() {
size_t prev_stack_top = m_match_stack.size();
if (Keyword("switch")) {
if (!Char('(')) {
throw exception::eval_error("Incomplete 'switch' expression", File_Position(m_line, m_col), *m_filename);
}
if (!(Operator() && Char(')'))) {
throw exception::eval_error("Incomplete 'switch' expression", File_Position(m_line, m_col), *m_filename);
}
while (Eol()) {}
if (Char('{')) {
while (Eol()) {}
while (Case()) {
while (Eol()) { } // eat
}
while (Eol()) { } // eat
if (!Char('}')) {
throw exception::eval_error("Incomplete block", File_Position(m_line, m_col), *m_filename);
}
}
else {
throw exception::eval_error("Incomplete block", File_Position(m_line, m_col), *m_filename);
}
build_match(AST_NodePtr(new eval::Switch_AST_Node()), prev_stack_top);
return true;
} else {
return false;
}
}
/**
* Reads a curly-brace C-style block from input
*/
@@ -1473,12 +1782,28 @@ 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
*/
bool Dot_Fun_Array() {
bool retval = false;
std::string::const_iterator prev_pos = m_input_pos;
size_t prev_stack_top = m_match_stack.size();
if (Lambda() || Num(true) || Quoted_String(true) || Single_Quoted_String(true) ||
@@ -1584,7 +1909,7 @@ namespace chaiscript
throw exception::eval_error("Incomplete expression", File_Position(m_line, m_col), *m_filename);
}
if (!Char(')')) {
throw exception::eval_error("Missing closing parenthesis", File_Position(m_line, m_col), *m_filename);
throw exception::eval_error("Missing closing parenthesis ')'", File_Position(m_line, m_col), *m_filename);
}
}
return retval;
@@ -1602,7 +1927,7 @@ namespace chaiscript
retval = true;
Container_Arg_List();
if (!Char(']')) {
throw exception::eval_error("Missing closing square bracket", 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) {
@@ -1720,6 +2045,7 @@ namespace chaiscript
retval = true;
if (Operator_Helper(t_precedence)) {
do {
while (Eol()) {}
if (!Operator(t_precedence+1)) {
throw exception::eval_error("Incomplete "
+ std::string(ast_node_type_to_string(m_operators[t_precedence])) + " expression",
@@ -1730,6 +2056,23 @@ namespace chaiscript
case(AST_Node_Type::Comparison) :
build_match(AST_NodePtr(new eval::Comparison_AST_Node()), prev_stack_top);
break;
case(AST_Node_Type::Ternary_Cond) :
m_match_stack.erase(m_match_stack.begin() + m_match_stack.size() - 2,
m_match_stack.begin() + m_match_stack.size() - 1);
if (Symbol(":")) {
if (!Operator(t_precedence+1)) {
throw exception::eval_error("Incomplete "
+ std::string(ast_node_type_to_string(m_operators[t_precedence])) + " expression",
File_Position(m_line, m_col), *m_filename);
}
build_match(AST_NodePtr(new eval::Ternary_Cond_AST_Node()), prev_stack_top);
}
else {
throw exception::eval_error("Incomplete "
+ std::string(ast_node_type_to_string(m_operators[t_precedence])) + " expression",
File_Position(m_line, m_col), *m_filename);
}
break;
case(AST_Node_Type::Addition) :
oper = m_match_stack.at(m_match_stack.size()-2);
m_match_stack.erase(m_match_stack.begin() + m_match_stack.size() - 2,
@@ -1887,7 +2230,6 @@ namespace chaiscript
bool saw_eol = true;
while (has_more) {
has_more = false;
int prev_line = m_line;
int prev_col = m_col;
if (Def()) {
@@ -1930,6 +2272,14 @@ namespace chaiscript
retval = true;
saw_eol = true;
}
else if (Switch()) {
if (!saw_eol) {
throw exception::eval_error("Two function definitions missing line separator", File_Position(prev_line, prev_col), *m_filename);
}
has_more = true;
retval = true;
saw_eol = true;
}
else if (Return()) {
if (!saw_eol) {
throw exception::eval_error("Two expressions missing line separator", File_Position(prev_line, prev_col), *m_filename);
@@ -1946,6 +2296,14 @@ namespace chaiscript
retval = true;
saw_eol = false;
}
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 = false;
}
else if (Equation()) {
if (!saw_eol) {
throw exception::eval_error("Two expressions missing line separator", File_Position(prev_line, prev_col), *m_filename);

View File

@@ -1,7 +1,7 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2011, Jonathan Turner (jonathan@emptycrate.com)
// and Jason Turner (jason@emptycrate.com)
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_PRELUDE_HPP_

View File

@@ -1,7 +1,7 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2011, Jonathan Turner (jonathan@emptycrate.com)
// and Jason Turner (jason@emptycrate.com)
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_UTILITY_UTILITY_HPP_
@@ -49,10 +49,20 @@
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.

View File

@@ -1,4 +1,7 @@
Copyright 2009-2011 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:

83
readme.md Normal file
View File

@@ -0,0 +1,83 @@
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-2011 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 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.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,5 +1,65 @@
Changes since 2.3.3
Current Version: 4.3.0
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.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
* 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
* Added support for returning pointers from functions (#13)
* Compile with -pedantic (#9)
* Fix issues with multiple ChaiScript object types having the same attribute name (#15)
* Prevent variable redeclaration in same scope (#22)
* mgee: Boxed_Number improvements (#27)
* Support switch statements (#34)
* Fix uint16 comparions (#26)
* Add ability to add const_var globals in Module objects (#14)
* Add support for ternary operators ?:
* Add headers to CMakeLists so they show up in IDEs
* Add ability to get vector of defined objects and vector of defined functions
* Fix memory leak in cyclical references
* Clean up static analysis issues discovered
* Fix vector construction to be consistent with map construction
* Increased unit tests to 161
* Performance enhancements
### Changes since 3.0.0
* Numeric operations performance increased approximately 10x
* Looping operations performance increased up to 2x
* Engine start up time decreased
* Several parsing bugs related to index operators fixed
* Added full support for all C algebraic types: double, long double, float, int, long, char,
uint8_t, uint16_t, uint32_t, uint64_t, int8_t, int16_t, int32_t, int64_t
* Enhanced support for capturing of exceptions thrown from ChaiScript in C++
### Changes since 2.3.3
* Code simplifications
* Fully integrate documentation with source code in doxygen style comments
* Unit tests increased from 114 to 137

View File

@@ -9,7 +9,18 @@
#include <chaiscript/chaiscript.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)
@@ -43,9 +54,9 @@ struct System
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;
}
@@ -141,7 +152,9 @@ int main(int /*argc*/, char * /*argv*/[]) {
//Creating a functor on the stack and using it immediatly
int x = chai.eval<boost::function<int (int, int)> >("fun (x, y) { return x + y; }")(5, 6);
log("Functor test output", boost::lexical_cast<std::string>(x));
std::stringstream ss;
ss << x;
log("Functor test output", ss.str());
chai.add(var(boost::shared_ptr<int>()), "nullvar");
chai("print(\"This should be true.\"); print(nullvar.is_var_null())");
@@ -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(boost::function<Boxed_Value (dispatch::Dynamic_Object &)>(boost::bind(&dispatch::detail::Dynamic_Object_Attribute::func, "TestType", "attr", _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

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

View File

@@ -1,7 +1,7 @@
// 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>
@@ -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;
@@ -80,7 +160,18 @@ std::string get_next_command() {
char *input_raw = readline("eval> ");
if ( input_raw ) {
add_history(input_raw);
retval = boost::trim_copy_if(std::string(input_raw),boost::is_any_of(" \t"));
std::string val(input_raw);
size_t pos = val.find_first_not_of("\t \n");
if (pos != std::string::npos)
{
val.erase(0, pos);
}
pos = val.find_last_not_of("\t \n");
if (pos != std::string::npos)
{
val.erase(pos+1, std::string::npos);
}
retval = val;
::free(input_raw);
}
}
@@ -156,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)
{
@@ -215,21 +308,11 @@ int main(int argc, char *argv[])
case eInteractive : interactive(chai); break;
case eCommand : val = chai.eval(arg); break;
case eFile : val = chai.eval_file(arg); break;
default : std::cout << "Unrecognized execution mode" << std::endl; return EXIT_FAILURE;
}
}
catch (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,40 +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 <boost/thread.hpp>
void do_work(chaiscript::ChaiScript &c)
{
// c("use(\"work.chai\"); do_chai_work(num_iterations);");
std::string name = "MyVar" + boost::lexical_cast<std::string>(rand());
c.add(chaiscript::var(5), name);
c("use(\"work.chai\"); do_chai_work(10000);");
}
int main(int argc, char *argv[]) {
std::string input;
chaiscript::ChaiScript chai;
//chai.add_shared_object(chaiscript::Boxed_Value(10000), "num_iterations");
std::vector<boost::shared_ptr<boost::thread> > threads;
for (int i = 0; i < argc - 1; ++i)
{
threads.push_back(boost::shared_ptr<boost::thread>(new boost::thread(boost::bind(do_work, boost::ref(chai)))));
}
for (int i = 0; i < argc - 1; ++i)
{
threads[i]->join();
}
}

View File

@@ -1,3 +1,9 @@
// 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/utility/utility.hpp>
@@ -18,7 +24,12 @@ bool has_parse_tree(const chaiscript::Const_Proxy_Function &t_pf)
= boost::dynamic_pointer_cast<const chaiscript::dispatch::Dynamic_Proxy_Function>(t_pf);
if (pf)
{
return pf->get_parse_tree();
if (pf->get_parse_tree())
{
return true;
} else {
return false;
}
} else {
return false;
}
@@ -42,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());
@@ -49,12 +66,12 @@ CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_reflect
m->add(chaiscript::fun(&has_parse_tree), "has_parse_tree");
m->add(chaiscript::fun(&get_parse_tree), "get_parse_tree");
m->add(chaiscript::base_class<std::exception, chaiscript::exception::eval_error>());
chaiscript::bootstrap::standard_library::vector_type<std::vector<boost::shared_ptr<chaiscript::AST_Node> > >("AST_NodeVector", m);
CHAISCRIPT_CLASS( m,
CHAISCRIPT_CLASS_NO_CONSTRUCTOR( m,
chaiscript::exception::eval_error,
,
((reason))
((call_stack))
);
@@ -67,9 +84,8 @@ CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_reflect
((column))
);
CHAISCRIPT_CLASS( m,
CHAISCRIPT_CLASS_NO_CONSTRUCTOR( m,
chaiscript::AST_Node,
,
((text))
((identifier))
((filename))
@@ -91,6 +107,11 @@ CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_reflect
return m;
}
#ifdef __llvm__
#pragma clang diagnostic pop
#endif
#ifdef BOOST_MSVC
#pragma warning(pop)

View File

@@ -1,3 +1,8 @@
// 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 <list>
@@ -10,11 +15,19 @@
#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 BOOST_MSVC
#pragma warning(pop)

View File

@@ -5,18 +5,39 @@
class TestBaseType
{
public:
TestBaseType() {}
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; }
const TestBaseType &constMe() const { return *this; }
int val;
const int const_val;
private:
TestBaseType &operator=(const TestBaseType &);
};
enum TestEnum
{
TestValue1 = 1
};
int to_int(TestEnum t)
{
return t;
}
class TestDerivedType : public TestBaseType
{
public:
virtual ~TestDerivedType() {}
virtual int func() { return 1; }
private:
TestDerivedType &operator=(const TestDerivedType &);
};
std::string hello_world()
@@ -24,6 +45,11 @@ std::string hello_world()
return "Hello World";
}
int *get_new_int()
{
return new int(1);
}
// MSVC doesn't like that we are using C++ return types from our C declared module
// but this is the best way to do it for cross platform compatibility
#ifdef BOOST_MSVC
@@ -31,6 +57,10 @@ std::string hello_world()
#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()
{
@@ -44,6 +74,7 @@ CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_test_mo
m->add(chaiscript::constructor<TestBaseType ()>(), "TestBaseType");
// m->add(chaiscript::constructor<TestBaseType (int)>(), "TestBaseType");
m->add(chaiscript::constructor<TestBaseType (const TestBaseType &)>(), "TestBaseType");
m->add(chaiscript::constructor<TestBaseType (int *)>(), "TestBaseType");
m->add(chaiscript::constructor<TestDerivedType ()>(), "TestDerivedType");
m->add(chaiscript::constructor<TestDerivedType (const TestDerivedType &)>(), "TestDerivedType");
@@ -51,11 +82,27 @@ CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_test_mo
m->add(chaiscript::base_class<TestBaseType, TestDerivedType>());
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(&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 __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

@@ -0,0 +1,58 @@
// Tests to make sure that type conversions happen only when they should
#include <chaiscript/chaiscript.hpp>
void f1(int)
{
}
void f4(std::string)
{
}
void f2(int)
{
}
void f3(double)
{
}
int main()
{
chaiscript::ChaiScript chai;
chai.add(chaiscript::fun(&f1), "f1");
chai.add(chaiscript::fun(&f2), "f2");
chai.add(chaiscript::fun(&f3), "f2");
chai.add(chaiscript::fun(&f1), "f3");
chai.add(chaiscript::fun(&f4), "f3");
// no overloads
chai.eval("f1(0)");
chai.eval("f1(0l)");
chai.eval("f1(0ul)");
chai.eval("f1(0ll)");
chai.eval("f1(0ull)");
chai.eval("f1(0.0)");
chai.eval("f1(0.0f)");
chai.eval("f1(0.0l)");
// expected overloads
chai.eval("f2(1)");
chai.eval("f2(1.0)");
// 1 non-arithmetic overload
chai.eval("f2(1.0)");
// this is the one call we expect to fail
try {
chai.eval("f2(1.0l)");
} catch (const std::exception &) {
return EXIT_SUCCESS;
}
// if the last one did not throw, we failed
return EXIT_FAILURE;
}

View File

@@ -301,8 +301,8 @@ int main()
passed &= built_in_type_test<int>(5, true);
passed &= built_in_type_test<double>(1.1, true);
passed &= built_in_type_test<char>('a', true);
passed &= built_in_type_test<uint8_t>('a', true);
passed &= built_in_type_test<int64_t>('a', true);
passed &= built_in_type_test<boost::uint8_t>('a', true);
passed &= built_in_type_test<boost::int64_t>('a', true);
passed &= built_in_type_test<bool>(false, false);
passed &= built_in_type_test<std::string>("Hello World", false);

11
unittests/break_for.chai Normal file
View File

@@ -0,0 +1,11 @@
var j = 0;
for (var i = 0; i < 10; ++i) {
if (i == 5) {
break
}
j = i
}
assert_equal(4, j);

View File

@@ -0,0 +1,20 @@
#include <chaiscript/chaiscript.hpp>
extern "C"
{
int dosomething(int i)
{
return i % 2;
}
}
int main()
{
chaiscript::ChaiScript chai;
chai.add(chaiscript::fun(&dosomething), "dosomething");
return chai.eval<int>("dosomething(101)") == 101 % 2?EXIT_SUCCESS:EXIT_FAILURE;
}

View File

@@ -0,0 +1,16 @@
var j = 0;
var k = 0;
for (var i = 0; i < 10; ++i)
{
j = i
if (i > 5)
{
continue
}
k = i
}
assert_equal(5, k);
assert_equal(9, j);

View File

@@ -0,0 +1,14 @@
var i = 0
var j = 0
while (i < 10) {
if (++i > 5)
{
continue
}
j = i;
}
assert_equal(10, i);
assert_equal(5, j);

View File

@@ -9,7 +9,7 @@ int test_generic()
try {
chai.eval("throw(runtime_error(\"error\"));");
} catch (const chaiscript::Boxed_Value &bv) {
const std::exception &e = chaiscript::boxed_cast<const std::exception &>(bv);
const std::exception &e = chai.boxed_cast<const std::exception &>(bv);
if (e.what() == std::string("error"))
{
return EXIT_SUCCESS;
@@ -60,7 +60,7 @@ int test_5()
try {
chai.eval("throw(runtime_error(\"error\"))", chaiscript::exception_specification<int, double, float, const std::string &, const std::exception &>());
} catch (const double e) {
} catch (const double) {
std::cout << "test_5 failed with double" << std::endl;
return EXIT_FAILURE;
} catch (int) {
@@ -72,7 +72,7 @@ int test_5()
} catch (const std::string &) {
std::cout << "test_5 failed with string" << std::endl;
return EXIT_FAILURE;
} catch (const std::exception &e) {
} catch (const std::exception &) {
return EXIT_SUCCESS;
}
@@ -95,10 +95,10 @@ int test_unhandled()
} catch (float) {
std::cout << "test_unhandled failed with float" << std::endl;
return EXIT_FAILURE;
} catch (const std::exception &e) {
} catch (const std::exception &) {
std::cout << "test_unhandled failed with std::exception" << std::endl;
return EXIT_FAILURE;
} catch (const chaiscript::Boxed_Value &bv) {
} catch (const chaiscript::Boxed_Value &) {
return EXIT_SUCCESS;
}

View File

@@ -0,0 +1,111 @@
// Tests to make sure no arity, dispatch or guard errors leak up past eval
#include <chaiscript/utility/utility.hpp>
int test_one(const int &)
{
return 1;
}
int main()
{
chaiscript::ChaiScript chai;
chai.add(chaiscript::fun(&test_one), "test_fun");
chai.eval("def guard_fun(i) : i.get_type_info().is_type_arithmetic() {} ");
bool eval_error = true;
// Dot notation
try {
// non-existant function
chai.eval("\"test\".test_one()");
eval_error = false;
} catch (const chaiscript::exception::eval_error &) {
}
try {
// wrong parameter type
chai.eval("\"test\".test_fun()");
eval_error = false;
} catch (const chaiscript::exception::eval_error &) {
}
try {
// wrong number of parameters
chai.eval("\"test\".test_fun(1)");
eval_error = false;
} catch (const chaiscript::exception::eval_error &) {
}
try {
// guard failure
chai.eval("\"test\".guard_fun(1)");
eval_error = false;
} catch (const chaiscript::exception::eval_error &) {
}
// regular notation
try {
// non-existant function
chai.eval("test_one(\"test\")");
eval_error = false;
} catch (const chaiscript::exception::eval_error &) {
}
try {
// wrong parameter type
chai.eval("test_fun(\"test\")");
eval_error = false;
} catch (const chaiscript::exception::eval_error &) {
}
try {
// wrong number of parameters
chai.eval("test_fun(\"test\")");
eval_error = false;
} catch (const chaiscript::exception::eval_error &) {
}
try {
// guard failure
chai.eval("guard_fun(\"test\")");
eval_error = false;
} catch (const chaiscript::exception::eval_error &) {
}
// index operator
try {
chai.eval("var a = [1,2,3]; a[\"bob\"];");
eval_error = false;
} catch (const chaiscript::exception::eval_error &) {
}
// unary operator
try {
chai.eval("++\"bob\"");
eval_error = false;
} catch (const chaiscript::exception::eval_error &) {
}
// binary operator
try {
chai.eval("\"bob\" + 1");
eval_error = false;
} catch (const chaiscript::exception::eval_error &) {
}
if (eval_error)
{
return EXIT_SUCCESS;
} else {
return EXIT_FAILURE;
}
}

View File

@@ -5,3 +5,57 @@ for (var i = 0; i < 5; ++i) {
}
assert_equal([0,1,2,3,4], ret);
var j = 0;
for (;j<10; ++j)
{
}
assert_equal(10, j);
var k = 0;
for (;k<10; )
{
++k;
}
assert_equal(10, k);
for (;;)
{
break;
}
var l = 0;
for (;;l = 1)
{
break;
}
assert_equal(0, l)
def isNotFive(x)
{
if (x != 5)
{
return true
} else {
return false
}
}
var m;
for (m = 0; isNotFive(m); m = m + 1)
{
}
assert_equal(5, m);

View File

@@ -17,7 +17,7 @@ int main()
chaiscript::ChaiScript chai;
chai.eval("def test_fun(x) { return 3; }");
chai.eval("def test_fun(x) : x == \"hi\" { return 4; }");
chai.eval("def test_fun(x) { return 5; }");
// chai.eval("def test_fun(x) { return 5; }");
chai.add(chaiscript::fun(&test_one), "test_fun");
chai.add(chaiscript::fun(&test_two), "test_fun");

View File

@@ -0,0 +1,2 @@
assert_throws("Function already defined", fun() { def foo(x) { x + 1 }; def foo(x) { x + 1 } } );

View File

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

4
unittests/hashbang.chai Normal file
View File

@@ -0,0 +1,4 @@
#!/usr/bin/env chai
//We just have to reach this point for success
assert_equal(true, true);

View File

@@ -6,3 +6,12 @@ var t = TestDerivedType();
assert_equal(t0.func(), 0);
assert_equal(t.func(), 1);
assert_equal(10, t0.val);
assert_equal(15, t0.const_val);
assert_equal(10, t.val);
assert_equal(15, t.const_val);
t.val = 23;
assert_equal(23, t.val)

View File

@@ -0,0 +1,88 @@
#include <chaiscript/chaiscript.hpp>
#define TEST_LITERAL(v) test_literal(v, #v)
template<typename T>
bool test_literal(T val, const std::string &str)
{
chaiscript::ChaiScript chai;
T val2 = chai.eval<T>(str);
std::cout << "Comparing : " << val << " " << val2 << std::endl;
return val == val2;
}
int main()
{
if( TEST_LITERAL(0xF)
&& TEST_LITERAL(0xFF)
&& TEST_LITERAL(0xFFF)
&& TEST_LITERAL(0xFFFF)
&& TEST_LITERAL(0xFFFFF)
&& TEST_LITERAL(0xFFFFFF)
&& TEST_LITERAL(0xFFFFFFF)
&& TEST_LITERAL(0xFFFFFFFF)
&& TEST_LITERAL(0xFFFFFFFFF)
&& TEST_LITERAL(0xFFFFFFFFFF)
&& TEST_LITERAL(0xFFFFFFFFFFF)
&& TEST_LITERAL(0xFFFFFFFFFFFF)
&& TEST_LITERAL(0xFFFFFFFFFFFFF)
&& TEST_LITERAL(0xFFFFFFFFFFFFFF)
&& TEST_LITERAL(0xFFFFFFFFFFFFFFF)
&& TEST_LITERAL(0xFFFFFFFFFFFFFFFF)
&& TEST_LITERAL(01)
&& TEST_LITERAL(017)
&& TEST_LITERAL(0177)
&& TEST_LITERAL(01777)
&& TEST_LITERAL(017777)
&& TEST_LITERAL(0177777)
&& TEST_LITERAL(01777777)
&& TEST_LITERAL(017777777)
&& TEST_LITERAL(0177777777)
&& TEST_LITERAL(01777777777)
&& TEST_LITERAL(017777777777)
&& TEST_LITERAL(0177777777777)
&& TEST_LITERAL(01777777777777)
&& TEST_LITERAL(017777777777777)
&& TEST_LITERAL(0177777777777777)
&& TEST_LITERAL(01777777777777777)
&& TEST_LITERAL(017777777777777777)
&& TEST_LITERAL(0177777777777777777)
&& TEST_LITERAL(01777777777777777777)
&& TEST_LITERAL(017777777777777777777)
&& TEST_LITERAL(0177777777777777777777)
&& TEST_LITERAL(01777777777777777777777)
&& TEST_LITERAL(1)
&& TEST_LITERAL(17)
&& TEST_LITERAL(177)
&& TEST_LITERAL(1777)
&& TEST_LITERAL(17777)
&& TEST_LITERAL(177777)
&& TEST_LITERAL(1777777)
&& TEST_LITERAL(17777777)
&& TEST_LITERAL(177777777)
&& TEST_LITERAL(1777777777)
&& TEST_LITERAL(17777777777)
&& TEST_LITERAL(177777777777)
&& TEST_LITERAL(1777777777777)
&& TEST_LITERAL(17777777777777)
&& TEST_LITERAL(177777777777777)
&& TEST_LITERAL(1777777777777777)
&& TEST_LITERAL(17777777777777777)
&& TEST_LITERAL(177777777777777777)
&& TEST_LITERAL(1777777777777777777)
)
{
return EXIT_SUCCESS;
} else {
return EXIT_FAILURE;
}
}

View File

@@ -1,2 +1,4 @@
load_module("test_module")
assert_equal("Hello World", hello_world());

View File

@@ -1 +1,29 @@
assert_equal([true, false, true], map([1,2,3], odd))
var m = ["a":1, "b":2];
assert_equal(1, m.count("a"))
assert_equal(0, m.count("c"))
assert_equal(1, m.erase("a"))
assert_equal(1, m.size())
assert_equal(0, m.erase("a"))
assert_equal(1, m.size());
var m2 = ["c":3, "b":4]
m.insert(m2);
assert_equal(3, m["c"])
// The inserted values do not overwrite the existing ones
assert_equal(2, m["b"])
assert_equal(2, m.size())
var v = "bob";
m.insert_ref(Map_Pair("d", v))
assert_equal("bob", m["d"])
v = "bob2"
assert_equal("bob2", m["d"])

5
unittests/map_count.chai Normal file
View File

@@ -0,0 +1,5 @@
assert_equal(1, ["a":1].count("a"))
assert_equal(0, ["A":1].count("a"))

View File

@@ -1,3 +1,14 @@
var x = ["bob":1, "fred":2]
assert_equal(2, x.size());
// Make sure vector elements are copied into place for consistency with
// map inplace construction
var i = 1;
var y = ["a":i];
assert_equal(1, y["a"]);
i = 3;
assert_equal(3, i);
assert_equal(1, y["a"]);

View File

@@ -0,0 +1,11 @@
load_module("test_module")
var t0 = TestBaseType()
t0.val = 13
assert_equal(15, t0.const_val)
assert_equal(13, t0.val)
assert_equal(15, t0.constMe().const_val)
assert_equal(13, t0.constMe().val)

View File

@@ -0,0 +1,4 @@
var x = 3 +
4
assert_equal(x, 7);

View File

@@ -0,0 +1,96 @@
#include <iostream>
#include <list>
#include <algorithm>
#include <chaiscript/chaiscript.hpp>
#include <boost/thread.hpp>
int expected_value(int num_iters)
{
int i = 0;
for (int k = 0; k<num_iters * 10; ++k)
{
i += k;
}
return i;
}
void do_work(chaiscript::ChaiScript &c, int id)
{
try{
std::stringstream ss;
ss << "MyVar" << rand();
c.add(chaiscript::var(5), ss.str());
ss.str("");
ss << id;
c.use("multithreaded_work.inc");
c("do_chai_work(4000, " + ss.str() + ");");
} catch (const std::exception &e) {
std::cout << "exception: " << e.what() << " thread: " << id;
}
}
int main()
{
// Disable deprecation warning for getenv call.
#ifdef BOOST_MSVC
#pragma warning(push)
#pragma warning(disable : 4996)
#endif
const char *usepath = getenv("CHAI_USE_PATH");
const char *modulepath = getenv("CHAI_MODULE_PATH");
#ifdef BOOST_MSVC
#pragma warning(pop)
#endif
std::vector<std::string> usepaths;
usepaths.push_back("");
if (usepath)
{
usepaths.push_back(usepath);
}
std::vector<std::string> modulepaths;
modulepaths.push_back("");
if (modulepath)
{
modulepaths.push_back(modulepath);
}
chaiscript::ChaiScript chai(modulepaths,usepaths);
boost::thread_group threads;
// Ensure at least two, but say only 7 on an 8 core processor
int num_threads = std::max<unsigned int>(boost::thread::hardware_concurrency() - 1, 2u);
for (int i = 0; i < num_threads; ++i)
{
threads.create_thread(boost::bind(&do_work, boost::ref(chai), i));
}
threads.join_all();
for (int i = 0; i < num_threads; ++i)
{
std::stringstream ss;
ss << i;
if (chai.eval<int>("getvalue(" + ss.str() + ")") != expected_value(4000))
{
return EXIT_FAILURE;
}
if (chai.eval<int>("getid(" + ss.str() + ")") != i)
{
return EXIT_FAILURE;
}
}
return EXIT_SUCCESS;
}

View File

@@ -0,0 +1,15 @@
def do_chai_work(num_iters, id)
{
var i = 0;
for (var k = 0; k<num_iters * 10; ++k)
{
if (k == 1000)
{
eval("def getid(id) : id == " + to_string(id) + " { return " + to_string(id) + "}");
}
i += k;
}
eval("def getvalue(id) : id == " + to_string(id) + " { return " + to_string(i) + "}");
}

View File

@@ -0,0 +1,11 @@
assert_equal(true, int_type.bare_equal(1.get_type_info()))
assert_equal(true, unsigned_int_type.bare_equal(1u.get_type_info()))
assert_equal(true, unsigned_long_type.bare_equal(1lu.get_type_info()))
assert_equal(true, long_type.bare_equal(1l.get_type_info()))
assert_equal(true, int64_t_type.bare_equal(1ll.get_type_info()))
assert_equal(true, uint64_t_type.bare_equal(1ull.get_type_info()))
assert_equal(true, double_type.bare_equal(1.6.get_type_info()))
assert_equal(true, float_type.bare_equal(1.6f.get_type_info()))
assert_equal(true, long_double_type.bare_equal(1.6l.get_type_info()))

View File

@@ -0,0 +1,9 @@
attr bob::z
def bob::bob() { this.z = 10 }
attr bob2::z
def bob2::bob2() { this.z = 12 }
var b = bob();
var b2 = bob2();

View File

@@ -38,19 +38,19 @@ int main()
chaiscript::ChaiScript chai;
chai.add(m);
chai.add(chaiscript::fun(&Test::count), "count");
// chai.add(chaiscript::fun(&Test::count), "count");
int count = chai.eval<int>("count()");
int count2 = chai.eval<int>("var i = 0; { var t = Test(); } return i;");
int count3 = chai.eval<int>("var i = 0; { var t = Test(); i = count(); } return i;");
int count3 = chai.eval<int>("i = 0; { var t = Test(); i = count(); } return i;");
int count4 = chai.eval<int>("var i = 0; { var t = Test(); { var t2 = Test(); i = count(); } } return i;");
int count4 = chai.eval<int>("i = 0; { var t = Test(); { var t2 = Test(); i = count(); } } return i;");
int count5 = chai.eval<int>("var i = 0; { var t = Test(); { var t2 = Test(); } i = count(); } return i;");
int count5 = chai.eval<int>("i = 0; { var t = Test(); { var t2 = Test(); } i = count(); } return i;");
int count6 = chai.eval<int>("var i = 0; { var t = Test(); { var t2 = Test(); } } i = count(); return i;");
int count6 = chai.eval<int>("i = 0; { var t = Test(); { var t2 = Test(); } } i = count(); return i;");
if (count == 0
&& count2 == 0

View File

@@ -0,0 +1,8 @@
load_module("reflection")
try {
eval("def `+`(x, y) \n { \n print(i); \n } \n \n var i = 10; \n \"1\" + 1;\n")
assert_false(true); // we should never get here
} catch (e) {
assert_equal("Error: \"Can not find object: i\" ", e.what());
}

View File

@@ -0,0 +1,19 @@
def f(x) { x+= 2; }
var i = 1;
assert_equal(i, 1);
f(i);
assert_equal(i, 3);
def g(x) { x+= " World"; }
var s = "Hello";
assert_equal(s, "Hello");
g(s);
assert_equal(s, "Hello World");

View File

@@ -0,0 +1,8 @@
load_module("test_module")
var i = 1;
var t0 = TestBaseType(i);
var t1 = TestBaseType(get_new_int())

View File

@@ -0,0 +1,61 @@
#include <chaiscript/chaiscript.hpp>
int myfun()
{
return 2;
}
int main()
{
chaiscript::ChaiScript chai;
// save the initial state of globals and locals
chaiscript::ChaiScript::State firststate = chai.get_state();
std::map<std::string, chaiscript::Boxed_Value> locals = chai.get_locals();
// add some new globals and locals
chai.add(chaiscript::var(1), "i");
chai.add(chaiscript::fun(&myfun), "myfun");
bool didcall = chai.eval<int>("myfun()") == 2;
bool hadi = chai.eval<int>("i") == 1;
chai.set_state(firststate);
// set state should have reverted the state of the functions and dropped
// the 'myfun'
bool didnotcall = false;
try {
chai.eval<int>("myfun()");
} catch (const chaiscript::exception::eval_error &) {
didnotcall = true;
}
// set state should not affect the local variables
bool stillhasid = chai.eval<int>("i") == 1;
// After resetting the locals we expect the 'i' to be gone
chai.set_locals(locals);
bool nolongerhasid = false;
try {
chai.eval<int>("i");
} catch (const chaiscript::exception::eval_error &) {
nolongerhasid = true;
}
if (didcall && hadi && didnotcall && stillhasid && nolongerhasid)
{
return EXIT_SUCCESS;
} else {
return EXIT_FAILURE;
}
}

View File

@@ -0,0 +1,29 @@
#include <chaiscript/utility/utility.hpp>
class Test {
public:
Test() : value_(5) {}
short get_value() { return value_; }
short value_;
};
int main()
{
chaiscript::ChaiScript chai;
chai.add(chaiscript::user_type<Test>(), "Test");
chai.add(chaiscript::constructor<Test()>(), "Test");
chai.add(chaiscript::fun(&Test::get_value), "get_value");
chai.eval("var t := Test();");
if (chai.eval<bool>("t.get_value() == 5"))
{
return EXIT_SUCCESS;
} else {
return EXIT_FAILURE;
}
}

View File

@@ -0,0 +1,60 @@
#include <chaiscript/chaiscript.hpp>
int dosomething(int i)
{
return i + 2;
}
int dosomethingelse(int i)
{
return i * 2;
}
int main()
{
chaiscript::ChaiScript chai;
chai.add(chaiscript::fun(&dosomething), "dosomething");
chai.add(chaiscript::var(1), "i");
for (int i = 0; i < 10; ++i)
{
chaiscript::ChaiScript chai2;
chai2.add(chaiscript::fun(&dosomethingelse), "dosomethingelse");
std::stringstream ss;
ss << i;
if (chai.eval<int>("dosomething(" + ss.str() + ")") != i + 2)
{
return EXIT_FAILURE;
}
if (chai2.eval<int>("dosomethingelse(" + ss.str() + ")") != i * 2)
{
return EXIT_FAILURE;
}
try {
chai2.eval("dosomething(1)");
return EXIT_FAILURE; // should not get here
} catch (const chaiscript::exception::eval_error &) {
// nothing to do, expected case
}
try {
chai2.eval("i");
return EXIT_FAILURE; // should not get here
} catch (const chaiscript::exception::eval_error &) {
// nothing to do, expected case
}
try {
chai.eval("dosomethingelse(1)");
return EXIT_FAILURE; // should not get here
} catch (const chaiscript::exception::eval_error &) {
// nothing to do, expected case
}
}
}

View File

@@ -0,0 +1,2 @@
assert_equal(true, "".empty())
assert_equal(3, "123".size())

View File

@@ -0,0 +1 @@
assert_equal("3ab", "123abab".substr(2,3))

View File

@@ -0,0 +1,22 @@
var total = 0;
switch(2) {
case (1) {
total += 1;
break;
}
case (2) {
total += 2;
break;
}
case (3) {
total += 4;
break;
}
case (4) {
total += 8;
break;
}
}
assert_equal(total, 2)

View File

@@ -0,0 +1,18 @@
var total = 0;
switch(2) {
case (1) {
total += 1;
}
case (3) {
total += 4;
}
case (4) {
total += 8;
}
default {
total += 16;
}
}
assert_equal(total, 16)

View File

@@ -0,0 +1,4 @@
switch(true) { }
// We just have to get here without error for success
assert_equal(true, true);

View File

@@ -0,0 +1,18 @@
var total = 0;
switch(2) {
case (1) {
total += 1;
}
case (2) {
total += 2;
}
case (3) {
total += 4;
}
case (4) {
total += 8;
}
}
assert_equal(total, 14);

View File

@@ -0,0 +1,19 @@
var total = 0;
switch(2) {
case (1) {
total += 1;
}
case (2) {
total += 2;
}
case (3) {
total += 4;
break;
}
case (4) {
total += 8;
}
}
assert_equal(total, 6)

View File

@@ -0,0 +1,18 @@
var funcs = get_functions();
assert_true(funcs.size() > 0);
assert_true(funcs["to_string"].get_type_info().bare_equal(Function_type));
var i = 1;
var objs = get_objects();
assert_true(objs.size() > 0);
assert_true(objs["i"].get_type_info().bare_equal(int_type));
assert_true(objs.count("j") == 0);

View File

@@ -0,0 +1,3 @@
for_each(range([1..10]), fun(x) {print(x);} );
assert_true(true);

View File

@@ -0,0 +1,2 @@
var x = 4;
assert_equal(x < 3 ? 4 < 1 : 5 > 3, true);

View File

@@ -5,7 +5,7 @@ def assert_equal(x, y)
// Passes
} else {
// Fails
print("assert_equal failure: got " + to_string(y) + " expected " + to_string(x));
print("assert_equal failure: got '" + to_string(y) + "' expected '" + to_string(x) + "'");
exit(-1);
}
}
@@ -23,7 +23,7 @@ def assert_true(f)
{
if (!f)
{
print("assert_false failure");
print("assert_true failure");
exit(-1);
}
}

View File

@@ -30,8 +30,8 @@ int main()
chaiscript::ChaiScript chai;
chai.add(m);
if (chai.eval<std::string>("var t = Test(); t.function2(); ") == "Function2"
&& chai.eval<std::string>("var t = Test(); t.functionOverload(1); ") == "int"
&& chai.eval<std::string>("var t = Test(); t.functionOverload(1.1); ") == "double")
&& chai.eval<std::string>("var t2 = Test(); t2.functionOverload(1); ") == "int"
&& chai.eval<std::string>("var t3 = Test(); t3.functionOverload(1.1); ") == "double")
{
chai.eval("t = Test();");
return EXIT_SUCCESS;

View File

@@ -0,0 +1,2 @@
assert_throws("Variable already defined", fun() { var y = 10; var y = 20; })

View File

@@ -1,2 +1,14 @@
var x = [1, 2, 3]
assert_equal(3, x.size())
// Make sure vector elements are copied into place for consistency with
// map inplace construction
var i = 1;
var y = [i];
assert_equal(1, y[0]);
i = 3;
assert_equal(3, i);
assert_equal(1, y[0]);

View File

@@ -0,0 +1,3 @@
var x = [1, 2u, 3.0l]
assert_equal(3.0l, x[2])
assert_equal(2u, x[1])