Compare commits

...

144 Commits

Author SHA1 Message Date
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
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
1cd9a9098c Update gcc flags for MacOS to ignore sign comparison warnings 2011-06-18 07:34:55 -06:00
Jason Turner
5ff14a54db Commented out code removal 2011-06-16 10:42:26 -06:00
Jason Turner
28e3d442e2 Update version number to 3.1.0 for next release 2011-06-16 10:19:54 -06:00
Jason Turner
bb0edcb62a Add exception_specification and unittests for it. #6 2011-06-16 10:14:52 -06:00
Jonathan Turner
9a015a5c49 Fix typo in unit test and add string literal access 2011-06-13 18:14:41 -07:00
Jonathan Turner
9d20f60903 Update license year 2011-06-13 07:45:11 -07:00
Jonathan Turner
5426496b4f Fix parsing of member access and function calls 2011-06-13 07:43:51 -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
9e9fb3ad7d Fix one more documentation error 2011-06-10 16:42:38 -06:00
Jason Turner
8cc3651c76 Correct copyright date 2011-06-10 16:41:00 -06:00
Jason Turner
4d879afca7 Documentation updates 2011-06-10 16:38:20 -06:00
Jason Turner
afae221cb3 Add tests for more complex uses of the index operator 2011-06-10 11:18:58 -06:00
Jason Turner
b064bb61e9 Finish renaming and cleaning up of Boxed_Number type for dump_system() output 2011-06-10 10:12:09 -06:00
Jason Turner
c839e4bc21 Handle unnecessary MSVC compiler warnings. 2011-06-08 19:19:59 -06:00
Jason Turner
7a9baeb350 Rename of numeric to number 2011-06-08 13:53:55 -06:00
Jason Turner
6d4041b2a1 Added profile for mathy functions.x 2011-06-07 14:59:43 -06:00
Jason Turner
1932cbfbbc Eliminate duplicate code and reduce Boxed_Value copies necessary 2011-06-04 12:31:33 -06:00
Jonathan Turner
8fecf5c145 Merge branch 'master' of github.com:ChaiScript/ChaiScript 2011-06-04 11:02:07 -07:00
Jonathan Turner
6131a9c4c1 Moved common operators into their own AST nodes and removed the operator child. 2011-06-04 11:01:35 -07:00
Jason Turner
881d569d8e Remove unnecessary loop from Binary_Operator 2011-06-04 10:34:15 -06:00
Jonathan Turner
6c18c197c6 Fixed operator parsing to return trees instead of flat representations. Fixed evaluator to not loop over equations. 2011-06-04 09:15:19 -07:00
Jason Turner
f47ec0d522 Merge pull request #7 from lefticus/master
Merge Number Performance Updates
2011-06-03 17:52:04 -07:00
Jason Turner
4053196188 Reduce creation of new Boxed_Value containers when returning the same value that was passed in 2011-06-04 04:26:06 +08:00
Jason Turner
5b40a85024 Add direct access to Boxed_Value data * for high performance operations 2011-06-04 04:26:00 +08:00
Jason Turner
36faba8ed3 Bypass dispatch during numeric operations. 2x speedup 2011-06-04 04:25:54 +08:00
Jason Turner
7d022c4f0d Add is_prime profile script 2011-06-04 04:25:47 +08:00
Jason Turner
b933bb6c50 Begin move of Operators code out a level so that it can be used before dispatch 2011-06-04 04:25:42 +08:00
Jason Turner
92bfcfdcf3 Wrap up new Boxed_Numeric support 2011-06-04 04:25:36 +08:00
Jason Turner
3b754cfec4 Further simplification and refinement of enhanced Algebraic types support 2011-06-04 04:25:30 +08:00
Jason Turner
3689c01e4b Significant reduction in templates instantiated by grouping of operators - smaller code and compile time 2011-06-04 04:25:24 +08:00
Jason Turner
4b90fbd07a wrap up support for all built in C++ Arithmetic types 2011-06-04 04:25:18 +08:00
Jason Turner
1a225dca67 Progress towards eliminating arithmetic operators on a per-type basis 2011-06-04 04:25:12 +08:00
Jason Turner
226666c2bb Rename Boxed_POD_Value to Boxed_Numeric, which is more correct. 2011-06-04 04:24:57 +08:00
Jason Turner
d4ef226911 Reduce creation of new Boxed_Value containers when returning the same value that was passed in 2011-06-03 13:48:32 -06:00
Jason Turner
6491262491 Add direct access to Boxed_Value data * for high performance operations 2011-06-03 12:41:38 -06:00
Jason Turner
2c4d69bfc0 Bypass dispatch during numeric operations. 2x speedup 2011-06-01 22:12:50 -06:00
Jason Turner
f423969a8e Add is_prime profile script 2011-05-31 08:09:30 -06:00
Jason Turner
36cd4c370a Begin move of Operators code out a level so that it can be used before dispatch 2011-05-31 07:42:30 -06:00
Jason Turner
85f69782b2 Wrap up new Boxed_Numeric support 2011-05-30 19:38:04 -06:00
Jason Turner
1f130c0891 Further simplification and refinement of enhanced Algebraic types support 2011-05-29 17:33:45 -06:00
Jason Turner
fdd1b40a9f Significant reduction in templates instantiated by grouping of operators - smaller code and compile time 2011-05-29 09:14:48 -06:00
Jason Turner
6993d58fdc wrap up support for all built in C++ Arithmetic types 2011-05-28 23:48:17 -06:00
Jason Turner
1845114d36 Progress towards eliminating arithmetic operators on a per-type basis 2011-05-26 05:58:19 -06:00
Jason Turner
bba1ffde38 Rename Boxed_POD_Value to Boxed_Numeric, which is more correct. 2011-05-24 12:39:39 -06:00
87 changed files with 4548 additions and 1291 deletions

View File

@@ -13,11 +13,11 @@ list(APPEND CPACK_SOURCE_IGNORE_FILES ".swp")
list(APPEND CPACK_SOURCE_IGNORE_FILES ".*~") list(APPEND CPACK_SOURCE_IGNORE_FILES ".*~")
set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/license.txt") 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_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/description.txt")
set(CPACK_PACKAGE_VERSION_MAJOR 3) set(CPACK_PACKAGE_VERSION_MAJOR 4)
set(CPACK_PACKAGE_VERSION_MINOR 0) set(CPACK_PACKAGE_VERSION_MINOR 1)
set(CPACK_PACKAGE_VERSION_PATCH 0) set(CPACK_PACKAGE_VERSION_PATCH 0)
set(CPACK_PACKAGE_EXECUTABLES "chai;ChaiScript Eval") set(CPACK_PACKAGE_EXECUTABLES "chai;ChaiScript Eval")
set(CPACK_PACKAGE_VENDOR "ChaiScript.com") set(CPACK_PACKAGE_VENDOR "ChaiScript.com")
@@ -39,58 +39,71 @@ configure_file(Doxyfile.in ${CMAKE_BINARY_DIR}/Doxyfile)
include(CTest) include(CTest)
include(CPack) 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() enable_testing()
MESSAGE(STATUS "Detecting readline support") message(STATUS "Detecting readline support")
if (READLINE_LIBRARY) if (READLINE_LIBRARY)
MESSAGE(STATUS "Found: ${READLINE_LIBRARY}") message(STATUS "Found: ${READLINE_LIBRARY}")
SET (READLINE_LIB readline) set (READLINE_LIB readline)
ADD_DEFINITIONS(/DREADLINE_AVAILABLE) add_definitions(/DREADLINE_AVAILABLE)
else(READLINE_LIBRARY) else(READLINE_LIBRARY)
MESSAGE(STATUS "Not Found") message(STATUS "Not Found")
SET (READLINE_LIB ) set (READLINE_LIB )
SET (READLINE_FLAG ) set (READLINE_FLAG )
endif(READLINE_LIBRARY) endif(READLINE_LIBRARY)
IF(MSVC) if(MSVC)
ADD_DEFINITIONS(/W4) add_definitions(/W4)
IF(CMAKE_CL_64) if(CMAKE_CL_64)
ADD_DEFINITIONS(/bigobj) add_definitions(/bigobj)
ENDIF() endif()
ELSE() else()
# -Wno-missing-field-initializers is for boost on macos add_definitions(-Wall -Wextra -Wshadow -pedantic)
ADD_DEFINITIONS(-Wall -Wextra -Wno-missing-field-initializers -Wshadow)
ENDIF() if (APPLE)
# -Wno-missing-field-initializers is for boost on macos
add_definitions(-Wno-missing-field-initializers -Wno-sign-compare)
endif()
endif()
include_directories(include) 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_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_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) if (MULTITHREAD_SUPPORT_ENABLED)
find_package(Boost 1.36.0 COMPONENTS thread) find_package(Boost 1.36.0 COMPONENTS thread system)
if (Boost_FOUND) if (Boost_FOUND)
link_directories( ${Boost_LIBRARY_DIRS} ) link_directories( ${Boost_LIBRARY_DIRS} )
else() else()
message(FATAL_ERROR "Can not find Boost") message(FATAL_ERROR "Can not find Boost")
endif(Boost_FOUND) endif(Boost_FOUND)
if (CMAKE_HOST_UNIX)
add_definitions(-pthread)
list(APPEND LIBS "pthread")
endif()
else() else()
ADD_DEFINITIONS(-DCHAISCRIPT_NO_THREADS) add_definitions(-DCHAISCRIPT_NO_THREADS)
endif() endif()
if (CMAKE_HOST_UNIX) if (CMAKE_HOST_UNIX)
SET(DYNAMIC_LOADER "dl") list(APPEND LIBS "dl")
endif(CMAKE_HOST_UNIX) endif(CMAKE_HOST_UNIX)
list(APPEND LIBS ${READLINE_LIB})
if (MSVC) if (NOT MSVC)
# Boost on MSVC does automatic linking # Boost on MSVC does automatic linking
SET(LIBS ${DYNAMIC_LOADER} ${READLINE_LIB}) list(APPEND LIBS ${Boost_LIBRARIES})
else()
SET(LIBS ${DYNAMIC_LOADER} ${Boost_LIBRARIES} ${READLINE_LIB})
endif() endif()
if (CMAKE_COMPILER_2005) if (CMAKE_COMPILER_2005)
@@ -100,7 +113,7 @@ endif()
include_directories(${Boost_INCLUDE_DIRS}) include_directories(${Boost_INCLUDE_DIRS})
include_directories(${Boost_INCLUDE_DIR}) include_directories(${Boost_INCLUDE_DIR})
add_executable(chai src/main.cpp) add_executable(chai src/main.cpp ${Chai_INCLUDES})
target_link_libraries(chai ${LIBS}) target_link_libraries(chai ${LIBS})
if (BUILD_SAMPLES) if (BUILD_SAMPLES)
@@ -124,7 +137,7 @@ file(GLOB UNIT_TESTS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/unittests/ ${CMAKE_CUR
list(SORT UNIT_TESTS) list(SORT UNIT_TESTS)
IF(BUILD_TESTING) if(BUILD_TESTING)
option(UNIT_TEST_LIGHT "Unit tests light (expect module loading failures)" FALSE) option(UNIT_TEST_LIGHT "Unit tests light (expect module loading failures)" FALSE)
foreach(filename ${UNIT_TESTS}) foreach(filename ${UNIT_TESTS})
@@ -132,13 +145,13 @@ IF(BUILD_TESTING)
add_test(${filename} chai ${CMAKE_CURRENT_SOURCE_DIR}/unittests/unit_test.inc ${CMAKE_CURRENT_SOURCE_DIR}/unittests/${filename}) add_test(${filename} chai ${CMAKE_CURRENT_SOURCE_DIR}/unittests/unit_test.inc ${CMAKE_CURRENT_SOURCE_DIR}/unittests/${filename})
endforeach(filename) endforeach(filename)
SET_PROPERTY(TEST ${UNIT_TESTS} set_property(TEST ${UNIT_TESTS}
PROPERTY ENVIRONMENT PROPERTY ENVIRONMENT
"CHAI_USE_PATH=${CMAKE_CURRENT_SOURCE_DIR}/unittests/" "CHAI_USE_PATH=${CMAKE_CURRENT_SOURCE_DIR}/unittests/"
"CHAI_MODULE_PATH=${CMAKE_CURRENT_BINARY_DIR}/" "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) add_executable(utility_test unittests/utility_test.cpp)
target_link_libraries(utility_test ${LIBS}) target_link_libraries(utility_test ${LIBS})
add_test(NAME Utility_Test COMMAND utility_test) add_test(NAME Utility_Test COMMAND utility_test)
@@ -154,7 +167,7 @@ IF(BUILD_TESTING)
add_executable(functor_cast_test unittests/functor_cast_test.cpp) add_executable(functor_cast_test unittests/functor_cast_test.cpp)
target_link_libraries(functor_cast_test ${LIBS}) target_link_libraries(functor_cast_test ${LIBS})
add_test(NAME Functor_Cast_Test COMMAND functor_cast_test) add_test(NAME Functor_Cast_Test COMMAND functor_cast_test)
add_executable(boxed_cast_test unittests/boxed_cast_test.cpp) add_executable(boxed_cast_test unittests/boxed_cast_test.cpp)
target_link_libraries(boxed_cast_test ${LIBS}) target_link_libraries(boxed_cast_test ${LIBS})
add_test(NAME Boxed_Cast_Test COMMAND boxed_cast_test) add_test(NAME Boxed_Cast_Test COMMAND boxed_cast_test)
@@ -175,6 +188,43 @@ IF(BUILD_TESTING)
target_link_libraries(eval_catch_exception_test ${LIBS}) target_link_libraries(eval_catch_exception_test ${LIBS})
add_test(NAME Eval_Catch_Exception_Test COMMAND eval_catch_exception_test) add_test(NAME Eval_Catch_Exception_Test COMMAND eval_catch_exception_test)
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)
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 add_executable(multifile_test unittests/multifile_test_main.cpp unittests/multifile_test_chai.cpp
unittests/multifile_test_module.cpp) unittests/multifile_test_module.cpp)
target_link_libraries(multifile_test ${LIBS}) target_link_libraries(multifile_test ${LIBS})
@@ -184,29 +234,28 @@ IF(BUILD_TESTING)
target_link_libraries(test_module ${LIBS}) target_link_libraries(test_module ${LIBS})
install(TARGETS test_module RUNTIME DESTINATION bin LIBRARY DESTINATION lib/chaiscript) install(TARGETS test_module RUNTIME DESTINATION bin LIBRARY DESTINATION lib/chaiscript)
ENDIF() endif()
ENDIF(BUILD_TESTING) endif(BUILD_TESTING)
install(TARGETS chai ${MODULES} RUNTIME DESTINATION bin LIBRARY DESTINATION lib/chaiscript ) install(TARGETS chai ${MODULES} RUNTIME DESTINATION bin LIBRARY DESTINATION lib/chaiscript )
install(DIRECTORY include/chaiscript DESTINATION include install(DIRECTORY include/chaiscript DESTINATION include
PATTERN "*.hpp" PATTERN "*.hpp"
PATTERN "*/.svn*" EXCLUDE PATTERN "*/.svn*" EXCLUDE
PATTERN "*/.git*" EXCLUDE PATTERN "*/.git*" EXCLUDE
PATTERN "*~" EXCLUDE) PATTERN "*~" EXCLUDE)
install(DIRECTORY unittests DESTINATION share/chaiscript install(DIRECTORY unittests DESTINATION share/chaiscript
PATTERN "*.chai" PATTERN "*.chai"
PATTERN "*.inc" PATTERN "*.inc"
PATTERN "*/.svn*" EXCLUDE PATTERN "*/.svn*" EXCLUDE
PATTERN "*/.git*" EXCLUDE PATTERN "*/.git*" EXCLUDE
PATTERN "*~" EXCLUDE) PATTERN "*~" EXCLUDE)
install(DIRECTORY samples DESTINATION share/chaiscript install(DIRECTORY samples DESTINATION share/chaiscript
PATTERN "*.chai" PATTERN "*.chai"
PATTERN "*/.svn*" EXCLUDE PATTERN "*/.svn*" EXCLUDE
PATTERN "*/.git*" EXCLUDE PATTERN "*/.git*" EXCLUDE
PATTERN "*~" EXCLUDE) PATTERN "*~" EXCLUDE)
configure_file(contrib/pkgconfig/chaiscript.pc.in lib/pkgconfig/chaiscript.pc @ONLY) configure_file(contrib/pkgconfig/chaiscript.pc.in lib/pkgconfig/chaiscript.pc @ONLY)
install(FILES "${chaiscript_BINARY_DIR}/lib/pkgconfig/chaiscript.pc" install(FILES "${chaiscript_BINARY_DIR}/lib/pkgconfig/chaiscript.pc"
DESTINATION lib/pkgconfig) DESTINATION lib/pkgconfig)

View File

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

View File

@@ -0,0 +1,9 @@
var something = 0;
for (var i = 1; i < 10000; ++i)
{
something += int(3 % 2 * 4 + 2 / 16.0 - 100 + (10 ^ 19) / 64 + (3 & 12) - (4 | 14)) % i;
}
print(something);

View File

@@ -48,7 +48,7 @@ $language_data = array (
'ESCAPE_CHAR' => '\\', 'ESCAPE_CHAR' => '\\',
'KEYWORDS' => array( 'KEYWORDS' => array(
1 => 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( 2 => array(
'def', 'false', 'fun', 'true', 'var', 'attr', 'def', 'false', 'fun', 'true', 'var', 'attr',

View File

@@ -7,6 +7,9 @@ if exists("b:current_syntax")
finish finish
end end
let s:cpo_save = &cpo
set cpo&vim
syn case match syn case match
" syncing method " syncing method
@@ -16,11 +19,11 @@ syn sync fromstart
syn region chaiscriptString start=+"+ end=+"+ skip=+\\\\\|\\"+ contains=chaiscriptSpecial,chaiscriptEval,@Spell syn region chaiscriptString start=+"+ end=+"+ skip=+\\\\\|\\"+ contains=chaiscriptSpecial,chaiscriptEval,@Spell
" Escape characters " Escape characters
syn match chaiscriptSpecial contained "\\[\\abfnrtv\'\"]\|\\\d\{,3}" syn match chaiscriptSpecial contained "\\[\\abfnrtv\'\"]\|\\\d\{,3}"
" String evals " String evals
syn region chaiscriptEval contained start="${" end="}" syn region chaiscriptEval contained start="${" end="}"
" integer number " integer number
syn match chaiscriptNumber "\<\d\+\>" syn match chaiscriptNumber "\<\d\+\>"
@@ -42,7 +45,7 @@ syn match chaiscriptNumber "\<0b[01]\+\>"
" Various language features " Various language features
syn keyword chaiscriptCond if else syn keyword chaiscriptCond if else
syn keyword chaiscriptRepeat while for do 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 syn keyword chaiscriptExceptions try catch throw
"Keyword "Keyword
@@ -91,4 +94,6 @@ hi def link chaiscriptEval Special
let b:current_syntax = "chaiscript" let b:current_syntax = "chaiscript"
let &cpo = s:cpo_save
unlet s:cpo_save
" vim: nowrap sw=2 sts=2 ts=8 noet " vim: nowrap sw=2 sts=2 ts=8 noet

View File

@@ -1,6 +1,6 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2011, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// and Jason Turner (jason@emptycrate.com) // and Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
@@ -24,6 +24,8 @@
/// ///
/// \sa chaiscript /// \sa chaiscript
/// \sa chaiscript::ChaiScript /// \sa chaiscript::ChaiScript
/// \sa ChaiScript_Language for Built in Functions
/// \sa \ref LangGettingStarted
/// \sa \ref LangKeywordRef /// \sa \ref LangKeywordRef
/// \sa \ref LangInPlaceRef /// \sa \ref LangInPlaceRef
/// \sa \ref LangObjectSystemRef /// \sa \ref LangObjectSystemRef
@@ -32,11 +34,13 @@
/// ///
/// <hr> /// <hr>
/// ///
/// \section gettingstarted Getting Started /// \section gettingstarted API Getting Started
/// ///
/// \li \ref basics /// \li \ref basics
/// \li \ref compiling
/// \li \ref eval /// \li \ref eval
/// \li \ref addingitems /// \li \ref addingitems
/// \li \ref operatoroverloading
/// \li \ref helpermacro /// \li \ref helpermacro
/// \li \ref pointerconversions /// \li \ref pointerconversions
/// \li \ref baseclasses /// \li \ref baseclasses
@@ -50,6 +54,7 @@
/// Basic simple example: /// Basic simple example:
/// ///
/// \code /// \code
/// //main.cpp
/// #include <chaiscript/chaiscript.hpp> /// #include <chaiscript/chaiscript.hpp>
/// ///
/// double function(int i, double j) /// double function(int i, double j)
@@ -67,6 +72,27 @@
/// \endcode /// \endcode
/// ///
/// <hr> /// <hr>
/// \subsection compiling Compiling ChaiScript Applications
///
/// ChaiScript is a header only library with only two dependecies. boost::threads (optional) and the
/// operating system provided dynamic library loader, which has to be specified on some platforms.
///
/// \subsubsection compilinggcc Compiling with GCC
///
/// To compile the above application on a Unix like operating system (MacOS, Linux) with GCC you need to link
/// both boost::threads and the dynamic loader. For example:
///
/// \code
/// gcc main.cpp -I/path/to/chaiscript/headers -ldl -lboost_threads
/// \endcode
///
/// Alternatively, you may compile without threading support.
///
/// \code
/// gcc main.cpp -I/path/to/chaiscript/headers -ldl -DCHAISCRIPT_NO_THREADS
/// \endcode
///
/// <hr>
/// \subsection eval Evaluating Scripts /// \subsection eval Evaluating Scripts
/// ///
/// Scripts can be evaluated with the () operator, eval method or eval_file method. /// Scripts can be evaluated with the () operator, eval method or eval_file method.
@@ -114,7 +140,10 @@
/// ///
/// \subsubsection addingobjects Adding Objects /// \subsubsection addingobjects Adding Objects
/// ///
/// Named objects can be created with the #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 /// \code
/// using namespace chaiscript; /// using namespace chaiscript;
@@ -166,8 +195,8 @@
/// Overloaded methods will need some help, to hint the compiler as to which overload you want: /// Overloaded methods will need some help, to hint the compiler as to which overload you want:
/// ///
/// \code /// \code
/// chai.add(fun<void (MyClass::*)()>(&MyClass::overloadedmethod), "overloadedmethod")); /// chai.add(fun<void (MyClass::*)()>(&MyClass::overloadedmethod), "overloadedmethod");
/// chai.add(fun<void (MyClass::*)(const std::string &)>(&MyClass::overloadedmethod, "overloadedmethod")); /// chai.add(fun<void (MyClass::*)(const std::string &)>(&MyClass::overloadedmethod), "overloadedmethod");
/// \endcode /// \endcode
/// ///
/// There are also shortcuts built into chaiscript::fun for binding up to the first two parameters of the function. /// There are also shortcuts built into chaiscript::fun for binding up to the first two parameters of the function.
@@ -204,7 +233,29 @@
/// \endcode /// \endcode
/// ///
/// \sa chaiscript::Module /// \sa chaiscript::Module
///
/// <hr>
/// \subsection operatoroverloading Operator Overloading
/// ///
/// Operators are just like any other function in ChaiScript, to overload an operator, simply register it.
///
/// \code
/// class MyClass {
/// MyClass operator+(const MyClass &) const;
/// };
///
/// chai.add(fun(&MyClass::operator+), "+");
///
/// std::string append_string_int(const std::string &t_lhs, int t_rhs)
/// {
/// return t_lhs + boost::lexical_cast<std::string>(t_rhs);
/// }
///
/// chai.add(fun(append_string_int), "+");
/// \endcode
///
/// \sa \ref addingfunctions
///
/// <hr> /// <hr>
/// \subsection helpermacro Class Helper Macro /// \subsection helpermacro Class Helper Macro
/// ///
@@ -252,7 +303,7 @@
/// As much as possible, ChaiScript attempts to convert between &, *, const &, const *, boost::shared_ptr<T>, /// As much as possible, ChaiScript attempts to convert between &, *, const &, const *, boost::shared_ptr<T>,
/// boost::shared_ptr<const T>, boost::reference_wrapper<T>, boost::reference_wrapper<const T> and value types automatically. /// boost::shared_ptr<const T>, boost::reference_wrapper<T>, boost::reference_wrapper<const T> and value types automatically.
/// ///
/// If a var object was created in C++ from a pointer, it cannot be convered to a shared_ptr (this would add invalid reference counting). /// If a chaiscript::var object was created in C++ from a pointer, it cannot be convered to a shared_ptr (this would add invalid reference counting).
/// Const may be added, but never removed. /// Const may be added, but never removed.
/// ///
/// The take away is that you can pretty much expect function calls to Just Work when you need them to. /// The take away is that you can pretty much expect function calls to Just Work when you need them to.
@@ -365,6 +416,8 @@
/// ///
/// \subsection exceptions Exception Handling /// \subsection exceptions Exception Handling
/// ///
/// \subsubsection exceptionsbasics Exception Handling Basics
///
/// Exceptions can be thrown in ChaiScript and caught in C++ or thrown in C++ and caught in /// Exceptions can be thrown in ChaiScript and caught in C++ or thrown in C++ and caught in
/// ChaiScript. /// ChaiScript.
/// ///
@@ -376,10 +429,12 @@
/// ///
/// int main() /// int main()
/// { /// {
/// // Throw in C++, catch in ChaiScript
/// chaiscript::ChaiScript chai; /// chaiscript::ChaiScript chai;
/// chai.add(chaiscript::fun(&throwexception), "throwexception"); /// chai.add(chaiscript::fun(&throwexception), "throwexception");
/// chai("try { throwexception(); } catch (e) { print(e.what()); }"); // prints "err" /// chai("try { throwexception(); } catch (e) { print(e.what()); }"); // prints "err"
/// ///
/// // Throw in ChaiScript, catch in C++
/// try { /// try {
/// chai("throw(1)"); /// chai("throw(1)");
/// } catch (chaiscript::Boxed_Value bv) { /// } catch (chaiscript::Boxed_Value bv) {
@@ -388,6 +443,31 @@
/// } /// }
/// } /// }
/// \endcode /// \endcode
///
/// \subsubsection exceptionsautomatic Exception Handling Automatic Unboxing
///
/// As an alternative to the manual unboxing of exceptions shown above, exception specifications allow the user to tell
/// ChaiScript what possible exceptions are expected from the script being executed.
///
/// Example:
/// \code
/// chaiscript::ChaiScript chai;
///
/// try {
/// chai.eval("throw(runtime_error(\"error\"))", chaiscript::exception_specification<int, double, float, const std::string &, const std::exception &>());
/// } catch (const double e) {
/// } catch (int) {
/// } catch (float) {
/// } catch (const std::string &) {
/// } catch (const std::exception &e) {
/// // This is the one what will be called in the specific throw() above
/// }
/// \endcode
///
/// \sa chaiscript::Exception_Handler for details on automatic exception unboxing
/// \sa chaiscript::exception_specification
/// \page LangObjectSystemRef ChaiScript Language Object Model Reference /// \page LangObjectSystemRef ChaiScript Language Object Model Reference
/// ///
@@ -429,6 +509,114 @@
/// In-place Map ::= "[" (string ":" expression)+ "]" /// In-place Map ::= "[" (string ":" expression)+ "]"
/// \endcode /// \endcode
/// \page LangGettingStarted ChaiScript Language Getting Started
///
/// ChaiScript is a simple language that should feel familiar to anyone who knows
/// C++ or ECMAScript (JavaScript).
///
/// <hr>
/// \section chaiscriptloops Loops
///
/// Common looping constructs exist in ChaiScript
///
/// \code
/// var i = 0;
/// while (i < 10)
/// {
/// // do something
/// ++i;
/// }
/// \endcode
///
/// \code
/// for (var i = 0; i < 10; ++i)
/// {
/// // do something
/// }
/// \endcode
///
/// \sa \ref keywordfor
/// \sa \ref keywordwhile
///
/// <hr>
/// \section chaiscriptifs Conditionals
///
/// If statements work as expected
///
/// \code
/// var b = true;
///
/// if (b) {
/// // do something
/// } else if (c < 10) {
/// // do something else
/// } else {
/// // or do this
/// }
/// \endcode
///
/// \sa \ref keywordif
///
/// <hr>
/// \section chaiscriptfunctions Functions
///
/// Functions are defined with the def keyword
///
/// \code
/// def myfun(x) { print(x); }
///
/// myfun(10);
/// \endcode
///
/// Functions may have "guards" which determine if which is called.
///
/// \code
/// eval> def myfun2(x) : x < 10 { print("less than 10"); }
/// eval> def myfun2(x) : x >= 10 { print("10 or greater"); }
/// eval> myfun2(5)
/// less than 10
/// eval> myfun2(12)
/// 10 or greater
/// \endcode
///
/// \sa \ref keyworddef
/// \sa \ref keywordattr
/// \sa \ref LangObjectSystemRef
///
/// <hr>
/// \section chaiscriptfunctionobjects Function Objects
///
/// Functions are first class types in ChaiScript and can be used as variables.
///
/// \code
/// eval> var p = print;
/// eval> p(1);
/// 1
/// \endcode
///
/// They can also be passed to functions.
///
/// \code
/// eval> def callfunc(f, lhs, rhs) { return f(lhs, rhs); }
/// eval> def dosomething(lhs, rhs) { print("lhs: ${lhs}, rhs: ${rhs}"); }
/// eval> callfunc(dosomething, 1, 2);
/// lhs: 1, rhs: 2
/// \endcode
///
/// Operators can also be treated as functions by using the back tick operator. Building on the above example:
///
/// \code
/// eval> callfunc(`+`, 1, 4);
/// 5
/// eval> callfunc(`*`, 3, 2);
/// 6
/// \endcode
///
/// <hr>
/// \sa \ref LangKeywordRef
/// \sa ChaiScript_Language for Built in Functions
/// \page LangKeywordRef ChaiScript Language Keyword Reference /// \page LangKeywordRef ChaiScript Language Keyword Reference
/// ///
/// ///
@@ -563,7 +751,7 @@
#include "dispatchkit/bootstrap_stl.hpp" #include "dispatchkit/bootstrap_stl.hpp"
#include "dispatchkit/function_call.hpp" #include "dispatchkit/function_call.hpp"
#include "dispatchkit/dynamic_object.hpp" #include "dispatchkit/dynamic_object.hpp"
#include "dispatchkit/boxed_pod_value.hpp" #include "dispatchkit/boxed_number.hpp"
#ifdef BOOST_HAS_DECLSPEC #ifdef BOOST_HAS_DECLSPEC
#define CHAISCRIPT_MODULE_EXPORT extern "C" __declspec(dllexport) #define CHAISCRIPT_MODULE_EXPORT extern "C" __declspec(dllexport)

View File

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

View File

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

View File

@@ -1,6 +1,6 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2011, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// and Jason Turner (jason@emptycrate.com) // and Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
@@ -89,5 +89,6 @@ namespace chaiscript
#undef n #undef n
#undef m #undef m
#undef param
#endif #endif

View File

@@ -1,6 +1,6 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2011, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// and Jason Turner (jason@emptycrate.com) // and Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
@@ -11,8 +11,9 @@
#include "dynamic_object.hpp" #include "dynamic_object.hpp"
#include "register_function.hpp" #include "register_function.hpp"
#include "operators.hpp" #include "operators.hpp"
#include "boxed_pod_value.hpp" #include "boxed_number.hpp"
#include <boost/function_types/result_type.hpp> #include <boost/function_types/result_type.hpp>
#include <sstream>
namespace chaiscript namespace chaiscript
{ {
@@ -21,189 +22,30 @@ namespace chaiscript
{ {
namespace detail namespace detail
{ {
/// \brief Constructs a new POD value object from a Boxed_Number
/// \brief Assigns a POD value from a Boxed_POD_Value. Helps support operators between /// \param[in] v Boxed_Number to copy into the new object
/// disparate POD types.
/// \param[in,out] p1 object to assign to
/// \param[in] v Boxed_POD_Value to assign from
/// \returns Reference to p1, to support normal C assignment semantics
template<typename P1>
P1 &assign_pod(P1 &p1, const Boxed_POD_Value &v)
{
if (v.isfloat)
{
return (p1 = P1(v.d));
} else {
return (p1 = P1(v.i));
}
}
/// \brief Constructs a new POD value object from a Boxed_POD_Value
/// \param[in] v Boxed_POD_Value to copy into the new object
/// \returns The newly created object. /// \returns The newly created object.
template<typename P1> template<typename P1>
P1 construct_pod(Boxed_POD_Value v) boost::shared_ptr<P1> construct_pod(Boxed_Number v)
{ {
if (v.isfloat) boost::shared_ptr<P1> p(new P1());
{ Boxed_Value bv(p);
return P1(v.d); Boxed_Number nb(bv);
} else { nb = v;
return P1(v.i); return p;
}
}
/// \brief Performs a bitwise and assignment (&=) on the given object with the given Boxed_POD_Value
/// \param[in,out] p1 object to bitwise and assign to
/// \param[in] r Boxed_POD_Value to assign from
/// \returns Reference to p1, to support normal C assignment semantics
template<typename P1>
P1 &assign_bitwise_and_pod(P1 &p1, Boxed_POD_Value r)
{
if (!r.isfloat)
{
return p1 &= P1(r.i);
}
throw exception::bad_boxed_cast("&= only valid for integer types");
}
/// \brief Performs a xor assignment (^=) on the given object with the given Boxed_POD_Value
/// \param[in,out] p1 object to xor assign to
/// \param[in] r Boxed_POD_Value to assign from
/// \returns Reference to p1, to support normal C assignment semantics
template<typename P1>
P1 &assign_xor_pod(P1 &p1, Boxed_POD_Value r)
{
if (!r.isfloat)
{
return p1 ^= P1(r.i);
}
throw exception::bad_boxed_cast("^= only valid for integer types");
}
/// \brief Performs a bitwise or assignment (|=) on the given object with the given Boxed_POD_Value
/// \param[in,out] p1 object to bitwise or assign to
/// \param[in] r Boxed_POD_Value to assign from
/// \returns Reference to p1, to support normal C assignment semantics
template<typename P1>
P1 &assign_bitwise_or_pod(P1 &p1, Boxed_POD_Value r)
{
if (!r.isfloat)
{
return p1 |= P1(r.i);
}
throw exception::bad_boxed_cast("&= only valid for integer types");
}
/// \brief Performs an assign difference (-=) on the given object with the given Boxed_POD_Value
/// \param[in,out] p1 object to difference assign to
/// \param[in] r Boxed_POD_Value to assign from
/// \returns Reference to p1, to support normal C assignment semantics
template<typename P1>
P1 &assign_difference_pod(P1 &p1, Boxed_POD_Value r)
{
if (r.isfloat)
{
return p1 -= P1(r.d);
} else {
return p1 -= P1(r.i);
}
}
/// \brief Performs an assign shift left (<<=) on the given object with the given Boxed_POD_Value
/// \param[in,out] p1 object to assign shift left to
/// \param[in] r Boxed_POD_Value to assign from
/// \returns Reference to p1, to support normal C assignment semantics
template<typename P1>
P1 &assign_left_shift_pod(P1 &p1, Boxed_POD_Value r)
{
if (!r.isfloat)
{
return p1 <<= P1(r.i);
}
throw exception::bad_boxed_cast("<<= only valid for integer types");
}
/// \brief Performs an assign product (*=) on the given object with the given Boxed_POD_Value
/// \param[in,out] p1 object to assign product to
/// \param[in] r Boxed_POD_Value to assign from
/// \returns Reference to p1, to support normal C assignment semantics
template<typename P1>
P1 &assign_product_pod(P1 &p1, Boxed_POD_Value r)
{
if (r.isfloat)
{
return p1 *= P1(r.d);
} else {
return p1 *= P1(r.i);
}
}
/// \brief Performs an assign quotient (/=) on the given object with the given Boxed_POD_Value
/// \param[in,out] p1 object to assign quotient to
/// \param[in] r Boxed_POD_Value to assign from
/// \returns Reference to p1, to support normal C assignment semantics
template<typename P1>
P1 &assign_quotient_pod(P1 &p1, Boxed_POD_Value r)
{
if (r.isfloat)
{
return p1 /= P1(r.d);
} else {
return p1 /= P1(r.i);
}
}
/// \brief Performs an assign remainder (%=) on the given object with the given Boxed_POD_Value
/// \param[in,out] p1 object to assign remainder to
/// \param[in] r Boxed_POD_Value to assign from
/// \returns Reference to p1, to support normal C assignment semantics
template<typename P1>
P1 &assign_remainder_pod(P1 &p1, Boxed_POD_Value r)
{
if (!r.isfloat)
{
return p1 %= P1(r.i);
}
throw exception::bad_boxed_cast("%= only valid for integer types");
}
/// \brief Performs an assign shift right (>>=) on the given object with the given Boxed_POD_Value
/// \param[in,out] p1 object to assign shift right to
/// \param[in] r Boxed_POD_Value to assign from
/// \returns Reference to p1, to support normal C assignment semantics
template<typename P1>
P1 &assign_right_shift_pod(P1 &p1, Boxed_POD_Value r)
{
if (!r.isfloat)
{
return p1 >>= P1(r.i);
}
throw exception::bad_boxed_cast(">>= only valid for integer types");
}
/// \brief Performs an assign sum (+=) on the given object with the given Boxed_POD_Value
/// \param[in,out] p1 object to sum assign to
/// \param[in] r Boxed_POD_Value to assign from
/// \returns Reference to p1, to support normal C assignment semantics
template<typename P1>
P1 &assign_sum_pod(P1 &p1, Boxed_POD_Value r)
{
if (r.isfloat)
{
return p1 += P1(r.d);
} else {
return p1 += P1(r.i);
}
} }
}
/// \brief Adds a copy constructor for the given type to the given Model
/// \param[in] type The name of the type. The copy constructor will be named "type".
/// \param[in,out] m The Module to add the copy constructor to
/// \tparam T The type to add a copy constructor for
/// \returns The passed in ModulePtr, or the newly constructed one if the default param is used
template<typename T>
ModulePtr copy_constructor(const std::string &type, ModulePtr m = ModulePtr(new Module()))
{
m->add(constructor<T (const T &)>(), type);
return m;
} }
/// \brief Add all comparison operators for the templated type. Used during bootstrap, also available to users. /// \brief Add all comparison operators for the templated type. Used during bootstrap, also available to users.
@@ -223,76 +65,6 @@ namespace chaiscript
} }
/// \brief Add all arithmetic operators appropriate for integers for the templated type.
/// Used during bootstrap, also available to users.
/// \tparam T Type to create arithmetic operators for
/// \param[in,out] m module to add arithmetic operators to
/// \returns the passed in ModulePtr or the newly constructed one if the default params are used.
template<typename T>
ModulePtr opers_integer_arithmetic(ModulePtr m = ModulePtr(new Module()))
{
operators::assign_bitwise_and<T>(m);
operators::assign_xor<T>(m);
operators::assign_bitwise_or<T>(m);
operators::assign_difference<T>(m);
operators::assign_left_shift<T>(m);
operators::assign_product<T>(m);
operators::assign_quotient<T>(m);
operators::assign_remainder<T>(m);
operators::assign_right_shift<T>(m);
operators::assign_sum<T>(m);
operators::prefix_decrement<T>(m);
operators::prefix_increment<T>(m);
operators::addition<T>(m);
operators::unary_plus<T>(m);
operators::subtraction<T>(m);
operators::unary_minus<T>(m);
operators::bitwise_and<T>(m);
operators::bitwise_compliment<T>(m);
operators::bitwise_xor<T>(m);
operators::bitwise_or<T>(m);
operators::division<T>(m);
operators::left_shift<T>(m);
operators::multiplication<T>(m);
operators::remainder<T>(m);
operators::right_shift<T>(m);
return m;
}
/// \brief Add all arithmetic operators appropriate for floating point numbers for the templated type.
/// Used during bootstrap, also available to users.
/// \tparam T Type to create arithmetic operators for
/// \param[in,out] m module to add arithmetic operators to
/// \returns the passed in ModulePtr or the newly constructed one if the default params are used.
template<typename T>
ModulePtr opers_float_arithmetic(ModulePtr m = ModulePtr(new Module()))
{
operators::assign_difference<T>(m);
operators::assign_product<T>(m);
operators::assign_quotient<T>(m);
operators::assign_sum<T>(m);
operators::addition<T>(m);
operators::unary_plus<T>(m);
operators::subtraction<T>(m);
operators::unary_minus<T>(m);
operators::division<T>(m);
operators::multiplication<T>(m);
return m;
}
/// \brief Adds a copy constructor for the given type to the given Model
/// \param[in] type The name of the type. The copy constructor will be named "type".
/// \param[in,out] m The Module to add the copy constructor to
/// \tparam T The type to add a copy constructor for
/// \returns The passed in ModulePtr, or the newly constructed one if the default param is used
template<typename T>
ModulePtr copy_constructor(const std::string &type, ModulePtr m = ModulePtr(new Module()))
{
m->add(constructor<T (const T &)>(), type);
return m;
}
/// \brief Adds default and copy constructors for the given type /// \brief Adds default and copy constructors for the given type
/// \param[in] type The name of the type to add the constructors for. /// \param[in] type The name of the type to add the constructors for.
@@ -322,36 +94,34 @@ 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);
}
/**
* 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);
}
/**
* Add assignment operator for T = POD.
*/ */
template<typename T> template<typename Input>
ModulePtr oper_assign_pod(ModulePtr m = ModulePtr(new Module())) std::string to_string(Input i)
{ {
m->add(fun(&detail::assign_pod<T>), "="); std::stringstream ss;
return m; ss << i;
return ss.str();
} }
/**
* 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)
{
std::stringstream ss(i);
Input t;
ss >> t;
return t;
}
/** /**
* Add all common functions for a POD type. All operators, and * Add all common functions for a POD type. All operators, and
* common conversions * common conversions
@@ -360,52 +130,14 @@ namespace chaiscript
ModulePtr bootstrap_pod_type(const std::string &name, ModulePtr m = ModulePtr(new Module())) ModulePtr bootstrap_pod_type(const std::string &name, ModulePtr m = ModulePtr(new Module()))
{ {
m->add(user_type<T>(), name); m->add(user_type<T>(), name);
basic_constructors<T>(name, m); m->add(constructor<T ()>(), name);
operators::assign<T>(m);
oper_assign_pod<T>(m);
construct_pod<T>(name, m); construct_pod<T>(name, m);
m->add(fun(&detail::assign_sum_pod<T>), "+=");
m->add(fun(&detail::assign_difference_pod<T>), "-=");
m->add(fun(&detail::assign_product_pod<T>), "*=");
m->add(fun(&detail::assign_quotient_pod<T>), "/=");
m->add(fun(&to_string<T>), "to_string"); m->add(fun(&to_string<T>), "to_string");
m->add(fun(&parse_string<T>), "to_" + name); m->add(fun(&parse_string<T>), "to_" + name);
return m; return m;
} }
/**
* Add all common functions for a POD type. All operators, and
* common conversions
*/
template<typename T>
ModulePtr bootstrap_integer_type(const std::string &name, ModulePtr m = ModulePtr(new Module()))
{
bootstrap_pod_type<T>(name, m);
m->add(fun(&detail::assign_bitwise_and_pod<T>), "&=");
m->add(fun(&detail::assign_xor_pod<T>), "^=");
m->add(fun(&detail::assign_bitwise_or_pod<T>), "|=");
m->add(fun(&detail::assign_left_shift_pod<T>), "<<=");
m->add(fun(&detail::assign_remainder_pod<T>), "%=");
m->add(fun(&detail::assign_right_shift_pod<T>), ">>=");
opers_integer_arithmetic<T>(m);
return m;
}
/**
* Add all common functions for a POD type. All operators, and
* common conversions
*/
template<typename T>
ModulePtr bootstrap_float_type(const std::string &name, ModulePtr m = ModulePtr(new Module()))
{
bootstrap_pod_type<T>(name, m);
opers_float_arithmetic<T>(m);
return m;
}
/** /**
* "clone" function for a shared_ptr type. This is used in the case * "clone" function for a shared_ptr type. This is used in the case
@@ -480,22 +212,48 @@ namespace chaiscript
std::cout << s << std::endl; std::cout << s << std::endl;
} }
/** /**
* Add all arithmetic operators for PODs * Add all arithmetic operators for PODs
*/ */
static void opers_arithmetic_pod(ModulePtr m = ModulePtr(new Module())) static void opers_arithmetic_pod(ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun(&operators::addition<Boxed_Value, Boxed_POD_Value, Boxed_POD_Value>), "+"); m->add(fun(&Boxed_Number::equals), "==");
m->add(fun(&operators::subtraction<Boxed_Value, Boxed_POD_Value, Boxed_POD_Value>), "-"); m->add(fun(&Boxed_Number::less_than), "<");
m->add(fun(&operators::bitwise_and<Boxed_Value, Boxed_POD_Value, Boxed_POD_Value>), "&"); m->add(fun(&Boxed_Number::greater_than), ">");
m->add(fun(&operators::bitwise_xor<Boxed_Value, Boxed_POD_Value, Boxed_POD_Value>), "^"); m->add(fun(&Boxed_Number::greater_than_equal), ">=");
m->add(fun(&operators::bitwise_or<Boxed_Value, Boxed_POD_Value, Boxed_POD_Value>), "|"); m->add(fun(&Boxed_Number::less_than_equal), "<=");
m->add(fun(&operators::division<Boxed_Value, Boxed_POD_Value, Boxed_POD_Value>), "/"); m->add(fun(&Boxed_Number::not_equal), "!=");
m->add(fun(&operators::left_shift<Boxed_Value, Boxed_POD_Value, Boxed_POD_Value>), "<<");
m->add(fun(&operators::multiplication<Boxed_Value, Boxed_POD_Value, Boxed_POD_Value>), "*"); m->add(fun(&Boxed_Number::pre_decrement), "--");
m->add(fun(&operators::remainder<Boxed_Value, Boxed_POD_Value, Boxed_POD_Value>), "%"); m->add(fun(&Boxed_Number::pre_increment), "++");
m->add(fun(&operators::right_shift<Boxed_Value, Boxed_POD_Value, Boxed_POD_Value>), ">>"); m->add(fun(&Boxed_Number::sum), "+");
} m->add(fun(&Boxed_Number::unary_plus), "+");
m->add(fun(&Boxed_Number::unary_minus), "-");
m->add(fun(&Boxed_Number::difference), "-");
m->add(fun(&Boxed_Number::assign_bitwise_and), "&=");
m->add(fun(&Boxed_Number::assign), "=");
m->add(fun(&Boxed_Number::assign_bitwise_or), "|=");
m->add(fun(&Boxed_Number::assign_bitwise_xor), "^=");
m->add(fun(&Boxed_Number::assign_remainder), "%=");
m->add(fun(&Boxed_Number::assign_shift_left), "<<=");
m->add(fun(&Boxed_Number::assign_shift_right), ">>=");
m->add(fun(&Boxed_Number::bitwise_and), "&");
m->add(fun(&Boxed_Number::bitwise_complement), "~");
m->add(fun(&Boxed_Number::bitwise_xor), "^");
m->add(fun(&Boxed_Number::bitwise_or), "|");
m->add(fun(&Boxed_Number::assign_product), "*=");
m->add(fun(&Boxed_Number::assign_quotient), "/=");
m->add(fun(&Boxed_Number::assign_sum), "+=");
m->add(fun(&Boxed_Number::assign_difference), "-=");
m->add(fun(&Boxed_Number::quotient), "/");
m->add(fun(&Boxed_Number::shift_left), "<<");
m->add(fun(&Boxed_Number::product), "*");
m->add(fun(&Boxed_Number::remainder), "%");
m->add(fun(&Boxed_Number::shift_right), ">>");
}
/** /**
* Create a bound function object. The first param is the function to bind * Create a bound function object. The first param is the function to bind
@@ -619,7 +377,7 @@ namespace chaiscript
m->add(user_type<void>(), "void"); m->add(user_type<void>(), "void");
m->add(user_type<bool>(), "bool"); m->add(user_type<bool>(), "bool");
m->add(user_type<Boxed_Value>(), "Object"); m->add(user_type<Boxed_Value>(), "Object");
m->add(user_type<Boxed_POD_Value>(), "PODObject"); m->add(user_type<Boxed_Number>(), "Number");
m->add(user_type<Proxy_Function>(), "Function"); m->add(user_type<Proxy_Function>(), "Function");
m->add(user_type<std::exception>(), "exception"); m->add(user_type<std::exception>(), "exception");
@@ -669,16 +427,15 @@ namespace chaiscript
m->add(fun(&Type_Info::is_void), "is_type_void"); 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_undef), "is_type_undef");
m->add(fun(&Type_Info::is_pointer), "is_type_pointer"); 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::name), "cpp_name");
m->add(fun(&Type_Info::bare_name), "cpp_bare_name"); m->add(fun(&Type_Info::bare_name), "cpp_bare_name");
m->add(fun(&Type_Info::bare_equal), "bare_equal"); 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); basic_constructors<bool>("bool", m);
operators::assign<bool>(m); operators::assign<bool>(m);
operators::equal<bool>(m);
m->add(fun(&to_string<const std::string &>), "internal_to_string"); m->add(fun(&to_string<const std::string &>), "internal_to_string");
m->add(fun(&Bootstrap::bool_to_string), "internal_to_string"); m->add(fun(&Bootstrap::bool_to_string), "internal_to_string");
@@ -686,15 +443,26 @@ namespace chaiscript
m->add(fun(&throw_exception), "throw"); m->add(fun(&throw_exception), "throw");
m->add(fun(&what), "what"); m->add(fun(&what), "what");
bootstrap_float_type<double>("double", m); bootstrap_pod_type<double>("double", m);
bootstrap_integer_type<int>("int", m); bootstrap_pod_type<long double>("long_double", m);
bootstrap_integer_type<size_t>("size_t", m); bootstrap_pod_type<float>("float", m);
bootstrap_integer_type<char>("char", m); bootstrap_pod_type<int>("int", m);
bootstrap_integer_type<boost::int64_t>("int64_t", m); bootstrap_pod_type<long>("long", m);
bootstrap_pod_type<unsigned int>("unsigned_int", m);
bootstrap_pod_type<unsigned long>("unsigned_long", m);
bootstrap_pod_type<size_t>("size_t", m);
bootstrap_pod_type<char>("char", m);
bootstrap_pod_type<boost::int8_t>("int8_t", m);
bootstrap_pod_type<boost::int16_t>("int16_t", m);
bootstrap_pod_type<boost::int32_t>("int32_t", m);
bootstrap_pod_type<boost::int64_t>("int64_t", m);
bootstrap_pod_type<boost::uint8_t>("uint8_t", m);
bootstrap_pod_type<boost::uint16_t>("uint16_t", m);
bootstrap_pod_type<boost::uint32_t>("uint32_t", m);
bootstrap_pod_type<boost::uint64_t>("uint64_t", m);
operators::logical_compliment<bool>(m); operators::logical_compliment<bool>(m);
opers_comparison<Boxed_POD_Value>(m);
opers_arithmetic_pod(m); opers_arithmetic_pod(m);

View File

@@ -1,6 +1,6 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2011, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// and Jason Turner (jason@emptycrate.com) // and Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
@@ -147,6 +147,104 @@ namespace chaiscript
}; };
namespace detail { namespace detail {
template<typename T>
int return_int_impl(const boost::function<typename T::size_type (const T *)> &t_func, const T *t_obj)
{
#ifdef BOOST_MSVC
#pragma warning(push)
#pragma warning(disable : 4267)
#endif
return t_func(t_obj);
#ifdef BOOST_MSVC
#pragma warning(pop)
#endif
}
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 * Add Bidir_Range support for the given ContainerType
*/ */
@@ -255,7 +353,9 @@ namespace chaiscript
template<typename ContainerType> template<typename ContainerType>
ModulePtr container_type(const std::string &/*type*/, ModulePtr m = ModulePtr(new Module())) ModulePtr container_type(const std::string &/*type*/, ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun(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(boost::function<int (const ContainerType *)>(boost::mem_fn(&ContainerType::size))), "size");
m->add(fun<bool (ContainerType::*)() const>(&ContainerType::empty), "empty"); m->add(fun<bool (ContainerType::*)() const>(&ContainerType::empty), "empty");
m->add(fun<void (ContainerType::*)()>(&ContainerType::clear), "clear"); m->add(fun<void (ContainerType::*)()>(&ContainerType::clear), "clear");
@@ -390,8 +490,25 @@ namespace chaiscript
template<typename ContainerType> template<typename ContainerType>
ModulePtr unique_associative_container_type(const std::string &/*type*/, ModulePtr m = ModulePtr(new Module())) 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; return m;
} }
@@ -512,15 +629,20 @@ namespace chaiscript
m->add(fun(&String::push_back), push_back_name); 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 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; 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"); typedef String (String::*substr_ptr)(typename String::size_type, typename String::size_type) const;
m->add(fun(find_func(boost::mem_fn(static_cast<find_func_ptr>(&String::rfind)))), "rfind"); typedef boost::function<String (const String *, int, int)> substr_func;
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(detail::return_int(static_cast<find_func_ptr>(&String::find)))), "find");
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(detail::return_int(static_cast<find_func_ptr>(&String::rfind)))), "rfind");
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(find_func(detail::return_int(static_cast<find_func_ptr>(&String::find_first_of)))), "find_first_of");
m->add(fun(find_func(detail::return_int(static_cast<find_func_ptr>(&String::find_last_of)))), "find_last_of");
m->add(fun(find_func(detail::return_int(static_cast<find_func_ptr>(&String::find_first_not_of)))), "find_first_not_of");
m->add(fun(find_func(detail::return_int(static_cast<find_func_ptr>(&String::find_last_not_of)))), "find_last_not_of");
m->add(fun(&detail::substr_helper<String, static_cast<substr_ptr>(&String::substr)>), "substr");
m->add(fun(&String::c_str), "c_str"); m->add(fun(&String::c_str), "c_str");
m->add(fun(&String::data), "data"); m->add(fun(&String::data), "data");

View File

@@ -1,11 +1,11 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2011, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// and Jason Turner (jason@emptycrate.com) // and Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
#ifndef __boxed_cast_hpp__ #ifndef CHAISCRIPT_BOXED_CAST_HPP_
#define __boxed_cast_hpp__ #define CHAISCRIPT_BOXED_CAST_HPP_
#include "type_info.hpp" #include "type_info.hpp"
#include "boxed_value.hpp" #include "boxed_value.hpp"

View File

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

View File

@@ -0,0 +1,815 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// and Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_BOXED_NUMERIC_HPP_
#define CHAISCRIPT_BOXED_NUMERIC_HPP_
#include "boxed_value.hpp"
#include "../language/chaiscript_algebraic.hpp"
#include <boost/cstdint.hpp>
namespace chaiscript
{
#ifdef BOOST_MSVC
#pragma warning(push)
#pragma warning(disable : 4244 4018 4389 4146)
#endif
/// \brief Represents any numeric type, generically. Used internally for generic operations between POD values
class Boxed_Number
{
private:
struct boolean
{
#ifdef __GNUC__
#pragma GCC diagnostic ignored "-Wsign-compare"
#endif
template<typename T, typename U>
static Boxed_Value go(Operators::Opers t_oper, const T &t, const U &u, const Boxed_Value &)
{
switch (t_oper)
{
case Operators::equals:
return const_var(t == u);
case Operators::less_than:
return const_var(t < u);
case Operators::greater_than:
return const_var(t > u);
case Operators::less_than_equal:
return const_var(t <= u);
case Operators::greater_than_equal:
return const_var(t >= u);
case Operators::not_equal:
return const_var(t != u);
default:
throw boost::bad_any_cast();
}
}
};
struct binary
{
template<typename T, typename U>
static Boxed_Value go(Operators::Opers t_oper, T &t, const U &u, const Boxed_Value &t_lhs)
{
switch (t_oper)
{
case Operators::assign:
t = u;
break;
case Operators::pre_increment:
++t;
break;
case Operators::pre_decrement:
--t;
break;
case Operators::assign_product:
t *= u;
break;
case Operators::assign_sum:
t += u;
break;
case Operators::assign_quotient:
t /= u;
break;
case Operators::assign_difference:
t -= u;
break;
default:
throw boost::bad_any_cast();
}
return t_lhs;
}
};
struct binary_int
{
template<typename T, typename U>
static Boxed_Value go(Operators::Opers t_oper, T &t, const U &u, const Boxed_Value &t_lhs)
{
switch (t_oper)
{
case Operators::assign_bitwise_and:
t &= u;
break;
case Operators::assign_bitwise_or:
t |= u;
break;
case Operators::assign_shift_left:
t <<= u;
break;
case Operators::assign_shift_right:
t >>= u;
break;
case Operators::assign_remainder:
t %= u;
break;
case Operators::assign_bitwise_xor:
t ^= u;
break;
default:
throw boost::bad_any_cast();
}
return t_lhs;
}
};
struct const_binary_int
{
template<typename T, typename U>
static Boxed_Value go(Operators::Opers t_oper, const T &t, const U &u, const Boxed_Value &)
{
switch (t_oper)
{
case Operators::shift_left:
return const_var(t << u);
case Operators::shift_right:
return const_var(t >> u);
case Operators::remainder:
return const_var(t % u);
case Operators::bitwise_and:
return const_var(t & u);
case Operators::bitwise_or:
return const_var(t | u);
case Operators::bitwise_xor:
return const_var(t ^ u);
case Operators::bitwise_complement:
return const_var(~t);
default:
throw boost::bad_any_cast();
}
}
};
struct const_binary
{
template<typename T, typename U>
static Boxed_Value go(Operators::Opers t_oper, const T &t, const U &u, const Boxed_Value &)
{
switch (t_oper)
{
case Operators::sum:
return const_var(t + u);
case Operators::quotient:
return const_var(t / u);
case Operators::product:
return const_var(t * u);
case Operators::difference:
return const_var(t - u);
case Operators::unary_minus:
return const_var(-t);
case Operators::unary_plus:
return const_var(+t);
default:
throw boost::bad_any_cast();
}
}
};
template<typename LHS, typename RHS, bool Float>
struct Go
{
static Boxed_Value go(Operators::Opers t_oper, const Boxed_Value &t_lhs, const Boxed_Value &t_rhs)
{
if (t_oper > Operators::boolean_flag && t_oper < Operators::non_const_flag)
{
return boolean::go<LHS, RHS>(t_oper, *static_cast<const LHS *>(t_lhs.get_const_ptr()), *static_cast<const RHS *>(t_rhs.get_const_ptr()), t_lhs);
} else if (t_oper > Operators::non_const_flag && t_oper < Operators::non_const_int_flag && !t_lhs.is_const()) {
return binary::go<LHS, RHS>(t_oper, *static_cast<LHS *>(t_lhs.get_ptr()), *static_cast<const RHS *>(t_rhs.get_const_ptr()), t_lhs);
} else if (t_oper > Operators::non_const_int_flag && t_oper < Operators::const_int_flag && !t_lhs.is_const()) {
return binary_int::go<LHS, RHS>(t_oper, *static_cast<LHS *>(t_lhs.get_ptr()), *static_cast<const RHS *>(t_rhs.get_const_ptr()), t_lhs);
} else if (t_oper > Operators::const_int_flag && t_oper < Operators::const_flag) {
return const_binary_int::go<LHS, RHS>(t_oper, *static_cast<const LHS *>(t_lhs.get_const_ptr()), *static_cast<const RHS *>(t_rhs.get_const_ptr()), t_lhs);
} else if (t_oper > Operators::const_flag) {
return const_binary::go<LHS, RHS>(t_oper, *static_cast<const LHS *>(t_lhs.get_const_ptr()), *static_cast<const RHS *>(t_rhs.get_const_ptr()), t_lhs);
} else {
throw boost::bad_any_cast();
}
}
};
template<typename LHS, typename RHS>
struct Go<LHS, RHS, true>
{
static Boxed_Value go(Operators::Opers t_oper, const Boxed_Value &t_lhs, const Boxed_Value &t_rhs)
{
if (t_oper > Operators::boolean_flag && t_oper < Operators::non_const_flag)
{
return boolean::go<LHS, RHS>(t_oper, *static_cast<const LHS *>(t_lhs.get_const_ptr()), *static_cast<const RHS *>(t_rhs.get_const_ptr()), t_lhs);
} else if (t_oper > Operators::non_const_flag && t_oper < Operators::non_const_int_flag && !t_lhs.is_const()) {
return binary::go<LHS, RHS>(t_oper, *static_cast<LHS *>(t_lhs.get_ptr()), *static_cast<const RHS *>(t_rhs.get_const_ptr()), t_lhs);
} else if (t_oper > Operators::non_const_int_flag && t_oper < Operators::const_int_flag) {
throw boost::bad_any_cast();
} else if (t_oper > Operators::const_int_flag && t_oper < Operators::const_flag) {
throw boost::bad_any_cast();
} else if (t_oper > Operators::const_flag) {
return const_binary::go<LHS, RHS>(t_oper, *static_cast<const LHS *>(t_lhs.get_const_ptr()), *static_cast<const RHS *>(t_rhs.get_const_ptr()), t_lhs);
} else {
throw boost::bad_any_cast();
}
}
};
template<typename LHS, bool Float>
static Boxed_Value oper_rhs(Operators::Opers t_oper, const Boxed_Value &t_lhs, const Boxed_Value &t_rhs)
{
const Type_Info &inp_ = t_rhs.get_type_info();
if (inp_ == typeid(int)) {
return Go<LHS, int, Float>::go(t_oper, t_lhs, t_rhs);
} else if (inp_ == typeid(double)) {
return Go<LHS, double, true>::go(t_oper, t_lhs, t_rhs);
} else if (inp_ == typeid(float)) {
return Go<LHS, float, true>::go(t_oper, t_lhs, t_rhs);
} else if (inp_ == typeid(long double)) {
return Go<LHS, long double, true>::go(t_oper, t_lhs, t_rhs);
} else if (inp_ == typeid(char)) {
return Go<LHS, char, Float>::go(t_oper, t_lhs, t_rhs);
} else if (inp_ == typeid(unsigned int)) {
return Go<LHS, unsigned int, Float>::go(t_oper, t_lhs, t_rhs);
} else if (inp_ == typeid(long)) {
return Go<LHS, long, Float>::go(t_oper, t_lhs, t_rhs);
} else if (inp_ == typeid(unsigned long)) {
return Go<LHS, unsigned long, Float>::go(t_oper, t_lhs, t_rhs);
} else if (inp_ == typeid(boost::int8_t)) {
return Go<LHS, boost::int8_t, Float>::go(t_oper, t_lhs, t_rhs);
} else if (inp_ == typeid(boost::int16_t)) {
return Go<LHS, boost::int16_t, Float>::go(t_oper, t_lhs, t_rhs);
} else if (inp_ == typeid(boost::int32_t)) {
return Go<LHS, boost::int32_t, Float>::go(t_oper, t_lhs, t_rhs);
} else if (inp_ == typeid(boost::int64_t)) {
return Go<LHS, boost::int64_t, Float>::go(t_oper, t_lhs, t_rhs);
} else if (inp_ == typeid(boost::uint8_t)) {
return Go<LHS, boost::uint8_t, Float>::go(t_oper, t_lhs, t_rhs);
} else if (inp_ == typeid(boost::uint16_t)) {
return Go<LHS, boost::uint16_t, Float>::go(t_oper, t_lhs, t_rhs);
} else if (inp_ == typeid(boost::uint32_t)) {
return Go<LHS, boost::uint32_t, Float>::go(t_oper, t_lhs, t_rhs);
} else if (inp_ == typeid(boost::uint64_t)) {
return Go<LHS, boost::uint64_t, Float>::go(t_oper, t_lhs, t_rhs);
} else {
throw boost::bad_any_cast();
}
}
static Boxed_Value oper(Operators::Opers t_oper, const Boxed_Value &t_lhs, const Boxed_Value &t_rhs)
{
const Type_Info &inp_ = t_lhs.get_type_info();
if (inp_ == typeid(int)) {
return oper_rhs<int, false>(t_oper, t_lhs, t_rhs);
} else if (inp_ == typeid(double)) {
return oper_rhs<double, true>(t_oper, t_lhs, t_rhs);
} else if (inp_ == typeid(long double)) {
return oper_rhs<long double, true>(t_oper, t_lhs, t_rhs);
} else if (inp_ == typeid(float)) {
return oper_rhs<float, true>(t_oper, t_lhs, t_rhs);
} else if (inp_ == typeid(char)) {
return oper_rhs<char, false>(t_oper, t_lhs, t_rhs);
} else if (inp_ == typeid(unsigned int)) {
return oper_rhs<unsigned int, false>(t_oper, t_lhs, t_rhs);
} else if (inp_ == typeid(long)) {
return oper_rhs<long, false>(t_oper, t_lhs, t_rhs);
} else if (inp_ == typeid(unsigned long)) {
return oper_rhs<unsigned long, false>(t_oper, t_lhs, t_rhs);
} else if (inp_ == typeid(boost::int8_t)) {
return oper_rhs<boost::int8_t, false>(t_oper, t_lhs, t_rhs);
} else if (inp_ == typeid(boost::int16_t)) {
return oper_rhs<boost::int16_t, false>(t_oper, t_lhs, t_rhs);
} else if (inp_ == typeid(boost::int32_t)) {
return oper_rhs<boost::int32_t, false>(t_oper, t_lhs, t_rhs);
} else if (inp_ == typeid(boost::int64_t)) {
return oper_rhs<boost::int64_t, false>(t_oper, t_lhs, t_rhs);
} else if (inp_ == typeid(boost::uint8_t)) {
return oper_rhs<boost::uint8_t, false>(t_oper, t_lhs, t_rhs);
} else if (inp_ == typeid(boost::uint16_t)) {
return oper_rhs<boost::uint16_t, false>(t_oper, t_lhs, t_rhs);
} else if (inp_ == typeid(boost::uint32_t)) {
return oper_rhs<boost::uint32_t, false>(t_oper, t_lhs, t_rhs);
} else if (inp_ == typeid(boost::uint64_t)) {
return oper_rhs<boost::uint64_t, false>(t_oper, t_lhs, t_rhs);
} else {
throw boost::bad_any_cast();
}
}
template<typename Target, typename Source>
Target get_as_aux() const
{
return static_cast<Target>(*static_cast<const Source *>(bv.get_const_ptr()));
}
template<typename Source>
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)
{
validate_boxed_number(v);
}
template<typename T> explicit Boxed_Number(T t)
: bv(Boxed_Value(t))
{
validate_boxed_number(bv);
}
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
{
return boxed_cast<bool>(oper(Operators::equals, this->bv, t_rhs.bv));
}
bool operator<(const Boxed_Number &t_rhs) const
{
return boxed_cast<bool>(oper(Operators::less_than, this->bv, t_rhs.bv));
}
bool operator>(const Boxed_Number &t_rhs) const
{
return boxed_cast<bool>(oper(Operators::greater_than, this->bv, t_rhs.bv));
}
bool operator>=(const Boxed_Number &t_rhs) const
{
return boxed_cast<bool>(oper(Operators::greater_than_equal, this->bv, t_rhs.bv));
}
bool operator<=(const Boxed_Number &t_rhs) const
{
return boxed_cast<bool>(oper(Operators::less_than_equal, this->bv, t_rhs.bv));
}
bool operator!=(const Boxed_Number &t_rhs) const
{
return boxed_cast<bool>(oper(Operators::not_equal, this->bv, t_rhs.bv));
}
Boxed_Number operator--()
{
return oper(Operators::pre_decrement, this->bv, var(0));
}
Boxed_Number operator++()
{
return oper(Operators::pre_increment, this->bv, var(0));
}
Boxed_Number operator+(const Boxed_Number &t_rhs) const
{
return oper(Operators::sum, this->bv, t_rhs.bv);
}
Boxed_Number operator+() const
{
return oper(Operators::unary_plus, this->bv, Boxed_Value(0));
}
Boxed_Number operator-() const
{
return oper(Operators::unary_minus, this->bv, Boxed_Value(0));
}
Boxed_Number operator-(const Boxed_Number &t_rhs) const
{
return oper(Operators::difference, this->bv, t_rhs.bv);
}
Boxed_Number operator&=(const Boxed_Number &t_rhs)
{
return oper(Operators::assign_bitwise_and, this->bv, t_rhs.bv);
}
void validate_boxed_number(const Boxed_Value &v)
{
const Type_Info &inp_ = v.get_type_info();
if (inp_ == typeid(bool))
{
throw 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);
}
Boxed_Number operator|=(const Boxed_Number &t_rhs)
{
return oper(Operators::assign_bitwise_or, this->bv, t_rhs.bv);
}
Boxed_Number operator^=(const Boxed_Number &t_rhs)
{
return oper(Operators::assign_bitwise_xor, this->bv, t_rhs.bv);
}
Boxed_Number operator%=(const Boxed_Number &t_rhs)
{
return oper(Operators::assign_remainder, this->bv, t_rhs.bv);
}
Boxed_Number operator<<=(const Boxed_Number &t_rhs)
{
return oper(Operators::assign_shift_left, this->bv, t_rhs.bv);
}
Boxed_Number operator>>=(const Boxed_Number &t_rhs)
{
return oper(Operators::assign_shift_right, this->bv, t_rhs.bv);
}
Boxed_Number operator&(const Boxed_Number &t_rhs) const
{
return oper(Operators::bitwise_and, this->bv, t_rhs.bv);
}
Boxed_Number operator~() const
{
return oper(Operators::bitwise_complement, this->bv, Boxed_Value(0));
}
Boxed_Number operator^(const Boxed_Number &t_rhs) const
{
return oper(Operators::bitwise_xor, this->bv, t_rhs.bv);
}
Boxed_Number operator|(const Boxed_Number &t_rhs) const
{
return oper(Operators::bitwise_or, this->bv, t_rhs.bv);
}
Boxed_Number operator*=(const Boxed_Number &t_rhs)
{
return oper(Operators::assign_product, this->bv, t_rhs.bv);
}
Boxed_Number operator/=(const Boxed_Number &t_rhs)
{
return oper(Operators::assign_quotient, this->bv, t_rhs.bv);
}
Boxed_Number operator+=(const Boxed_Number &t_rhs)
{
return oper(Operators::assign_sum, this->bv, t_rhs.bv);
}
Boxed_Number operator-=(const Boxed_Number &t_rhs)
{
return oper(Operators::assign_difference, this->bv, t_rhs.bv);
}
Boxed_Number operator/(const Boxed_Number &t_rhs) const
{
return oper(Operators::quotient, this->bv, t_rhs.bv);
}
Boxed_Number operator<<(const Boxed_Number &t_rhs) const
{
return oper(Operators::shift_left, this->bv, t_rhs.bv);
}
Boxed_Number operator*(const Boxed_Number &t_rhs) const
{
return oper(Operators::product, this->bv, t_rhs.bv);
}
Boxed_Number operator%(const Boxed_Number &t_rhs) const
{
return oper(Operators::remainder, this->bv, t_rhs.bv);
}
Boxed_Number operator>>(const Boxed_Number &t_rhs) const
{
return oper(Operators::shift_right, this->bv, t_rhs.bv);
}
static bool equals(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs)
{
return boxed_cast<bool>(oper(Operators::equals, t_lhs.bv, t_rhs.bv));
}
static bool less_than(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs)
{
return boxed_cast<bool>(oper(Operators::less_than, t_lhs.bv, t_rhs.bv));
}
static bool greater_than(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs)
{
return boxed_cast<bool>(oper(Operators::greater_than, t_lhs.bv, t_rhs.bv));
}
static bool greater_than_equal(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs)
{
return boxed_cast<bool>(oper(Operators::greater_than_equal, t_lhs.bv, t_rhs.bv));
}
static bool less_than_equal(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs)
{
return boxed_cast<bool>(oper(Operators::less_than_equal, t_lhs.bv, t_rhs.bv));
}
static bool not_equal(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs)
{
return boxed_cast<bool>(oper(Operators::not_equal, t_lhs.bv, t_rhs.bv));
}
static Boxed_Number pre_decrement(Boxed_Number t_lhs)
{
return oper(Operators::pre_decrement, t_lhs.bv, var(0));
}
static Boxed_Number pre_increment(Boxed_Number t_lhs)
{
return oper(Operators::pre_increment, t_lhs.bv, var(0));
}
static const Boxed_Number sum(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs)
{
return oper(Operators::sum, t_lhs.bv, t_rhs.bv);
}
static const Boxed_Number unary_plus(const Boxed_Number &t_lhs)
{
return oper(Operators::unary_plus, t_lhs.bv, Boxed_Value(0));
}
static const Boxed_Number unary_minus(const Boxed_Number &t_lhs)
{
return oper(Operators::unary_minus, t_lhs.bv, Boxed_Value(0));
}
static const Boxed_Number difference(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs)
{
return oper(Operators::difference, t_lhs.bv, t_rhs.bv);
}
static Boxed_Number assign_bitwise_and(Boxed_Number t_lhs, const Boxed_Number &t_rhs)
{
return oper(Operators::assign_bitwise_and, t_lhs.bv, t_rhs.bv);
}
static Boxed_Number assign(Boxed_Number t_lhs, const Boxed_Number &t_rhs)
{
return oper(Operators::assign, t_lhs.bv, t_rhs.bv);
}
static Boxed_Number assign_bitwise_or(Boxed_Number t_lhs, const Boxed_Number &t_rhs)
{
return oper(Operators::assign_bitwise_or, t_lhs.bv, t_rhs.bv);
}
static Boxed_Number assign_bitwise_xor(Boxed_Number t_lhs, const Boxed_Number &t_rhs)
{
return oper(Operators::assign_bitwise_xor, t_lhs.bv, t_rhs.bv);
}
static Boxed_Number assign_remainder(Boxed_Number t_lhs, const Boxed_Number &t_rhs)
{
return oper(Operators::assign_remainder, t_lhs.bv, t_rhs.bv);
}
static Boxed_Number assign_shift_left(Boxed_Number t_lhs, const Boxed_Number &t_rhs)
{
return oper(Operators::assign_shift_left, t_lhs.bv, t_rhs.bv);
}
static Boxed_Number assign_shift_right(Boxed_Number t_lhs, const Boxed_Number &t_rhs)
{
return oper(Operators::assign_shift_right, t_lhs.bv, t_rhs.bv);
}
static const Boxed_Number bitwise_and(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs)
{
return oper(Operators::bitwise_and, t_lhs.bv, t_rhs.bv);
}
static const Boxed_Number bitwise_complement(const Boxed_Number &t_lhs)
{
return oper(Operators::bitwise_complement, t_lhs.bv, Boxed_Value(0));
}
static const Boxed_Number bitwise_xor(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs)
{
return oper(Operators::bitwise_xor, t_lhs.bv, t_rhs.bv);
}
static const Boxed_Number bitwise_or(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs)
{
return oper(Operators::bitwise_or, t_lhs.bv, t_rhs.bv);
}
static Boxed_Number assign_product(Boxed_Number t_lhs, const Boxed_Number &t_rhs)
{
return oper(Operators::assign_product, t_lhs.bv, t_rhs.bv);
}
static Boxed_Number assign_quotient(Boxed_Number t_lhs, const Boxed_Number &t_rhs)
{
return oper(Operators::assign_quotient, t_lhs.bv, t_rhs.bv);
}
static Boxed_Number assign_sum(Boxed_Number t_lhs, const Boxed_Number &t_rhs)
{
return oper(Operators::assign_sum, t_lhs.bv, t_rhs.bv);
}
static Boxed_Number assign_difference(Boxed_Number t_lhs, const Boxed_Number &t_rhs)
{
return oper(Operators::assign_difference, t_lhs.bv, t_rhs.bv);
}
static const Boxed_Number quotient(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs)
{
return oper(Operators::quotient, t_lhs.bv, t_rhs.bv);
}
static const Boxed_Number shift_left(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs)
{
return oper(Operators::shift_left, t_lhs.bv, t_rhs.bv);
}
static const Boxed_Number product(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs)
{
return oper(Operators::product, t_lhs.bv, t_rhs.bv);
}
static const Boxed_Number remainder(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs)
{
return oper(Operators::remainder, t_lhs.bv, t_rhs.bv);
}
static const Boxed_Number shift_right(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs)
{
return oper(Operators::shift_right, t_lhs.bv, t_rhs.bv);
}
static Boxed_Value do_oper(Operators::Opers t_oper, const Boxed_Value &t_lhs, const Boxed_Value &t_rhs)
{
return oper(t_oper, t_lhs, t_rhs);
}
static Boxed_Value do_oper(Operators::Opers t_oper, const Boxed_Value &t_lhs)
{
return oper(t_oper, t_lhs, const_var(0));
}
Boxed_Value bv;
};
namespace detail
{
/**
* Cast_Helper for converting from Boxed_Value to Boxed_Number
*/
template<>
struct Cast_Helper<Boxed_Number>
{
typedef Boxed_Number Result_Type;
static Result_Type cast(const Boxed_Value &ob)
{
return Boxed_Number(ob);
}
};
/**
* Cast_Helper for converting from Boxed_Value to Boxed_Number
*/
template<>
struct Cast_Helper<const Boxed_Number &> : Cast_Helper<Boxed_Number>
{
};
/**
* Cast_Helper for converting from Boxed_Value to Boxed_Number
*/
template<>
struct Cast_Helper<const Boxed_Number> : Cast_Helper<Boxed_Number>
{
};
}
#ifdef BOOST_MSVC
#pragma warning(pop)
#endif
}
#endif

View File

@@ -1,260 +0,0 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2011, Jonathan Turner (jonathan@emptycrate.com)
// and Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_BOXED_POD_VALUE_HPP_
#define CHAISCRIPT_BOXED_POD_VALUE_HPP_
#include "type_info.hpp"
#include "boxed_value.hpp"
#include "boxed_cast_helper.hpp"
#include <boost/any.hpp>
#include <boost/cstdint.hpp>
#include <boost/integer_traits.hpp>
namespace chaiscript
{
/// \brief Represents any numeric type, generically. Used internally for generic operations between POD values
class Boxed_POD_Value
{
public:
Boxed_POD_Value(const Boxed_Value &v)
: d(0), i(0), isfloat(false)
{
if (v.get_type_info().is_undef())
{
throw boost::bad_any_cast();
}
const Type_Info &inp_ = v.get_type_info();
if (inp_ == typeid(double))
{
d = boxed_cast<double>(v);
isfloat = true;
} else if (inp_ == typeid(float)) {
d = boxed_cast<float>(v);
isfloat = true;
} else if (inp_ == typeid(bool)) {
i = boxed_cast<bool>(v);
} else if (inp_ == typeid(char)) {
i = boxed_cast<char>(v);
} else if (inp_ == typeid(int)) {
i = boxed_cast<int>(v);
} else if (inp_ == typeid(unsigned int)) {
i = boxed_cast<unsigned int>(v);
} else if (inp_ == typeid(long)) {
i = boxed_cast<long>(v);
} else if (inp_ == typeid(unsigned long)) {
i = boxed_cast<unsigned long>(v);
} else if (inp_ == typeid(boost::int8_t)) {
i = boxed_cast<boost::int8_t>(v);
} else if (inp_ == typeid(boost::int16_t)) {
i = boxed_cast<boost::int16_t>(v);
} else if (inp_ == typeid(boost::int32_t)) {
i = boxed_cast<boost::int32_t>(v);
} else if (inp_ == typeid(boost::int64_t)) {
i = boxed_cast<boost::int64_t>(v);
} else if (inp_ == typeid(boost::uint8_t)) {
i = boxed_cast<boost::uint8_t>(v);
} else if (inp_ == typeid(boost::uint16_t)) {
i = boxed_cast<boost::uint16_t>(v);
} else if (inp_ == typeid(boost::uint32_t)) {
i = boxed_cast<boost::uint32_t>(v);
} else {
throw boost::bad_any_cast();
}
}
bool operator==(const Boxed_POD_Value &r) const
{
return ((isfloat)?d:i) == ((r.isfloat)?r.d:r.i);
}
bool operator<(const Boxed_POD_Value &r) const
{
return ((isfloat)?d:i) < ((r.isfloat)?r.d:r.i);
}
bool operator>(const Boxed_POD_Value &r) const
{
return ((isfloat)?d:i) > ((r.isfloat)?r.d:r.i);
}
bool operator>=(const Boxed_POD_Value &r) const
{
return ((isfloat)?d:i) >= ((r.isfloat)?r.d:r.i);
}
bool operator<=(const Boxed_POD_Value &r) const
{
return ((isfloat)?d:i) <= ((r.isfloat)?r.d:r.i);
}
bool operator!=(const Boxed_POD_Value &r) const
{
return ((isfloat)?d:i) != ((r.isfloat)?r.d:r.i);
}
Boxed_Value operator+(const Boxed_POD_Value &r) const
{
if (!isfloat && !r.isfloat)
{
return smart_size(i + r.i);
}
return Boxed_Value(((isfloat)?d:i) + ((r.isfloat)?r.d:r.i));
}
Boxed_Value operator-(const Boxed_POD_Value &r) const
{
if (!isfloat && !r.isfloat)
{
return smart_size(i - r.i);
}
return Boxed_Value(((isfloat)?d:i) - ((r.isfloat)?r.d:r.i));
}
Boxed_Value operator&(const Boxed_POD_Value &r) const
{
if (!isfloat && !r.isfloat)
{
return Boxed_Value(i & r.i);
}
throw exception::bad_boxed_cast("& only valid for integer types");
}
Boxed_Value operator^(const Boxed_POD_Value &r) const
{
if (!isfloat && !r.isfloat)
{
return Boxed_Value(i ^ r.i);
}
throw exception::bad_boxed_cast("^ only valid for integer types");
}
Boxed_Value operator|(const Boxed_POD_Value &r) const
{
if (!isfloat && !r.isfloat)
{
return Boxed_Value(i | r.i);
}
throw exception::bad_boxed_cast("| only valid for integer types");
}
Boxed_Value operator/(const Boxed_POD_Value &r) const
{
if (!isfloat && !r.isfloat)
{
return smart_size(i / r.i);
}
return Boxed_Value(((isfloat)?d:i) / ((r.isfloat)?r.d:r.i));
}
Boxed_Value operator<<(const Boxed_POD_Value &r) const
{
if (!isfloat && !r.isfloat)
{
return smart_size(i << r.i);
}
throw exception::bad_boxed_cast("<< only valid for integer types");
}
Boxed_Value operator*(const Boxed_POD_Value &r) const
{
if (!isfloat && !r.isfloat)
{
return smart_size(i * r.i);
}
return Boxed_Value(((isfloat)?d:i) * ((r.isfloat)?r.d:r.i));
}
Boxed_Value operator%(const Boxed_POD_Value &r) const
{
if (!isfloat && !r.isfloat)
{
return smart_size(i % r.i);
}
throw exception::bad_boxed_cast("% only valid for integer types");
}
Boxed_Value operator>>(const Boxed_POD_Value &r) const
{
if (!isfloat && !r.isfloat)
{
return smart_size(i >> r.i);
}
throw exception::bad_boxed_cast(">> only valid for integer types");
}
Boxed_Value smart_size(boost::int64_t t_i) const
{
if (t_i < boost::integer_traits<int>::const_min
|| t_i > boost::integer_traits<int>::const_max)
{
return Boxed_Value(t_i);
} else {
return Boxed_Value(static_cast<int>(t_i));
}
}
double d;
boost::int64_t i;
bool isfloat;
};
namespace detail
{
/**
* Cast_Helper for converting from Boxed_Value to Boxed_POD_Value
*/
template<>
struct Cast_Helper<Boxed_POD_Value>
{
typedef Boxed_POD_Value Result_Type;
static Result_Type cast(const Boxed_Value &ob)
{
return Boxed_POD_Value(ob);
}
};
/**
* Cast_Helper for converting from Boxed_Value to Boxed_POD_Value
*/
template<>
struct Cast_Helper<const Boxed_POD_Value &> : Cast_Helper<Boxed_POD_Value>
{
};
/**
* Cast_Helper for converting from Boxed_Value to Boxed_POD_Value
*/
template<>
struct Cast_Helper<const Boxed_POD_Value> : Cast_Helper<Boxed_POD_Value>
{
};
}
}
#endif

View File

@@ -1,6 +1,6 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2011, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// and Jason Turner (jason@emptycrate.com) // and Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
@@ -13,6 +13,7 @@
#include <map> #include <map>
#include <boost/shared_ptr.hpp> #include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>
#include <boost/any.hpp> #include <boost/any.hpp>
#include <boost/function.hpp> #include <boost/function.hpp>
#include <boost/ref.hpp> #include <boost/ref.hpp>
@@ -23,6 +24,7 @@
namespace chaiscript namespace chaiscript
{ {
/// \brief A wrapper for holding any valid C++ type. All types in ChaiScript are Boxed_Value objects /// \brief A wrapper for holding any valid C++ type. All types in ChaiScript are Boxed_Value objects
/// \sa chaiscript::boxed_cast /// \sa chaiscript::boxed_cast
class Boxed_Value class Boxed_Value
@@ -41,19 +43,12 @@ namespace chaiscript
*/ */
struct Data struct Data
{ {
template<typename T>
static bool is_null(boost::any *a)
{
boost::shared_ptr<T> *ptr = boost::any_cast<boost::shared_ptr<T> >(a);
return ptr->get() == 0;
}
Data(const Type_Info &ti, Data(const Type_Info &ti,
const boost::any &to, const boost::any &to,
bool tr, bool tr,
const boost::function<bool (boost::any*)> &t_is_null = boost::function<bool (boost::any*)>()) const void *t_void_ptr)
: m_type_info(ti), m_obj(to), : m_type_info(ti), m_obj(to), m_data_ptr(ti.is_const()?0:const_cast<void *>(t_void_ptr)), m_const_data_ptr(t_void_ptr),
m_is_ref(tr), m_is_null(t_is_null) m_is_ref(tr)
{ {
} }
@@ -62,7 +57,8 @@ namespace chaiscript
m_type_info = rhs.m_type_info; m_type_info = rhs.m_type_info;
m_obj = rhs.m_obj; m_obj = rhs.m_obj;
m_is_ref = rhs.m_is_ref; m_is_ref = rhs.m_is_ref;
m_is_null = rhs.m_is_null; m_data_ptr = rhs.m_data_ptr;
m_const_data_ptr = rhs.m_const_data_ptr;
return *this; return *this;
} }
@@ -73,20 +69,20 @@ namespace chaiscript
Type_Info m_type_info; Type_Info m_type_info;
boost::any m_obj; boost::any m_obj;
void *m_data_ptr;
const void *m_const_data_ptr;
bool m_is_ref; bool m_is_ref;
boost::function<bool (boost::any*)> m_is_null;
std::vector<boost::shared_ptr<Data> > m_dependencies;
}; };
struct Object_Data struct Object_Data
{ {
static boost::shared_ptr<Data> get(Boxed_Value::Void_Type) 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(), detail::Get_Type_Info<void>::get(),
boost::any(), boost::any(),
false) false,
); static_cast<void *>(0));
} }
template<typename T> template<typename T>
@@ -98,12 +94,11 @@ namespace chaiscript
template<typename T> template<typename T>
static boost::shared_ptr<Data> get(const boost::shared_ptr<T> &obj) 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(), detail::Get_Type_Info<T>::get(),
boost::any(obj), boost::any(obj),
false, false,
boost::function<bool (boost::any *)>(&Data::is_null<T>)) obj.get());
);
} }
template<typename T> template<typename T>
@@ -115,31 +110,31 @@ namespace chaiscript
template<typename T> template<typename T>
static boost::shared_ptr<Data> get(boost::reference_wrapper<T> obj) 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(), detail::Get_Type_Info<T>::get(),
boost::any(obj), boost::any(obj),
true) true,
); obj.get_pointer());
} }
template<typename T> template<typename T>
static boost::shared_ptr<Data> get(const T& t) static boost::shared_ptr<Data> get(const T& t)
{ {
return boost::shared_ptr<Data>(new Data( boost::shared_ptr<T> p(new T(t));
return boost::make_shared<Data>(
detail::Get_Type_Info<T>::get(), detail::Get_Type_Info<T>::get(),
boost::any(boost::shared_ptr<T>(new T(t))), boost::any(p),
false, false,
boost::function<bool (boost::any *)>(&Data::is_null<T>)) p.get());
);
} }
static boost::shared_ptr<Data> get() static boost::shared_ptr<Data> get()
{ {
return boost::shared_ptr<Data> (new Data( return boost::make_shared<Data>(
Type_Info(), Type_Info(),
boost::any(), boost::any(),
false) false,
); static_cast<void *>(0));
} }
}; };
@@ -224,12 +219,7 @@ namespace chaiscript
bool is_null() const bool is_null() const
{ {
if (m_data->m_is_null) return (m_data->m_data_ptr == 0 && m_data->m_const_data_ptr == 0);
{
return m_data->m_is_null(&m_data->m_obj);
} else {
return false;
}
} }
const boost::any & get() const const boost::any & get() const
@@ -247,24 +237,15 @@ namespace chaiscript
return !is_ref(); return !is_ref();
} }
void clear_dependencies() void *get_ptr() const
{ {
m_data->m_dependencies.clear(); return m_data->m_data_ptr;
} }
template<typename InItr> const void *get_const_ptr() const
void add_dependencies(InItr begin, const InItr &end) {
{ return m_data->m_const_data_ptr;
while (begin != end) }
{
if (begin->m_data != m_data)
{
m_data->m_dependencies.push_back(begin->m_data);
}
++begin;
}
}
private: private:
boost::shared_ptr<Data> m_data; boost::shared_ptr<Data> m_data;

View File

@@ -1,6 +1,6 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2011, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// and Jason Turner (jason@emptycrate.com) // and Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
@@ -12,12 +12,11 @@
#include <map> #include <map>
#include <set> #include <set>
#include <boost/shared_ptr.hpp> #include <boost/shared_ptr.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/tuple/tuple.hpp>
#include <stdexcept> #include <stdexcept>
#include <vector> #include <vector>
#include <iostream> #include <iostream>
#include <deque> #include <deque>
#include <list>
#include "boxed_value.hpp" #include "boxed_value.hpp"
#include "type_info.hpp" #include "type_info.hpp"
@@ -32,6 +31,71 @@
namespace chaiscript 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 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. /// \brief Holds a collection of ChaiScript settings which can be applied to the ChaiScript runtime.
/// Used to implement loadable module support. /// Used to implement loadable module support.
class Module class Module
@@ -55,6 +119,17 @@ namespace chaiscript
return *this; 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 //Add a bit of chaiscript to eval during module implementation
Module &eval(const std::string &str) Module &eval(const std::string &str)
@@ -76,11 +151,13 @@ namespace chaiscript
apply(m_funcs.begin(), m_funcs.end(), t_engine); apply(m_funcs.begin(), m_funcs.end(), t_engine);
apply_eval(m_evals.begin(), m_evals.end(), t_eval); apply_eval(m_evals.begin(), m_evals.end(), t_eval);
apply_single(m_conversions.begin(), m_conversions.end(), t_engine); apply_single(m_conversions.begin(), m_conversions.end(), t_engine);
apply_globals(m_globals.begin(), m_globals.end(), t_engine);
} }
private: private:
std::vector<std::pair<Type_Info, std::string> > m_typeinfos; std::vector<std::pair<Type_Info, std::string> > m_typeinfos;
std::vector<std::pair<Proxy_Function, std::string> > m_funcs; std::vector<std::pair<Proxy_Function, std::string> > m_funcs;
std::vector<std::pair<Boxed_Value, std::string> > m_globals;
std::vector<std::string> m_evals; std::vector<std::string> m_evals;
std::vector<Dynamic_Cast_Conversion> m_conversions; std::vector<Dynamic_Cast_Conversion> m_conversions;
@@ -89,7 +166,22 @@ namespace chaiscript
{ {
while (begin != end) 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; ++begin;
} }
} }
@@ -266,48 +358,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 namespace detail
{ {
@@ -326,6 +376,7 @@ namespace chaiscript
struct State struct State
{ {
std::map<std::string, std::vector<Proxy_Function> > m_functions; 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; std::map<std::string, Boxed_Value> m_global_objects;
Type_Name_Map m_types; Type_Name_Map m_types;
std::set<std::string> m_reserved_words; std::set<std::string> m_reserved_words;
@@ -353,10 +404,10 @@ namespace chaiscript
/** /**
* Add a new named Proxy_Function to the system * 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); validate_object_name(name);
return add_function(f, name); add_function(f, name);
} }
/** /**
@@ -380,6 +431,7 @@ namespace chaiscript
add_object(name, obj); add_object(name, obj);
} }
/** /**
* Adds a named object to the current scope * Adds a named object to the current scope
@@ -388,7 +440,15 @@ namespace chaiscript
{ {
StackData &stack = get_stack_data(); StackData &stack = get_stack_data();
validate_object_name(name); 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,7 +464,12 @@ namespace chaiscript
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l(m_global_object_mutex); 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));
}
} }
/** /**
@@ -430,28 +495,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()); Stack s(new Stack::element_type());
s->push_back(Scope()); 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 Stack get_stack() const
{ {
return m_stack_holder->stack; return m_stack_holder->stacks.back();
} }
/** /**
@@ -491,21 +552,7 @@ namespace chaiscript
} }
// If all that failed, then check to see if it's a function // If all that failed, then check to see if it's a function
std::vector<Proxy_Function> funcs = get_function(name); return get_function_object(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)));
}
}
} }
/** /**
@@ -588,9 +635,26 @@ namespace chaiscript
} else { } else {
return std::vector<Proxy_Function>(); 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 * Return true if a function exists
*/ */
@@ -602,6 +666,78 @@ namespace chaiscript
return functions.find(name) != functions.end(); 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 * Get a vector of all registered functions
*/ */
@@ -665,10 +801,9 @@ namespace chaiscript
/** /**
* Dump object info to stdout * 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 << (o.is_const()?"const ":"") << type_name(o) << std::endl;
std::cout << (ti.is_const()?"const ":"") << get_type_name(ti) << std::endl;
} }
/** /**
@@ -760,7 +895,7 @@ namespace chaiscript
return false; 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()); return get_type_name(obj.get_type_info());
} }
@@ -781,6 +916,29 @@ namespace chaiscript
m_state = t_state; 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: private:
/** /**
@@ -789,7 +947,17 @@ namespace chaiscript
*/ */
StackData &get_stack_data() const 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 const std::map<std::string, std::vector<Proxy_Function> > &get_functions_int() const
@@ -811,7 +979,7 @@ namespace chaiscript
const size_t rhssize = rhsparamtypes.size(); const size_t rhssize = rhsparamtypes.size();
const Type_Info boxed_type = user_type<Boxed_Value>(); const Type_Info boxed_type = user_type<Boxed_Value>();
const Type_Info boxed_pod_type = user_type<Boxed_POD_Value>(); const Type_Info boxed_pod_type = user_type<Boxed_Number>();
boost::shared_ptr<const dispatch::Dynamic_Proxy_Function> dynamic_lhs(boost::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(lhs)); boost::shared_ptr<const dispatch::Dynamic_Proxy_Function> dynamic_lhs(boost::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(lhs));
boost::shared_ptr<const dispatch::Dynamic_Proxy_Function> dynamic_rhs(boost::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(rhs)); boost::shared_ptr<const dispatch::Dynamic_Proxy_Function> dynamic_rhs(boost::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(rhs));
@@ -911,11 +1079,10 @@ namespace chaiscript
} }
/** /**
* Implementation detail for adding a function. Returns * Implementation detail for adding a function.
* true if the function was added, false if a function with the * \throws exception::name_conflict_error if there's a function matching the given one being added
* same signature and name already exists.
*/ */
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); chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
@@ -924,6 +1091,8 @@ namespace chaiscript
std::map<std::string, std::vector<Proxy_Function> >::iterator itr std::map<std::string, std::vector<Proxy_Function> >::iterator itr
= funcs.find(t_name); = funcs.find(t_name);
std::map<std::string, Proxy_Function> &func_objs = get_function_objects_int();
if (itr != funcs.end()) if (itr != funcs.end())
{ {
std::vector<Proxy_Function> &vec = itr->second; std::vector<Proxy_Function> &vec = itr->second;
@@ -933,19 +1102,21 @@ namespace chaiscript
{ {
if ((*t_f) == *(*itr2)) if ((*t_f) == *(*itr2))
{ {
return false; throw exception::name_conflict_error(t_name);
} }
} }
vec.push_back(t_f); vec.push_back(t_f);
std::stable_sort(vec.begin(), vec.end(), &function_less_than); std::stable_sort(vec.begin(), vec.end(), &function_less_than);
func_objs[t_name] = Proxy_Function(new Dispatch_Function(vec));
} else { } else {
std::vector<Proxy_Function> vec; std::vector<Proxy_Function> vec;
vec.push_back(t_f); vec.push_back(t_f);
funcs.insert(std::make_pair(t_name, vec)); funcs.insert(std::make_pair(t_name, vec));
func_objs[t_name] = t_f;
} }
return true;
} }
mutable chaiscript::detail::threading::shared_mutex m_mutex; mutable chaiscript::detail::threading::shared_mutex m_mutex;
@@ -954,12 +1125,17 @@ namespace chaiscript
struct Stack_Holder struct Stack_Holder
{ {
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; std::vector<Dynamic_Cast_Conversion> m_conversions;

View File

@@ -1,6 +1,6 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2011, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// and Jason Turner (jason@emptycrate.com) // and Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
@@ -48,6 +48,7 @@ namespace chaiscript
{ {
public: public:
virtual Boxed_Value convert(const Boxed_Value &derived) = 0; virtual Boxed_Value convert(const Boxed_Value &derived) = 0;
const Type_Info &base() const Type_Info &base()
{ {
return m_base; return m_base;
@@ -63,6 +64,8 @@ namespace chaiscript
{ {
} }
virtual ~Dynamic_Conversion() {}
private: private:
Type_Info m_base; Type_Info m_base;
Type_Info m_derived; Type_Info m_derived;

View File

@@ -1,6 +1,6 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2011, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// and Jason Turner (jason@emptycrate.com) // and Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
@@ -44,20 +44,6 @@ namespace chaiscript
namespace detail 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 * A Proxy_Function implementation designed for calling a function
* that is automatically guarded based on the first param based on the * that is automatically guarded based on the first param based on the

View File

@@ -0,0 +1,176 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// and Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_EXCEPTION_SPECIFICATION_HPP_
#define CHAISCRIPT_EXCEPTION_SPECIFICATION_HPP_
#include "boxed_cast.hpp"
namespace chaiscript
{
namespace detail
{
struct Exception_Handler_Base
{
virtual void handle(const Boxed_Value &bv) = 0;
protected:
template<typename T>
void throw_type(const Boxed_Value &bv)
{
try { T t = boxed_cast<T>(bv); throw t; } catch (const exception::bad_boxed_cast &) {}
}
};
template<typename T1>
struct Exception_Handler_Impl1 : Exception_Handler_Base
{
virtual void handle(const Boxed_Value &bv)
{
throw_type<T1>(bv);
}
};
template<typename T1, typename T2>
struct Exception_Handler_Impl2 : Exception_Handler_Base
{
virtual void handle(const Boxed_Value &bv)
{
throw_type<T1>(bv);
throw_type<T2>(bv);
}
};
template<typename T1, typename T2, typename T3>
struct Exception_Handler_Impl3 : Exception_Handler_Base
{
virtual void handle(const Boxed_Value &bv)
{
throw_type<T1>(bv);
throw_type<T2>(bv);
throw_type<T3>(bv);
}
};
template<typename T1, typename T2, typename T3, typename T4>
struct Exception_Handler_Impl4 : Exception_Handler_Base
{
virtual void handle(const Boxed_Value &bv)
{
throw_type<T1>(bv);
throw_type<T2>(bv);
throw_type<T3>(bv);
throw_type<T4>(bv);
}
};
template<typename T1, typename T2, typename T3, typename T4, typename T5>
struct Exception_Handler_Impl5 : Exception_Handler_Base
{
virtual void handle(const Boxed_Value &bv)
{
throw_type<T1>(bv);
throw_type<T2>(bv);
throw_type<T3>(bv);
throw_type<T4>(bv);
throw_type<T5>(bv);
}
};
}
/// \brief Used in the automatic unboxing of exceptions thrown during script evaluation
///
/// Exception specifications allow the user to tell ChaiScript what possible exceptions are expected from the script
/// being executed. Exception_Handler objects are created with the chaiscript::exception_specification() function.
///
/// Example:
/// \code
/// chaiscript::ChaiScript chai;
///
/// try {
/// chai.eval("throw(runtime_error(\"error\"))", chaiscript::exception_specification<int, double, float, const std::string &, const std::exception &>());
/// } catch (const double e) {
/// } catch (int) {
/// } catch (float) {
/// } catch (const std::string &) {
/// } catch (const std::exception &e) {
/// // This is the one what will be called in the specific throw() above
/// }
/// \endcode
///
/// It is recommended that if catching the generic \c std::exception& type that you specifically catch
/// the chaiscript::exception::eval_error type, so that there is no confusion.
///
/// \code
/// try {
/// chai.eval("throw(runtime_error(\"error\"))", chaiscript::exception_specification<const std::exception &>());
/// } catch (const chaiscript::exception::eval_error &) {
/// // Error in script parsing / execution
/// } catch (const std::exception &e) {
/// // Error explicitly thrown from script
/// }
/// \endcode
///
/// Similarly, if you are using the ChaiScript::eval form that unboxes the return value, then chaiscript::exception::bad_boxed_cast
/// should be handled as well.
///
/// \code
/// try {
/// chai.eval<int>("1.0", chaiscript::exception_specification<const std::exception &>());
/// } catch (const chaiscript::exception::eval_error &) {
/// // Error in script parsing / execution
/// } catch (const chaiscript::exception::bad_boxed_cast &) {
/// // Error unboxing return value
/// } catch (const std::exception &e) {
/// // Error explicitly thrown from script
/// }
/// \endcode
///
/// \sa chaiscript::exception_specification for creation of chaiscript::Exception_Handler objects
/// \sa \ref exceptions
typedef boost::shared_ptr<detail::Exception_Handler_Base> Exception_Handler;
/// \brief creates a chaiscript::Exception_Handler which handles one type of exception unboxing
/// \sa \ref exceptions
template<typename T1>
Exception_Handler exception_specification()
{
return Exception_Handler(new detail::Exception_Handler_Impl1<T1>());
}
/// \brief creates a chaiscript::Exception_Handler which handles two types of exception unboxing
/// \sa \ref exceptions
template<typename T1, typename T2>
Exception_Handler exception_specification()
{
return Exception_Handler(new detail::Exception_Handler_Impl2<T1, T2>());
}
/// \brief creates a chaiscript::Exception_Handler which handles three types of exception unboxing
/// \sa \ref exceptions
template<typename T1, typename T2, typename T3>
Exception_Handler exception_specification()
{
return Exception_Handler(new detail::Exception_Handler_Impl3<T1, T2, T3>());
}
/// \brief creates a chaiscript::Exception_Handler which handles four types of exception unboxing
/// \sa \ref exceptions
template<typename T1, typename T2, typename T3, typename T4>
Exception_Handler exception_specification()
{
return Exception_Handler(new detail::Exception_Handler_Impl4<T1, T2, T3, T4>());
}
/// \brief creates a chaiscript::Exception_Handler which handles five types of exception unboxing
/// \sa \ref exceptions
template<typename T1, typename T2, typename T3, typename T4, typename T5>
Exception_Handler exception_specification()
{
return Exception_Handler(new detail::Exception_Handler_Impl5<T1, T2, T3, T4, T5>());
}
}
#endif

View File

@@ -1,6 +1,6 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2011, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// and Jason Turner (jason@emptycrate.com) // and Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
@@ -114,6 +114,8 @@ namespace chaiscript
} }
} }
#undef n #undef n
#undef addparam
#undef curry
#endif #endif

View File

@@ -1,6 +1,6 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2011, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// and Jason Turner (jason@emptycrate.com) // and Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
@@ -8,6 +8,7 @@
#define CHAISCRIPT_HANDLE_RETURN_HPP_ #define CHAISCRIPT_HANDLE_RETURN_HPP_
#include "boxed_value.hpp" #include "boxed_value.hpp"
#include "boxed_number.hpp"
#include "type_info.hpp" #include "type_info.hpp"
#include <string> #include <string>
#include <boost/function.hpp> #include <boost/function.hpp>
@@ -33,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> template<typename Ret>
struct Handle_Return<boost::shared_ptr<Ret> &> struct Handle_Return<boost::shared_ptr<Ret> &>
{ {
@@ -135,6 +145,30 @@ namespace chaiscript
} }
}; };
/**
* Used internally for handling a return value from a Proxy_Function call
*/
template<>
struct Handle_Return<Boxed_Number>
{
static Boxed_Value handle(const Boxed_Number &r)
{
return r.bv;
}
};
/**
* Used internally for handling a return value from a Proxy_Function call
*/
template<>
struct Handle_Return<const Boxed_Number>
{
static Boxed_Value handle(const Boxed_Number &r)
{
return r.bv;
}
};
/** /**
* Used internally for handling a return value from a Proxy_Function call * Used internally for handling a return value from a Proxy_Function call

View File

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

View File

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

View File

@@ -1,6 +1,6 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2011, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// and Jason Turner (jason@emptycrate.com) // and Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
@@ -20,12 +20,11 @@
namespace chaiscript namespace chaiscript
{ {
class Boxed_POD_Value; class Boxed_Number;
struct AST_Node; struct AST_Node;
typedef boost::shared_ptr<struct AST_Node> AST_NodePtr; typedef boost::shared_ptr<struct AST_Node> AST_NodePtr;
namespace dispatch namespace dispatch
{ {
/** /**
@@ -74,7 +73,6 @@ namespace chaiscript
Boxed_Value operator()(const std::vector<Boxed_Value> &params) const Boxed_Value operator()(const std::vector<Boxed_Value> &params) const
{ {
Boxed_Value bv = do_call(params); Boxed_Value bv = do_call(params);
bv.add_dependencies(params.begin(), params.end());
return bv; return bv;
} }
@@ -139,7 +137,7 @@ namespace chaiscript
if (ti.is_undef() if (ti.is_undef()
|| ti.bare_equal(user_type<Boxed_Value>()) || ti.bare_equal(user_type<Boxed_Value>())
|| (!bv.get_type_info().is_undef() || (!bv.get_type_info().is_undef()
&& (ti.bare_equal(user_type<Boxed_POD_Value>()) && (ti.bare_equal(user_type<Boxed_Number>())
|| ti.bare_equal(bv.get_type_info()) || ti.bare_equal(bv.get_type_info())
|| chaiscript::detail::dynamic_cast_converts(ti, 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> >()) || bv.get_type_info().bare_equal(user_type<boost::shared_ptr<const Proxy_Function_Base> >())
@@ -219,7 +217,12 @@ namespace chaiscript
virtual bool operator==(const Proxy_Function_Base &rhs) const 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
@@ -587,17 +590,16 @@ namespace chaiscript
class dispatch_error : public std::runtime_error class dispatch_error : public std::runtime_error
{ {
public: public:
dispatch_error() throw() dispatch_error(const std::vector<Boxed_Value> &t_parameters,
: std::runtime_error("No matching function to dispatch to") 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() {} virtual ~dispatch_error() throw() {}
std::vector<Boxed_Value> parameters;
std::vector<Const_Proxy_Function> functions;
}; };
} }
@@ -610,9 +612,10 @@ namespace chaiscript
* function is found or throw dispatch_error if no matching function is found * function is found or throw dispatch_error if no matching function is found
*/ */
template<typename InItr> template<typename InItr>
Boxed_Value dispatch(InItr begin, InItr end, Boxed_Value dispatch(InItr begin, const InItr &end,
const std::vector<Boxed_Value> &plist) const std::vector<Boxed_Value> &plist)
{ {
InItr orig(begin);
while (begin != end) while (begin != end)
{ {
try { try {
@@ -631,7 +634,7 @@ namespace chaiscript
++begin; ++begin;
} }
throw exception::dispatch_error(plist.empty()?false:plist[0].is_const()); throw exception::dispatch_error(plist, std::vector<Const_Proxy_Function>(orig, end));
} }
/** /**

View File

@@ -1,6 +1,6 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2011, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// and Jason Turner (jason@emptycrate.com) // and Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
@@ -21,7 +21,6 @@
#include <string> #include <string>
#include <boost/function.hpp> #include <boost/function.hpp>
#include <boost/bind.hpp> #include <boost/bind.hpp>
#include <boost/lexical_cast.hpp>
#include <stdexcept> #include <stdexcept>
#include <vector> #include <vector>
@@ -121,6 +120,10 @@ namespace chaiscript
} }
#undef n #undef n
#undef gettypeinfo
#undef casthelper
#undef trycast
#endif #endif

View File

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

View File

@@ -1,6 +1,6 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2011, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// and Jason Turner (jason@emptycrate.com) // and Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
@@ -14,6 +14,8 @@
#include <boost/type_traits/is_void.hpp> #include <boost/type_traits/is_void.hpp>
#include <boost/type_traits/is_reference.hpp> #include <boost/type_traits/is_reference.hpp>
#include <boost/type_traits/is_pointer.hpp> #include <boost/type_traits/is_pointer.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/type_traits/is_arithmetic.hpp>
#include <boost/type_traits/remove_const.hpp> #include <boost/type_traits/remove_const.hpp>
#include <boost/type_traits/remove_reference.hpp> #include <boost/type_traits/remove_reference.hpp>
#include <boost/type_traits/remove_pointer.hpp> #include <boost/type_traits/remove_pointer.hpp>
@@ -36,38 +38,41 @@ namespace chaiscript
{ {
public: public:
Type_Info(bool t_is_const, bool t_is_reference, bool t_is_pointer, bool t_is_void, Type_Info(bool t_is_const, bool t_is_reference, bool t_is_pointer, bool t_is_void,
const std::type_info *t_ti, const std::type_info *t_bareti) 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_void(t_is_void), 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_void(t_is_void), m_is_arithmetic(t_is_arithmetic),
m_is_undef(false) m_is_undef(false)
{ {
} }
Type_Info() Type_Info()
: m_is_const(false), m_is_reference(false), m_is_pointer(false), : m_type_info(0), m_bare_type_info(0),
m_is_void(false), 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) m_is_undef(true)
{ {
} }
Type_Info(const Type_Info &ti) 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_is_pointer(ti.m_is_pointer),
m_is_void(ti.m_is_void), m_type_info(ti.m_type_info),
m_bare_type_info(ti.m_bare_type_info), m_bare_type_info(ti.m_bare_type_info),
m_is_const(ti.m_is_const), m_is_reference(ti.m_is_reference),
m_is_pointer(ti.m_is_pointer),
m_is_void(ti.m_is_void), m_is_arithmetic(ti.m_is_arithmetic),
m_is_undef(ti.m_is_undef) m_is_undef(ti.m_is_undef)
{ {
} }
Type_Info &operator=(const Type_Info &ti) 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_const = ti.m_is_const;
m_is_reference = ti.m_is_reference; m_is_reference = ti.m_is_reference;
m_is_pointer = ti.m_is_pointer; m_is_pointer = ti.m_is_pointer;
m_is_void = ti.m_is_void; m_is_void = ti.m_is_void;
m_type_info = ti.m_type_info; m_is_arithmetic = ti.m_is_arithmetic;
m_bare_type_info = ti.m_bare_type_info;
m_is_undef = ti.m_is_undef; m_is_undef = ti.m_is_undef;
return *this; return *this;
} }
@@ -97,6 +102,7 @@ namespace chaiscript
bool is_const() const { return m_is_const; } bool is_const() const { return m_is_const; }
bool is_reference() const { return m_is_reference; } bool is_reference() const { return m_is_reference; }
bool is_void() const { return m_is_void; } bool is_void() const { return m_is_void; }
bool is_arithmetic() const { return m_is_arithmetic; }
bool is_undef() const { return m_is_undef || m_bare_type_info == 0; } bool is_undef() const { return m_is_undef || m_bare_type_info == 0; }
bool is_pointer() const { return m_is_pointer; } bool is_pointer() const { return m_is_pointer; }
@@ -121,12 +127,13 @@ namespace chaiscript
} }
private: private:
const std::type_info *m_type_info;
const std::type_info *m_bare_type_info;
bool m_is_const; bool m_is_const;
bool m_is_reference; bool m_is_reference;
bool m_is_pointer; bool m_is_pointer;
bool m_is_void; bool m_is_void;
const std::type_info *m_type_info; bool m_is_arithmetic;
const std::type_info *m_bare_type_info;
bool m_is_undef; bool m_is_undef;
}; };
@@ -144,6 +151,7 @@ namespace chaiscript
{ {
return Type_Info(boost::is_const<typename boost::remove_pointer<typename boost::remove_reference<T>::type>::type>::value, boost::is_reference<T>::value, boost::is_pointer<T>::value, return Type_Info(boost::is_const<typename boost::remove_pointer<typename boost::remove_reference<T>::type>::type>::value, boost::is_reference<T>::value, boost::is_pointer<T>::value,
boost::is_void<T>::value, boost::is_void<T>::value,
boost::is_arithmetic<T>::value && !boost::is_same<typename boost::remove_const<T>::type, bool>::value,
&typeid(T), &typeid(T),
&typeid(typename Bare_Type<T>::type)); &typeid(typename Bare_Type<T>::type));
} }
@@ -158,6 +166,7 @@ namespace chaiscript
{ {
return Type_Info(boost::is_const<T>::value, boost::is_reference<T>::value, boost::is_pointer<T>::value, return Type_Info(boost::is_const<T>::value, boost::is_reference<T>::value, boost::is_pointer<T>::value,
boost::is_void<T>::value, boost::is_void<T>::value,
boost::is_arithmetic<T>::value && !boost::is_same<typename boost::remove_const<T>::type, bool>::value,
&typeid(boost::shared_ptr<T> ), &typeid(boost::shared_ptr<T> ),
&typeid(typename Bare_Type<T>::type)); &typeid(typename Bare_Type<T>::type));
} }
@@ -172,6 +181,7 @@ namespace chaiscript
{ {
return Type_Info(boost::is_const<T>::value, boost::is_reference<T>::value, boost::is_pointer<T>::value, return Type_Info(boost::is_const<T>::value, boost::is_reference<T>::value, boost::is_pointer<T>::value,
boost::is_void<T>::value, boost::is_void<T>::value,
boost::is_arithmetic<T>::value && !boost::is_same<typename boost::remove_const<T>::type, bool>::value,
&typeid(const boost::shared_ptr<T> &), &typeid(const boost::shared_ptr<T> &),
&typeid(typename Bare_Type<T>::type)); &typeid(typename Bare_Type<T>::type));
} }
@@ -186,6 +196,7 @@ namespace chaiscript
{ {
return Type_Info(boost::is_const<T>::value, boost::is_reference<T>::value, boost::is_pointer<T>::value, return Type_Info(boost::is_const<T>::value, boost::is_reference<T>::value, boost::is_pointer<T>::value,
boost::is_void<T>::value, boost::is_void<T>::value,
boost::is_arithmetic<T>::value && !boost::is_same<typename boost::remove_const<T>::type, bool>::value,
&typeid(boost::reference_wrapper<T> ), &typeid(boost::reference_wrapper<T> ),
&typeid(typename Bare_Type<T>::type)); &typeid(typename Bare_Type<T>::type));
} }
@@ -200,6 +211,7 @@ namespace chaiscript
{ {
return Type_Info(boost::is_const<T>::value, boost::is_reference<T>::value, boost::is_pointer<T>::value, return Type_Info(boost::is_const<T>::value, boost::is_reference<T>::value, boost::is_pointer<T>::value,
boost::is_void<T>::value, boost::is_void<T>::value,
boost::is_arithmetic<T>::value && !boost::is_same<typename boost::remove_const<T>::type, bool>::value,
&typeid(const boost::reference_wrapper<T> &), &typeid(const boost::reference_wrapper<T> &),
&typeid(typename Bare_Type<T>::type)); &typeid(typename Bare_Type<T>::type));
} }

View File

@@ -0,0 +1,131 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// and Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_ALGEBRAIC_HPP_
#define CHAISCRIPT_ALGEBRAIC_HPP_
#include <chaiscript/dispatchkit/dispatchkit.hpp>
#include <boost/enable_shared_from_this.hpp>
namespace chaiscript
{
struct Operators {
enum Opers
{
boolean_flag,
equals, less_than, greater_than, less_than_equal, greater_than_equal, not_equal,
non_const_flag,
assign, pre_increment, pre_decrement, assign_product, assign_sum,
assign_quotient, assign_difference,
non_const_int_flag,
assign_bitwise_and, assign_bitwise_or, assign_shift_left, assign_shift_right,
assign_remainder, assign_bitwise_xor,
const_int_flag,
shift_left, shift_right, remainder, bitwise_and, bitwise_or, bitwise_xor, bitwise_complement,
const_flag,
sum, quotient, product, difference, unary_plus, unary_minus,
invalid
};
static const char *to_string(Opers t_oper) {
const char *opers[] = {
"",
"==", "<", ">", "<=", ">=", "!=",
"",
"=", "++", "--", "*=", "+=",
"/=", "-=",
"",
"&=", "|=", "<<=", ">>=",
"%=", "^=",
"",
"<<", ">>", "%", "&", "|", "^", "~",
"",
"+", "/", "*", "-", "+", "-",
""
};
return opers[t_oper];
}
static Opers to_operator(const std::string &t_str, bool t_is_unary = false)
{
if (t_str == "==")
{
return equals;
} else if (t_str == "<") {
return less_than;
} else if (t_str == ">") {
return greater_than;
} else if (t_str == "<=") {
return less_than_equal;
} else if (t_str == ">=") {
return greater_than_equal;
} else if (t_str == "!=") {
return not_equal;
} else if (t_str == "=") {
return assign;
} else if (t_str == "++") {
return pre_increment;
} else if (t_str == "--") {
return pre_decrement;
} else if (t_str == "*=") {
return assign_product;
} else if (t_str == "+=") {
return assign_sum;
} else if (t_str == "-=") {
return assign_difference;
} else if (t_str == "&=") {
return assign_bitwise_and;
} else if (t_str == "|=") {
return assign_bitwise_or;
} else if (t_str == "<<=") {
return assign_shift_left;
} else if (t_str == ">>=") {
return assign_shift_right;
} else if (t_str == "%=") {
return assign_remainder;
} else if (t_str == "^=") {
return assign_bitwise_xor;
} else if (t_str == "<<") {
return shift_left;
} else if (t_str == ">>") {
return shift_right;
} else if (t_str == "%") {
return remainder;
} else if (t_str == "&") {
return bitwise_and;
} else if (t_str == "|") {
return bitwise_or;
} else if (t_str == "^") {
return bitwise_xor;
} else if (t_str == "~") {
return bitwise_complement;
} else if (t_str == "+") {
if (t_is_unary) {
return unary_plus;
} else {
return sum;
}
} else if (t_str == "-") {
if (t_is_unary) {
return unary_minus;
} else {
return difference;
}
} else if (t_str == "/") {
return quotient;
} else if (t_str == "*") {
return product;
} else {
return invalid;
}
}
};
}
#endif /* _CHAISCRIPT_ALGEBRAIC_HPP */

View File

@@ -1,6 +1,6 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2011, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// and Jason Turner (jason@emptycrate.com) // and Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
@@ -15,14 +15,15 @@ namespace chaiscript
/// Signature of module entry point that all binary loadable modules must implement. /// Signature of module entry point that all binary loadable modules must implement.
typedef ModulePtr (*Create_Module_Func)(); typedef ModulePtr (*Create_Module_Func)();
/// Types of AST nodes available to the parser and eval /// Types of AST nodes available to the parser and eval
class AST_Node_Type { class AST_Node_Type {
public: public:
enum Type { Error, Int, Float, Id, Char, Str, Eol, Fun_Call, Inplace_Fun_Call, Arg_List, Variable, Equation, Var_Decl, enum Type { Error, Int, Float, Id, Char, Str, Eol, Fun_Call, Inplace_Fun_Call, Arg_List, Variable, Equation, Var_Decl,
Comparison, Additive, Multiplicative, Array_Call, Dot_Access, Quoted_String, Single_Quoted_String, 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, Map_Pair, Value_Range,
Inline_Range, Annotation, Try, Catch, Finally, Method, Attr_Decl, Shift, Equality, Bitwise_And, Bitwise_Xor, Bitwise_Or, Inline_Range, Annotation, Try, Catch, Finally, Method, Attr_Decl, Shift, Equality, Bitwise_And, Bitwise_Xor, Bitwise_Or,
Logical_And, Logical_Or Logical_And, Logical_Or, Switch, Case, Default, Ternary_Cond
}; };
}; };
@@ -33,10 +34,10 @@ namespace chaiscript
*/ */
const char *ast_node_type_to_string(int ast_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", const char *ast_node_types[] = { "Internal Parser Error", "Int", "Float", "Id", "Char", "Str", "Eol", "Fun_Call", "Inplace_Fun_Call", "Arg_List", "Variable", "Equation", "Var_Decl",
"Comparison", "Additive", "Multiplicative", "Array_Call", "Dot_Access", "Quoted_String", "Single_Quoted_String", "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", "Map_Pair", "Value_Range",
"Inline_Range", "Annotation", "Try", "Catch", "Finally", "Method", "Attr_Decl", "Shift", "Equality", "Bitwise_And", "Bitwise_Xor", "Bitwise_Or", "Inline_Range", "Annotation", "Try", "Catch", "Finally", "Method", "Attr_Decl", "Shift", "Equality", "Bitwise_And", "Bitwise_Xor", "Bitwise_Or",
"Logical_And", "Logical_Or"}; "Logical_And", "Logical_Or", "Switch", "Case", "Default", "Ternary Condition"};
return ast_node_types[ast_node_type]; return ast_node_types[ast_node_type];
} }
@@ -68,22 +69,312 @@ namespace chaiscript
File_Position start_position; File_Position start_position;
File_Position end_position; File_Position end_position;
std::string filename; std::string filename;
std::string detail;
std::vector<AST_NodePtr> call_stack; std::vector<AST_NodePtr> call_stack;
eval_error(const std::string &t_why, const File_Position &t_where, const std::string &t_fname) throw() : eval_error(const std::string &t_why, const File_Position &t_where, const std::string &t_fname,
std::runtime_error("Error: \"" + t_why + "\" " + const std::vector<Boxed_Value> &t_parameters, const std::vector<chaiscript::Const_Proxy_Function> &t_functions,
(t_fname != "__EVAL__" ? ("in '" + t_fname + "' ") : "during evaluation ") + bool t_dot_notation,
+ "at (" + boost::lexical_cast<std::string>(t_where.line) + ", " + const chaiscript::detail::Dispatch_Engine &t_ss) :
boost::lexical_cast<std::string>(t_where.column) + ")"), 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) reason(t_why), start_position(t_where), end_position(t_where), filename(t_fname)
{ } {}
eval_error(const std::string &t_why) throw() eval_error(const std::string &t_why) throw()
: std::runtime_error("Error: \"" + t_why + "\" "), : std::runtime_error("Error: \"" + t_why + "\" "),
reason(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() {} 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();
}
}; };
/** /**
@@ -110,6 +401,19 @@ namespace chaiscript
std::vector<AST_NodePtr> children; std::vector<AST_NodePtr> children;
AST_NodePtr annotation; AST_NodePtr annotation;
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 * Prints the contents of an AST node, including its children, recursively
*/ */
@@ -212,6 +516,57 @@ namespace chaiscript
chaiscript::detail::Dispatch_Engine &m_de; 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,6 +1,6 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2011, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// and Jason Turner (jason@emptycrate.com) // and Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
@@ -10,7 +10,7 @@
#include <exception> #include <exception>
#include <fstream> #include <fstream>
#include <chaiscript/language/chaiscript_common.hpp> #include "chaiscript_common.hpp"
#ifdef _POSIX_VERSION #ifdef _POSIX_VERSION
#include <dlfcn.h> #include <dlfcn.h>
@@ -23,8 +23,9 @@
#endif #endif
#include <chaiscript/language/chaiscript_prelude.hpp> #include "chaiscript_prelude.hpp"
#include <chaiscript/language/chaiscript_parser.hpp> #include "chaiscript_parser.hpp"
#include "../dispatchkit/exception_specification.hpp"
namespace chaiscript namespace chaiscript
{ {
@@ -75,7 +76,7 @@ namespace chaiscript
struct DLSym struct DLSym
{ {
DLSym(DLModule &t_mod, const std::string &t_symbol) 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) if (!m_symbol)
{ {
@@ -83,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; T m_symbol;
}; };
@@ -260,7 +274,11 @@ namespace chaiscript
const Boxed_Value internal_eval_ast(const AST_NodePtr &t_ast) const Boxed_Value internal_eval_ast(const AST_NodePtr &t_ast)
{ {
return t_ast->eval(m_engine); try {
return t_ast->eval(m_engine);
} catch (const exception::eval_error &t_ee) {
throw Boxed_Value(t_ee);
}
} }
@@ -268,37 +286,14 @@ namespace chaiscript
* Evaluates the given string, used during eval() inside of a script * Evaluates the given string, used during eval() inside of a script
*/ */
const Boxed_Value internal_eval(const std::string &t_e) { const Boxed_Value internal_eval(const std::string &t_e) {
return do_eval(t_e, "__EVAL__", true); try {
} return do_eval(t_e, "__EVAL__", true);
} catch (const exception::eval_error &t_ee) {
void use(const std::string &t_filename) throw Boxed_Value(t_ee);
{
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
}
} }
} }
/** /**
* Returns the current evaluation m_engine * Returns the current evaluation m_engine
*/ */
@@ -311,6 +306,7 @@ namespace chaiscript
*/ */
void build_eval_system() { void build_eval_system() {
using namespace bootstrap; using namespace bootstrap;
m_engine.add_reserved_word("auto");
m_engine.add_reserved_word("def"); m_engine.add_reserved_word("def");
m_engine.add_reserved_word("fun"); m_engine.add_reserved_word("fun");
m_engine.add_reserved_word("while"); m_engine.add_reserved_word("while");
@@ -335,6 +331,8 @@ 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::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::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::function_exists, boost::ref(m_engine)), "function_exists");
m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::get_function_objects, boost::ref(m_engine)), "get_functions");
m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::get_scripting_objects, boost::ref(m_engine)), "get_objects");
m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::get_type_name, boost::ref(m_engine)), "name"); m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::get_type_name, boost::ref(m_engine)), "name");
@@ -403,6 +401,40 @@ namespace chaiscript
build_eval_system(); 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::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);
}
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 /// \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_bv Boxed_Value to add as a global
/// \param[in] t_name Name of the value to add /// \param[in] t_name Name of the value to add
@@ -424,8 +456,12 @@ namespace chaiscript
std::set<std::string> active_loaded_modules; std::set<std::string> active_loaded_modules;
}; };
/// \brief Returns a state object that represents the current state of the system /// \brief Returns a state object that represents the current state of the global system
/// \return Current state of the 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: /// \b Example:
/// ///
@@ -446,6 +482,10 @@ namespace chaiscript
} }
/// \brief Sets the state of the system /// \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 /// \param[in] t_state New state to set
/// ///
/// \b Example: /// \b Example:
@@ -465,7 +505,23 @@ namespace chaiscript
m_engine.set_state(t_state.engine_state); 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_t Item to add
/// \param[in] t_name Name of item to add /// \param[in] t_name Name of item to add
/// \returns Reference to current ChaiScript object /// \returns Reference to current ChaiScript object
@@ -598,19 +654,30 @@ namespace chaiscript
/// \brief Evaluates a string. Equivalent to ChaiScript::eval. /// \brief Evaluates a string. Equivalent to ChaiScript::eval.
/// ///
/// \param[in] t_script Script to execute /// \param[in] t_script Script to execute
/// \param[in] t_handler Optional Exception_Handler used for automatic unboxing of script thrown exceptions
/// ///
/// \return result of the script execution /// \return result of the script execution
/// ///
/// \throw exception::eval_error In the case that evaluation fails. /// \throw exception::eval_error In the case that evaluation fails.
Boxed_Value operator()(const std::string &t_script) Boxed_Value operator()(const std::string &t_script, const Exception_Handler &t_handler = Exception_Handler())
{ {
return do_eval(t_script); try {
return do_eval(t_script);
} catch (Boxed_Value &bv) {
if (t_handler) {
t_handler->handle(bv);
}
throw bv;
}
} }
/// \brief Evaluates a string and returns a typesafe result. /// \brief Evaluates a string and returns a typesafe result.
/// ///
/// \tparam T Type to extract from the result value of the script execution /// \tparam T Type to extract from the result value of the script execution
/// \param[in] t_input Script to execute /// \param[in] t_input Script to execute
/// \param[in] t_handler Optional Exception_Handler used for automatic unboxing of script thrown exceptions
/// \param[in] t_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 /// \return result of the script execution
/// ///
@@ -618,41 +685,74 @@ namespace chaiscript
/// \throw exception::bad_boxed_cast In the case that evaluation succeeds but the result value cannot be converted /// \throw exception::bad_boxed_cast In the case that evaluation succeeds but the result value cannot be converted
/// to the requested type. /// to the requested type.
template<typename T> template<typename T>
T eval(const std::string &t_input) T eval(const std::string &t_input, const Exception_Handler &t_handler = Exception_Handler(), const std::string &t_filename="__EVAL__")
{ {
return boxed_cast<T>(do_eval(t_input)); try {
return boxed_cast<T>(do_eval(t_input, t_filename));
} catch (Boxed_Value &bv) {
if (t_handler) {
t_handler->handle(bv);
}
throw bv;
}
} }
/// \brief Evaluates a string. /// \brief Evaluates a string.
/// ///
/// \param[in] t_input Script to execute /// \param[in] t_input Script to execute
/// \param[in] t_handler Optional Exception_Handler used for automatic unboxing of script thrown exceptions
/// \param[in] t_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 /// \return result of the script execution
/// ///
/// \throw exception::eval_error In the case that evaluation fails. /// \throw exception::eval_error In the case that evaluation fails.
Boxed_Value eval(const std::string &t_input) Boxed_Value eval(const std::string &t_input, const Exception_Handler &t_handler = Exception_Handler(), const std::string &t_filename="__EVAL__")
{ {
return do_eval(t_input); try {
return do_eval(t_input, t_filename);
} catch (Boxed_Value &bv) {
if (t_handler) {
t_handler->handle(bv);
}
throw bv;
}
} }
/// \brief Loads the file specified by filename, evaluates it, and returns the result. /// \brief Loads the file specified by filename, evaluates it, and returns the result.
/// \param[in] t_filename File to load and parse. /// \param[in] t_filename File to load and parse.
/// \param[in] t_handler Optional Exception_Handler used for automatic unboxing of script thrown exceptions
/// \return result of the script execution /// \return result of the script execution
/// \throw exception::eval_error In the case that evaluation fails. /// \throw exception::eval_error In the case that evaluation fails.
Boxed_Value eval_file(const std::string &t_filename) { Boxed_Value eval_file(const std::string &t_filename, const Exception_Handler &t_handler = Exception_Handler()) {
return do_eval(load_file(t_filename), t_filename); try {
return do_eval(load_file(t_filename), t_filename);
} catch (Boxed_Value &bv) {
if (t_handler) {
t_handler->handle(bv);
}
throw bv;
}
} }
/// \brief Loads the file specified by filename, evaluates it, and returns the typesafe result. /// \brief Loads the file specified by filename, evaluates it, and returns the typesafe result.
/// \tparam T Type to extract from the result value of the script execution /// \tparam T Type to extract from the result value of the script execution
/// \param[in] t_filename File to load and parse. /// \param[in] t_filename File to load and parse.
/// \param[in] t_handler Optional Exception_Handler used for automatic unboxing of script thrown exceptions
/// \return result of the script execution /// \return result of the script execution
/// \throw exception::eval_error In the case that evaluation fails. /// \throw exception::eval_error In the case that evaluation fails.
/// \throw exception::bad_boxed_cast In the case that evaluation succeeds but the result value cannot be converted /// \throw exception::bad_boxed_cast In the case that evaluation succeeds but the result value cannot be converted
/// to the requested type. /// to the requested type.
template<typename T> template<typename T>
T eval_file(const std::string &t_filename) { T eval_file(const std::string &t_filename, const Exception_Handler &t_handler = Exception_Handler()) {
return boxed_cast<T>(do_eval(load_file(t_filename), t_filename)); try {
return boxed_cast<T>(do_eval(load_file(t_filename), t_filename));
} catch (Boxed_Value &bv) {
if (t_handler) {
t_handler->handle(bv);
}
throw bv;
}
} }
}; };

View File

@@ -1,6 +1,6 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2011, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// and Jason Turner (jason@emptycrate.com) // and Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
@@ -39,25 +39,55 @@ namespace chaiscript
struct Binary_Operator_AST_Node : public AST_Node { struct Binary_Operator_AST_Node : public AST_Node {
public: public:
Binary_Operator_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Bitwise_Xor, const boost::shared_ptr<std::string> &t_fname=boost::shared_ptr<std::string>(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : Binary_Operator_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Bitwise_Xor, const boost::shared_ptr<std::string> &t_fname=boost::shared_ptr<std::string>(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) :
AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col)
{ }
virtual ~Binary_Operator_AST_Node() {} virtual ~Binary_Operator_AST_Node() {}
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss){ virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) {
Boxed_Value retval; return do_oper(t_ss, Operators::to_operator(children[1]->text), children[1]->text,
this->children[0]->eval(t_ss),
retval = this->children[0]->eval(t_ss); this->children[2]->eval(t_ss));
for (size_t i = 1; i < this->children.size(); i += 2) {
try {
retval = t_ss.call_function(this->children[i]->text, retval, this->children[i+1]->eval(t_ss));
}
catch(const exception::dispatch_error &){
throw exception::eval_error("Can not find appropriate '" + this->children[i]->text + "'");
}
}
return retval;
} }
virtual std::string pretty_print() const
{
if (children.size() == 3)
{
return "(" + this->children[0]->pretty_print() + " " + this->children[1]->text + " " + this->children[2]->pretty_print() + ")";
} else {
return "(" + this->children[0]->pretty_print() + " " + text + " " + this->children[1]->pretty_print() + ")";
}
}
protected:
Boxed_Value do_oper(chaiscript::detail::Dispatch_Engine &t_ss,
Operators::Opers t_oper, const std::string &t_oper_string, const Boxed_Value &t_lhs, const Boxed_Value &t_rhs)
{
try {
chaiscript::eval::detail::Function_Push_Pop fpp(t_ss);
std::vector<Boxed_Value> params(2);
params.push_back(t_lhs);
params.push_back(t_rhs);
fpp.save_params(params);
if (t_oper != Operators::invalid && t_lhs.get_type_info().is_arithmetic() && t_rhs.get_type_info().is_arithmetic())
{
// If it's an arithmetic operation we want to short circuit dispatch
try{
return Boxed_Number::do_oper(t_oper, t_lhs, t_rhs);
} catch (...) {
throw exception::eval_error("Error with numeric operator calling: " + t_oper_string);
}
} else {
chaiscript::eval::detail::Stack_Push_Pop spp(t_ss);
return t_ss.call_function(t_oper_string, t_lhs, t_rhs);
}
}
catch(const exception::dispatch_error &e){
throw exception::eval_error("Can not find appropriate '" + t_oper_string + "' operator.", e.parameters, e.functions, false, t_ss);
}
}
}; };
struct Error_AST_Node : public AST_Node { struct Error_AST_Node : public AST_Node {
@@ -73,6 +103,9 @@ namespace chaiscript
Int_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Int, const boost::shared_ptr<std::string> &t_fname=boost::shared_ptr<std::string>(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : Int_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Int, const boost::shared_ptr<std::string> &t_fname=boost::shared_ptr<std::string>(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) :
AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col), AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col),
m_value(const_var(int(atoi(t_ast_node_text.c_str())))) { } m_value(const_var(int(atoi(t_ast_node_text.c_str())))) { }
Int_AST_Node(const std::string &t_ast_node_text, const Boxed_Value &t_bv, int t_id = AST_Node_Type::Int, const boost::shared_ptr<std::string> &t_fname=boost::shared_ptr<std::string>(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) :
AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col),
m_value(t_bv) { }
virtual ~Int_AST_Node() {} virtual ~Int_AST_Node() {}
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &){ virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &){
return m_value; return m_value;
@@ -88,6 +121,9 @@ namespace chaiscript
Float_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Float, const boost::shared_ptr<std::string> &t_fname=boost::shared_ptr<std::string>(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : Float_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Float, const boost::shared_ptr<std::string> &t_fname=boost::shared_ptr<std::string>(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) :
AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col), AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col),
m_value(const_var(double(atof(t_ast_node_text.c_str())))) { } m_value(const_var(double(atof(t_ast_node_text.c_str())))) { }
Float_AST_Node(const std::string &t_ast_node_text, const Boxed_Value &t_bv, int t_id = AST_Node_Type::Float, const boost::shared_ptr<std::string> &t_fname=boost::shared_ptr<std::string>(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) :
AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col),
m_value(t_bv) { }
virtual ~Float_AST_Node() {} virtual ~Float_AST_Node() {}
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &){ virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &){
return m_value; return m_value;
@@ -161,6 +197,11 @@ namespace chaiscript
Eol_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Eol, const boost::shared_ptr<std::string> &t_fname=boost::shared_ptr<std::string>(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : Eol_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Eol, const boost::shared_ptr<std::string> &t_fname=boost::shared_ptr<std::string>(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) :
AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { }
virtual ~Eol_AST_Node() {} virtual ~Eol_AST_Node() {}
virtual std::string pretty_print() const
{
return "\n";
}
}; };
struct Fun_Call_AST_Node : public AST_Node { struct Fun_Call_AST_Node : public AST_Node {
@@ -169,6 +210,7 @@ namespace chaiscript
AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { }
virtual ~Fun_Call_AST_Node() {} virtual ~Fun_Call_AST_Node() {}
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss){ virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss){
chaiscript::eval::detail::Function_Push_Pop fpp(t_ss);
dispatch::Param_List_Builder plb; dispatch::Param_List_Builder plb;
if ((this->children.size() > 1) && (this->children[1]->identifier == AST_Node_Type::Arg_List)) { if ((this->children.size() > 1) && (this->children[1]->identifier == AST_Node_Type::Arg_List)) {
@@ -177,36 +219,56 @@ namespace chaiscript
} }
} }
chaiscript::detail::Dispatch_Engine::Stack prev_stack = t_ss.get_stack(); fpp.save_params(plb.objects);
chaiscript::detail::Dispatch_Engine::Stack new_stack = t_ss.new_stack();
Boxed_Value fn = this->children[0]->eval(t_ss);
try { try {
Boxed_Value fn = this->children[0]->eval(t_ss); chaiscript::eval::detail::Stack_Push_Pop spp(t_ss);
const Boxed_Value &retval = (*boxed_cast<const Const_Proxy_Function &>(fn))(plb);
return retval;
}
catch(const exception::dispatch_error &e){
throw exception::eval_error(std::string(e.what()) + " with function '" + this->children[0]->text + "'", e.parameters, e.functions, false, t_ss);
}
catch(const exception::bad_boxed_cast &){
try { try {
t_ss.set_stack(new_stack); Const_Proxy_Function f = boxed_cast<const Const_Proxy_Function &>(fn);
const Boxed_Value &retval = (*boxed_cast<const Const_Proxy_Function &>(fn))(plb); // handle the case where there is only 1 function to try to call and dispatch fails on it
t_ss.set_stack(prev_stack); std::vector<Const_Proxy_Function> funcs;
return retval; funcs.push_back(f);
} throw exception::eval_error("Error calling function '" + this->children[0]->text + "'", plb.objects, funcs, false, t_ss);
catch(const exception::dispatch_error &e){ } catch (const exception::bad_boxed_cast &) {
t_ss.set_stack(prev_stack); throw exception::eval_error("'" + this->children[0]->pretty_print() + "' does not evaluate to a function.");
throw exception::eval_error(std::string(e.what()) + " with function '" + this->children[0]->text + "'");
}
catch(detail::Return_Value &rv) {
t_ss.set_stack(prev_stack);
return rv.retval;
}
catch(...) {
t_ss.set_stack(prev_stack);
throw;
} }
} }
catch(exception::eval_error &) { catch(const exception::arity_error &e){
t_ss.set_stack(prev_stack); throw exception::eval_error(std::string(e.what()) + " with function '" + this->children[0]->text + "'");
throw; }
catch(const exception::guard_error &e){
throw exception::eval_error(std::string(e.what()) + " with function '" + this->children[0]->text + "'");
}
catch(detail::Return_Value &rv) {
return rv.retval;
}
}
virtual std::string pretty_print() const
{
std::ostringstream oss;
for (unsigned int j = 0; j < this->children.size(); ++j) {
oss << this->children[j]->pretty_print();
if (j == 0)
{
oss << "(";
}
} }
oss << ")";
return oss.str();
} }
}; };
@@ -225,18 +287,53 @@ namespace chaiscript
} }
} }
Boxed_Value bv;
Const_Proxy_Function fn;
try { try {
return (*boxed_cast<const Const_Proxy_Function &>(this->children[0]->eval(t_ss)))(plb); bv = this->children[0]->eval(t_ss);
try {
fn = boxed_cast<const Const_Proxy_Function &>(bv);
} catch (const exception::bad_boxed_cast &) {
throw exception::eval_error("'" + this->children[0]->pretty_print() + "' does not evaluate to a function.");
}
return (*fn)(plb);
} }
catch(const exception::dispatch_error &e){ catch(const exception::dispatch_error &e){
throw exception::eval_error(std::string(e.what()) + " with function '" + this->children[0]->text + "'", e.parameters, e.functions, false, t_ss);
}
catch(const exception::bad_boxed_cast &){
// handle the case where there is only 1 function to try to call and dispatch fails on it
std::vector<Const_Proxy_Function> funcs;
funcs.push_back(fn);
throw exception::eval_error("Error calling function '" + this->children[0]->text + "'", plb.objects, funcs, false, t_ss);
}
catch(const exception::arity_error &e){
throw exception::eval_error(std::string(e.what()) + " with function '" + this->children[0]->text + "'");
}
catch(const exception::guard_error &e){
throw exception::eval_error(std::string(e.what()) + " with function '" + this->children[0]->text + "'"); throw exception::eval_error(std::string(e.what()) + " with function '" + this->children[0]->text + "'");
} }
catch(detail::Return_Value &rv) { catch(detail::Return_Value &rv) {
return rv.retval; return rv.retval;
} }
catch(...) { }
throw;
virtual std::string pretty_print() const
{
std::ostringstream oss;
for (unsigned int j = 0; j < this->children.size(); ++j) {
oss << this->children[j]->pretty_print();
if (j == 0)
{
oss << "(";
}
} }
oss << ")";
return oss.str();
} }
}; };
@@ -246,6 +343,21 @@ namespace chaiscript
Arg_List_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Arg_List, const boost::shared_ptr<std::string> &t_fname=boost::shared_ptr<std::string>(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : Arg_List_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Arg_List, const boost::shared_ptr<std::string> &t_fname=boost::shared_ptr<std::string>(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) :
AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { }
virtual ~Arg_List_AST_Node() {} virtual ~Arg_List_AST_Node() {}
virtual std::string pretty_print() const
{
std::ostringstream oss;
for (unsigned int j = 0; j < this->children.size(); ++j) {
if (j != 0)
{
oss << ", ";
}
oss << this->children[j]->pretty_print();
}
return oss.str();
}
}; };
struct Variable_AST_Node : public AST_Node { struct Variable_AST_Node : public AST_Node {
@@ -258,47 +370,56 @@ namespace chaiscript
struct Equation_AST_Node : public AST_Node { struct Equation_AST_Node : public AST_Node {
public: public:
Equation_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Equation, const boost::shared_ptr<std::string> &t_fname=boost::shared_ptr<std::string>(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : Equation_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Equation, const boost::shared_ptr<std::string> &t_fname=boost::shared_ptr<std::string>(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) :
AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col)
{}
virtual ~Equation_AST_Node() {} virtual ~Equation_AST_Node() {}
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss){ virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) {
Boxed_Value retval = this->children.back()->eval(t_ss); Boxed_Value retval = this->children.back()->eval(t_ss);
if (this->children.size() > 1) { if (this->children.size() > 1) {
for (int i = static_cast<int>(this->children.size())-3; i >= 0; i -= 2) { Boxed_Value lhs = this->children[0]->eval(t_ss);
if (this->children[i+1]->text == "=") {
Boxed_Value lhs = this->children[i]->eval(t_ss); Operators::Opers oper = Operators::to_operator(this->children[1]->text);
if (oper != Operators::invalid && lhs.get_type_info().is_arithmetic() &&
retval.get_type_info().is_arithmetic())
{
try {
retval = Boxed_Number::do_oper(oper, lhs, retval);
} catch (const std::exception &) {
throw exception::eval_error("Error with unsupported arithmetic assignment operation");
}
} else if (this->children[1]->text == "=") {
try {
if (lhs.is_undef()) {
retval = t_ss.call_function("clone", retval);
}
try { try {
if (lhs.is_undef()) { retval = t_ss.call_function(this->children[1]->text, lhs, retval);
retval = t_ss.call_function("clone", retval);
retval.clear_dependencies();
}
try {
retval = t_ss.call_function(this->children[i+1]->text, lhs, retval);
}
catch(const exception::dispatch_error &){
throw exception::eval_error(std::string("Mismatched types in equation") + (lhs.is_const()?", lhs is const.":"."));
}
} }
catch(const exception::dispatch_error &){ catch(const exception::dispatch_error &e){
throw exception::eval_error("Can not clone right hand side of equation"); throw exception::eval_error("Unable to find appropriate'" + this->children[1]->text + "' operator.", e.parameters, e.functions, false, t_ss);
} }
} }
else if (this->children[i+1]->text == ":=") { catch(const exception::dispatch_error &e){
Boxed_Value lhs = this->children[i]->eval(t_ss); throw exception::eval_error("Missing clone or copy constructor for right hand side of equation", e.parameters, e.functions, false, t_ss);
if (lhs.is_undef() || type_match(lhs, retval)) {
lhs.assign(retval);
} else {
throw exception::eval_error("Mismatched types in equation");
}
} }
else { }
try { else if (this->children[1]->text == ":=") {
retval = t_ss.call_function(this->children[i+1]->text, this->children[i]->eval(t_ss), retval); if (lhs.is_undef() || type_match(lhs, retval)) {
} catch(const exception::dispatch_error &){ lhs.assign(retval);
throw exception::eval_error("Can not find appropriate '" + this->children[i+1]->text + "'"); } else {
} throw exception::eval_error("Mismatched types in equation");
}
}
else {
try {
retval = t_ss.call_function(this->children[1]->text, lhs, retval);
} catch(const exception::dispatch_error &e){
throw exception::eval_error("Unable to find appropriate'" + this->children[1]->text + "' operator.", e.parameters, e.functions, false, t_ss);
} }
} }
} }
@@ -317,10 +438,17 @@ namespace chaiscript
} }
catch (const exception::reserved_word_error &) { catch (const exception::reserved_word_error &) {
throw exception::eval_error("Reserved word used as variable '" + this->children[0]->text + "'"); throw exception::eval_error("Reserved word used as variable '" + this->children[0]->text + "'");
} catch (const exception::name_conflict_error &e) {
throw exception::eval_error("Variable redefined '" + e.name() + "'");
} }
return t_ss.get_object(this->children[0]->text); return t_ss.get_object(this->children[0]->text);
} }
virtual std::string pretty_print() const
{
return "var " + this->children[0]->text;
}
}; };
struct Comparison_AST_Node : public Binary_Operator_AST_Node { struct Comparison_AST_Node : public Binary_Operator_AST_Node {
@@ -330,18 +458,64 @@ namespace chaiscript
virtual ~Comparison_AST_Node() {} virtual ~Comparison_AST_Node() {}
}; };
struct Additive_AST_Node : public Binary_Operator_AST_Node { struct Addition_AST_Node : public Binary_Operator_AST_Node {
public: public:
Additive_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Additive, const boost::shared_ptr<std::string> &t_fname=boost::shared_ptr<std::string>(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : Addition_AST_Node(const std::string &t_ast_node_text = "+", int t_id = AST_Node_Type::Addition,
const boost::shared_ptr<std::string> &t_fname=boost::shared_ptr<std::string>(),
int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) :
Binary_Operator_AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } Binary_Operator_AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { }
virtual ~Additive_AST_Node() {} virtual ~Addition_AST_Node() {}
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) {
return do_oper(t_ss, Operators::sum, "+", this->children[0]->eval(t_ss), this->children[1]->eval(t_ss));
}
}; };
struct Multiplicative_AST_Node : public Binary_Operator_AST_Node { struct Subtraction_AST_Node : public Binary_Operator_AST_Node {
public: public:
Multiplicative_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Multiplicative, const boost::shared_ptr<std::string> &t_fname=boost::shared_ptr<std::string>(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : Subtraction_AST_Node(const std::string &t_ast_node_text = "-", int t_id = AST_Node_Type::Subtraction,
const boost::shared_ptr<std::string> &t_fname=boost::shared_ptr<std::string>(), int t_start_line = 0,
int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) :
Binary_Operator_AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } Binary_Operator_AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { }
virtual ~Multiplicative_AST_Node() {} virtual ~Subtraction_AST_Node() {}
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) {
return do_oper(t_ss, Operators::difference, "-", this->children[0]->eval(t_ss), this->children[1]->eval(t_ss));
}
};
struct Multiplication_AST_Node : public Binary_Operator_AST_Node {
public:
Multiplication_AST_Node(const std::string &t_ast_node_text = "*", int t_id = AST_Node_Type::Multiplication,
const boost::shared_ptr<std::string> &t_fname=boost::shared_ptr<std::string>(), int t_start_line = 0,
int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) :
Binary_Operator_AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { }
virtual ~Multiplication_AST_Node() {}
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) {
return do_oper(t_ss, Operators::product, "*", this->children[0]->eval(t_ss), this->children[1]->eval(t_ss));
}
};
struct Division_AST_Node : public Binary_Operator_AST_Node {
public:
Division_AST_Node(const std::string &t_ast_node_text = "/", int t_id = AST_Node_Type::Division,
const boost::shared_ptr<std::string> &t_fname=boost::shared_ptr<std::string>(), int t_start_line = 0,
int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) :
Binary_Operator_AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { }
virtual ~Division_AST_Node() {}
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) {
return do_oper(t_ss, Operators::quotient, "/", this->children[0]->eval(t_ss), this->children[1]->eval(t_ss));
}
};
struct Modulus_AST_Node : public Binary_Operator_AST_Node {
public:
Modulus_AST_Node(const std::string &t_ast_node_text = "%", int t_id = AST_Node_Type::Modulus,
const boost::shared_ptr<std::string> &t_fname=boost::shared_ptr<std::string>(), int t_start_line = 0,
int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) :
Binary_Operator_AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { }
virtual ~Modulus_AST_Node() {}
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) {
return do_oper(t_ss, Operators::remainder, "%", this->children[0]->eval(t_ss), this->children[1]->eval(t_ss));
}
}; };
struct Array_Call_AST_Node : public AST_Node { struct Array_Call_AST_Node : public AST_Node {
@@ -350,22 +524,46 @@ namespace chaiscript
AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { }
virtual ~Array_Call_AST_Node() {} virtual ~Array_Call_AST_Node() {}
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss){ virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss){
chaiscript::eval::detail::Function_Push_Pop fpp(t_ss);
Boxed_Value retval = this->children[0]->eval(t_ss); Boxed_Value retval = this->children[0]->eval(t_ss);
std::vector<Boxed_Value> params;
params.push_back(retval);
for (size_t i = 1; i < this->children.size(); ++i) { for (size_t i = 1; i < this->children.size(); ++i) {
try { try {
retval = t_ss.call_function("[]", retval, this->children[i]->eval(t_ss)); Boxed_Value p1(this->children[i]->eval(t_ss));
chaiscript::eval::detail::Stack_Push_Pop spp(t_ss);
params.push_back(p1);
fpp.save_params(params);
params.clear();
retval = t_ss.call_function("[]", retval, p1);
} }
catch(std::out_of_range &) { catch(std::out_of_range &) {
throw exception::eval_error("Out of bounds exception"); throw exception::eval_error("Out of bounds exception");
} }
catch(const exception::dispatch_error &){ catch(const exception::dispatch_error &e){
throw exception::eval_error("Can not find appropriate array lookup '[]' "); throw exception::eval_error("Can not find appropriate array lookup operator '[]'.", e.parameters, e.functions, false, t_ss );
} }
} }
return retval; return retval;
} }
virtual std::string pretty_print() const
{
std::ostringstream oss;
oss << this->children[0]->pretty_print();
for (size_t i = 1; i < this->children.size(); ++i)
{
oss << "[";
oss << this->children[i]->pretty_print();
oss << "]";
}
return oss.str();
}
}; };
struct Dot_Access_AST_Node : public AST_Node { struct Dot_Access_AST_Node : public AST_Node {
@@ -378,6 +576,7 @@ namespace chaiscript
if (this->children.size() > 1) { if (this->children.size() > 1) {
for (size_t i = 2; i < this->children.size(); i+=2) { for (size_t i = 2; i < this->children.size(); i+=2) {
chaiscript::eval::detail::Function_Push_Pop fpp(t_ss);
dispatch::Param_List_Builder plb; dispatch::Param_List_Builder plb;
plb << retval; plb << retval;
@@ -387,6 +586,8 @@ namespace chaiscript
} }
} }
fpp.save_params(plb.objects);
std::string fun_name; std::string fun_name;
if ((this->children[i]->identifier == AST_Node_Type::Fun_Call) || (this->children[i]->identifier == AST_Node_Type::Array_Call)) { if ((this->children[i]->identifier == AST_Node_Type::Fun_Call) || (this->children[i]->identifier == AST_Node_Type::Array_Call)) {
fun_name = this->children[i]->children[0]->text; fun_name = this->children[i]->children[0]->text;
@@ -395,26 +596,22 @@ namespace chaiscript
fun_name = this->children[i]->text; fun_name = this->children[i]->text;
} }
chaiscript::detail::Dispatch_Engine::Stack prev_stack = t_ss.get_stack();
chaiscript::detail::Dispatch_Engine::Stack new_stack = t_ss.new_stack();
try { try {
t_ss.set_stack(new_stack); chaiscript::eval::detail::Stack_Push_Pop spp(t_ss);
retval = t_ss.call_function(fun_name, plb); retval = t_ss.call_function(fun_name, plb);
t_ss.set_stack(prev_stack);
} }
catch(const exception::dispatch_error &e){ catch(const exception::dispatch_error &e){
t_ss.set_stack(prev_stack); if (e.functions.empty())
throw exception::eval_error(std::string(e.what()) + " for function: " + fun_name); {
throw exception::eval_error("'" + fun_name + "' is not a function.");
} else {
throw exception::eval_error(std::string(e.what()) + " for function '" + fun_name + "'", e.parameters, e.functions, true, t_ss);
}
} }
catch(detail::Return_Value &rv) { catch(detail::Return_Value &rv) {
t_ss.set_stack(prev_stack);
retval = rv.retval; retval = rv.retval;
} }
catch(...) {
t_ss.set_stack(prev_stack);
throw;
}
if (this->children[i]->identifier == AST_Node_Type::Array_Call) { if (this->children[i]->identifier == AST_Node_Type::Array_Call) {
for (size_t j = 1; j < this->children[i]->children.size(); ++j) { for (size_t j = 1; j < this->children[i]->children.size(); ++j) {
try { try {
@@ -423,8 +620,8 @@ namespace chaiscript
catch(std::out_of_range &) { catch(std::out_of_range &) {
throw exception::eval_error("Out of bounds exception"); throw exception::eval_error("Out of bounds exception");
} }
catch(const exception::dispatch_error &){ catch(const exception::dispatch_error &e){
throw exception::eval_error("Can not find appropriate array lookup '[]' "); throw exception::eval_error("Can not find appropriate array lookup operator '[]'.", e.parameters, e.functions, true, t_ss);
} }
} }
} }
@@ -446,6 +643,11 @@ namespace chaiscript
return m_value; return m_value;
} }
virtual std::string pretty_print() const
{
return "\"" + text + "\"";
}
private: private:
Boxed_Value m_value; Boxed_Value m_value;
@@ -461,6 +663,11 @@ namespace chaiscript
return m_value; return m_value;
} }
virtual std::string pretty_print() const
{
return "'" + text + "'";
}
private: private:
Boxed_Value m_value; Boxed_Value m_value;
}; };
@@ -570,6 +777,8 @@ namespace chaiscript
} }
catch (const exception::reserved_word_error &e) { catch (const exception::reserved_word_error &e) {
throw exception::eval_error("Reserved word used as function name '" + e.word() + "'"); throw exception::eval_error("Reserved word used as function name '" + e.word() + "'");
} catch (const exception::name_conflict_error &e) {
throw exception::eval_error("Function redefined '" + e.name() + "'");
} }
return Boxed_Value(); return Boxed_Value();
} }
@@ -612,6 +821,29 @@ namespace chaiscript
}; };
struct Ternary_Cond_AST_Node : public AST_Node {
public:
Ternary_Cond_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::If, const boost::shared_ptr<std::string> &t_fname=boost::shared_ptr<std::string>(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) :
AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { }
virtual ~Ternary_Cond_AST_Node() {}
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss){
bool cond;
try {
cond = boxed_cast<bool>(this->children[0]->eval(t_ss));
}
catch (const exception::bad_boxed_cast &) {
throw exception::eval_error("If condition not boolean");
}
if (cond) {
return this->children[1]->eval(t_ss);
}
else {
return this->children[2]->eval(t_ss);
}
}
};
struct If_AST_Node : public AST_Node { struct If_AST_Node : public AST_Node {
public: public:
If_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::If, const boost::shared_ptr<std::string> &t_fname=boost::shared_ptr<std::string>(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : If_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::If, const boost::shared_ptr<std::string> &t_fname=boost::shared_ptr<std::string>(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) :
@@ -707,20 +939,97 @@ namespace chaiscript
}; };
struct Switch_AST_Node : public AST_Node {
public:
Switch_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Switch, const boost::shared_ptr<std::string> &t_fname=boost::shared_ptr<std::string>(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) :
AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { }
virtual ~Switch_AST_Node() {}
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) {
Boxed_Value match_value;
bool breaking = false;
size_t currentCase = 1;
bool hasMatched = false;
chaiscript::eval::detail::Scope_Push_Pop spp(t_ss);
match_value = this->children[0]->eval(t_ss);
while (!breaking && (currentCase < this->children.size())) {
try {
if (this->children[currentCase]->identifier == AST_Node_Type::Case) {
//This is a little odd, but because want to see both the switch and the case simultaneously, I do a downcast here.
try {
if (hasMatched || boxed_cast<bool>(t_ss.call_function("==", match_value, this->children[currentCase]->children[0]->eval(t_ss)))) {
this->children[currentCase]->eval(t_ss);
hasMatched = true;
}
}
catch (const exception::bad_boxed_cast &) {
throw exception::eval_error("Internal error: case guard evaluation not boolean");
}
}
else if (this->children[currentCase]->identifier == AST_Node_Type::Default) {
this->children[currentCase]->eval(t_ss);
breaking = true;
}
}
catch (detail::Break_Loop &) {
breaking = true;
}
++currentCase;
}
return Boxed_Value();
}
};
struct Case_AST_Node : public AST_Node {
public:
Case_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Case, const boost::shared_ptr<std::string> &t_fname=boost::shared_ptr<std::string>(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) :
AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { }
virtual ~Case_AST_Node() {}
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) {
chaiscript::eval::detail::Scope_Push_Pop spp(t_ss);
this->children[1]->eval(t_ss);
return Boxed_Value();
}
};
struct Default_AST_Node : public AST_Node {
public:
Default_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Default, const boost::shared_ptr<std::string> &t_fname=boost::shared_ptr<std::string>(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) :
AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { }
virtual ~Default_AST_Node() {}
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) {
chaiscript::eval::detail::Scope_Push_Pop spp(t_ss);
this->children[0]->eval(t_ss);
return Boxed_Value();
}
};
struct Inline_Array_AST_Node : public AST_Node { struct Inline_Array_AST_Node : public AST_Node {
public: public:
Inline_Array_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Inline_Array, const boost::shared_ptr<std::string> &t_fname=boost::shared_ptr<std::string>(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : Inline_Array_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Inline_Array, const boost::shared_ptr<std::string> &t_fname=boost::shared_ptr<std::string>(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) :
AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { }
virtual ~Inline_Array_AST_Node() {} virtual ~Inline_Array_AST_Node() {}
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss){ virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss){
std::vector<Boxed_Value> vec; try {
if (this->children.size() > 0) { std::vector<Boxed_Value> vec;
for (size_t i = 0; i < this->children[0]->children.size(); ++i) { if (this->children.size() > 0) {
vec.push_back(this->children[0]->children[i]->eval(t_ss)); for (size_t i = 0; i < this->children[0]->children.size(); ++i) {
Boxed_Value bv = t_ss.call_function("clone", this->children[0]->children[i]->eval(t_ss));
vec.push_back(bv);
}
} }
return const_var(vec);
}
catch (const exception::dispatch_error &) {
throw exception::eval_error("Can not find appropriate 'clone' or copy constructor for vector elements");
} }
return const_var(vec);
} }
}; };
@@ -734,13 +1043,14 @@ namespace chaiscript
try { try {
std::map<std::string, Boxed_Value> retval; std::map<std::string, Boxed_Value> retval;
for (size_t i = 0; i < this->children[0]->children.size(); ++i) { for (size_t i = 0; i < this->children[0]->children.size(); ++i) {
Boxed_Value bv = t_ss.call_function("clone", this->children[0]->children[i]->children[1]->eval(t_ss));
retval[boxed_cast<std::string>(this->children[0]->children[i]->children[0]->eval(t_ss))] retval[boxed_cast<std::string>(this->children[0]->children[i]->children[0]->eval(t_ss))]
= t_ss.call_function("clone", this->children[0]->children[i]->children[1]->eval(t_ss)); = bv;
} }
return const_var(retval); return const_var(retval);
} }
catch (const exception::dispatch_error &) { catch (const exception::dispatch_error &e) {
throw exception::eval_error("Can not find appropriate 'Map()'"); throw exception::eval_error("Can not find appropriate copy constructor or 'clone' while inserting into Map.", e.parameters, e.functions, false, t_ss);
} }
} }
@@ -782,10 +1092,29 @@ namespace chaiscript
struct Prefix_AST_Node : public AST_Node { struct Prefix_AST_Node : public AST_Node {
public: public:
Prefix_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Prefix, const boost::shared_ptr<std::string> &t_fname=boost::shared_ptr<std::string>(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : Prefix_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Prefix, const boost::shared_ptr<std::string> &t_fname=boost::shared_ptr<std::string>(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) :
AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col)
{ }
virtual ~Prefix_AST_Node() {} virtual ~Prefix_AST_Node() {}
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss){ virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss){
return t_ss.call_function(this->children[0]->text, this->children[1]->eval(t_ss)); chaiscript::eval::detail::Function_Push_Pop fpp(t_ss);
Boxed_Value bv(this->children[1]->eval(t_ss));
Operators::Opers oper = Operators::to_operator(children[0]->text, true);
try {
if (bv.get_type_info().is_arithmetic() && oper != Operators::invalid)
{
return Boxed_Number::do_oper(oper, bv);
} else {
chaiscript::eval::detail::Stack_Push_Pop spp(t_ss);
std::vector<Boxed_Value> params;
params.push_back(bv);
fpp.save_params(params);
return t_ss.call_function(this->children[0]->text, bv);
}
} catch (const exception::dispatch_error &e) {
throw exception::eval_error("Error with prefix operator evaluation: '" + children[0]->text + "'", e.parameters, e.functions, false, t_ss);
}
} }
}; };
@@ -825,8 +1154,8 @@ namespace chaiscript
this->children[0]->children[0]->children[0]->eval(t_ss), this->children[0]->children[0]->children[0]->eval(t_ss),
this->children[0]->children[0]->children[1]->eval(t_ss)); this->children[0]->children[0]->children[1]->eval(t_ss));
} }
catch (const exception::dispatch_error &) { catch (const exception::dispatch_error &e) {
throw exception::eval_error("Unable to generate range vector"); throw exception::eval_error("Unable to generate range vector, while calling 'generate_range'", e.parameters, e.functions, false, t_ss);
} }
} }
@@ -867,6 +1196,7 @@ namespace chaiscript
end_point = this->children.size() - 1; end_point = this->children.size() - 1;
} }
for (unsigned int i = 1; i < end_point; ++i) { for (unsigned int i = 1; i < end_point; ++i) {
chaiscript::eval::detail::Scope_Push_Pop catchscope(t_ss);
AST_NodePtr catch_block = this->children[i]; AST_NodePtr catch_block = this->children[i];
if (catch_block->children.size() == 1) { if (catch_block->children.size() == 1) {
@@ -909,6 +1239,7 @@ namespace chaiscript
} }
catch (Boxed_Value &except) { catch (Boxed_Value &except) {
for (size_t i = 1; i < this->children.size(); ++i) { for (size_t i = 1; i < this->children.size(); ++i) {
chaiscript::eval::detail::Scope_Push_Pop catchscope(t_ss);
AST_NodePtr catch_block = this->children[i]; AST_NodePtr catch_block = this->children[i];
if (catch_block->children.size() == 1) { if (catch_block->children.size() == 1) {
@@ -923,7 +1254,7 @@ namespace chaiscript
break; break;
} }
else if (catch_block->children.size() == 3) { else if (catch_block->children.size() == 3) {
//Variable capture, no guards //Variable capture, guards
t_ss.add_object(catch_block->children[0]->text, except); t_ss.add_object(catch_block->children[0]->text, except);
bool guard; bool guard;
@@ -1051,6 +1382,8 @@ namespace chaiscript
} }
catch (const exception::reserved_word_error &e) { catch (const exception::reserved_word_error &e) {
throw exception::eval_error("Reserved word used as method name '" + e.word() + "'"); throw exception::eval_error("Reserved word used as method name '" + e.word() + "'");
} catch (const exception::name_conflict_error &e) {
throw exception::eval_error("Method redefined '" + e.name() + "'");
} }
return Boxed_Value(); return Boxed_Value();
} }
@@ -1064,12 +1397,22 @@ namespace chaiscript
virtual ~Attr_Decl_AST_Node() {} virtual ~Attr_Decl_AST_Node() {}
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss){ virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss){
try { try {
t_ss.add(fun(boost::function<Boxed_Value (dispatch::Dynamic_Object &)>(boost::bind(&dispatch::detail::Dynamic_Object_Attribute::func, this->children[0]->text,
this->children[1]->text, _1))), this->children[1]->text); t_ss.add(Proxy_Function
(new dispatch::detail::Dynamic_Object_Function(
this->children[0]->text,
fun(boost::function<Boxed_Value (dispatch::Dynamic_Object &)>(boost::bind(&dispatch::Dynamic_Object::get_attr,
_1,
this->children[1]->text
)))
)
), this->children[1]->text);
} }
catch (const exception::reserved_word_error &) { catch (const exception::reserved_word_error &) {
throw exception::eval_error("Reserved word used as attribute '" + this->children[1]->text + "'"); throw exception::eval_error("Reserved word used as attribute '" + this->children[1]->text + "'");
} catch (const exception::name_conflict_error &e) {
throw exception::eval_error("Attribute redefined '" + e.name() + "'");
} }
return Boxed_Value(); return Boxed_Value();
} }
@@ -1138,6 +1481,11 @@ namespace chaiscript
} }
return retval; return retval;
} }
virtual std::string pretty_print() const
{
return "(" + AST_Node::pretty_print() + ")";
}
}; };
struct Logical_Or_AST_Node : public AST_Node { struct Logical_Or_AST_Node : public AST_Node {
@@ -1165,6 +1513,11 @@ namespace chaiscript
return retval; return retval;
} }
virtual std::string pretty_print() const
{
return "(" + AST_Node::pretty_print() + ")";
}
}; };
} }

View File

@@ -1,6 +1,6 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2011, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// and Jason Turner (jason@emptycrate.com) // and Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
@@ -33,6 +33,8 @@ namespace chaiscript
, bin_alphabet , bin_alphabet
, id_alphabet , id_alphabet
, white_alphabet , white_alphabet
, int_suffix_alphabet
, float_suffix_alphabet
, max_alphabet , max_alphabet
, lengthof_alphabet = 256 , lengthof_alphabet = 256
}; };
@@ -66,6 +68,11 @@ namespace chaiscript
void setup_operators() 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); m_operators.push_back(AST_Node_Type::Logical_Or);
std::vector<std::string> logical_or; std::vector<std::string> logical_or;
logical_or.push_back("||"); logical_or.push_back("||");
@@ -111,29 +118,27 @@ namespace chaiscript
shift.push_back(">>"); shift.push_back(">>");
m_operator_matches.push_back(shift); m_operator_matches.push_back(shift);
m_operators.push_back(AST_Node_Type::Additive); //We share precedence here but then separate them later
std::vector<std::string> additive; m_operators.push_back(AST_Node_Type::Addition);
additive.push_back("+"); std::vector<std::string> addition;
additive.push_back("-"); addition.push_back("+");
m_operator_matches.push_back(additive); addition.push_back("-");
m_operator_matches.push_back(addition);
m_operators.push_back(AST_Node_Type::Multiplicative); //We share precedence here but then separate them later
std::vector<std::string> multiplicative; m_operators.push_back(AST_Node_Type::Multiplication);
multiplicative.push_back("*"); std::vector<std::string> multiplication;
multiplicative.push_back("/"); multiplication.push_back("*");
multiplicative.push_back("%"); multiplication.push_back("/");
m_operator_matches.push_back(multiplicative); multiplication.push_back("%");
m_operator_matches.push_back(multiplication);
m_operators.push_back(AST_Node_Type::Dot_Access);
std::vector<std::string> dot_access;
dot_access.push_back(".");
m_operator_matches.push_back(dot_access);
for ( int c = 0 ; c < detail::lengthof_alphabet ; ++c ) { for ( int c = 0 ; c < detail::lengthof_alphabet ; ++c ) {
for ( int a = 0 ; a < detail::max_alphabet ; a ++ ) { for ( int a = 0 ; a < detail::max_alphabet ; a ++ ) {
m_alphabet[a][c]=false; 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; 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;
@@ -172,6 +177,17 @@ namespace chaiscript
m_alphabet[detail::white_alphabet][static_cast<int>(' ')]=true; m_alphabet[detail::white_alphabet][static_cast<int>(' ')]=true;
m_alphabet[detail::white_alphabet][static_cast<int>('\t')]=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;
} }
/** /**
@@ -249,7 +265,7 @@ namespace chaiscript
m_match_stack.push_back(t_t); m_match_stack.push_back(t_t);
} }
else { else {
//todo: fix the fact that a successful match that captured no ast_nodes doesn't have any real start position /// \todo fix the fact that a successful match that captured no ast_nodes doesn't have any real start position
m_match_stack.push_back(t_t); m_match_stack.push_back(t_t);
} }
} }
@@ -325,7 +341,6 @@ namespace chaiscript
*/ */
bool Float_() { bool Float_() {
bool retval = false; bool retval = false;
std::string::const_iterator start = m_input_pos;
if (has_more_input() && char_in_alphabet(*m_input_pos,detail::float_alphabet) ) { 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) ) { while (has_more_input() && char_in_alphabet(*m_input_pos,detail::int_alphabet) ) {
@@ -341,6 +356,12 @@ namespace chaiscript
++m_input_pos; ++m_input_pos;
++m_col; ++m_col;
} }
while (has_more_input() && char_in_alphabet(*m_input_pos, detail::float_suffix_alphabet))
{
++m_input_pos;
++m_col;
}
} }
else { else {
--m_input_pos; --m_input_pos;
@@ -352,7 +373,7 @@ namespace chaiscript
} }
/** /**
* Reads a floating point value from input, without skipping initial whitespace * Reads a hex value from input, without skipping initial whitespace
*/ */
bool Hex_() { bool Hex_() {
bool retval = false; bool retval = false;
@@ -369,6 +390,11 @@ namespace chaiscript
++m_input_pos; ++m_input_pos;
++m_col; ++m_col;
} }
while (has_more_input() && char_in_alphabet(*m_input_pos, detail::int_suffix_alphabet))
{
++m_input_pos;
++m_col;
}
} }
else { else {
--m_input_pos; --m_input_pos;
@@ -384,8 +410,16 @@ namespace chaiscript
return retval; 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 floating point value from input, without skipping initial whitespace * Reads a binary value from input, without skipping initial whitespace
*/ */
bool Binary_() { bool Binary_() {
bool retval = false; bool retval = false;
@@ -417,6 +451,173 @@ namespace chaiscript
return retval; 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 * Reads a number from the input, detecting if it's an integer or floating point
*/ */
@@ -433,19 +634,14 @@ namespace chaiscript
if (has_more_input() && char_in_alphabet(*m_input_pos, detail::float_alphabet) ) { if (has_more_input() && char_in_alphabet(*m_input_pos, detail::float_alphabet) ) {
if (Hex_()) { if (Hex_()) {
std::string match(start, m_input_pos); std::string match(start, m_input_pos);
std::stringstream ss(match); Boxed_Value i = buildInt(std::hex, match);
unsigned int temp_int; AST_NodePtr t(new eval::Int_AST_Node(match, i, AST_Node_Type::Int, m_filename, prev_line, prev_col, m_line, m_col));
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));
m_match_stack.push_back(t); m_match_stack.push_back(t);
return true; return true;
} }
if (Binary_()) { if (Binary_()) {
std::string match(start, m_input_pos); std::string match(start, m_input_pos);
int temp_int = 0; boost::int64_t temp_int = 0;
size_t pos = 0, end = match.length(); size_t pos = 0, end = match.length();
while ((pos < end) && (pos < (2 + sizeof(int) * 8))) { while ((pos < end) && (pos < (2 + sizeof(int) * 8))) {
@@ -456,32 +652,36 @@ namespace chaiscript
++pos; ++pos;
} }
std::ostringstream out_int; Boxed_Value i;
out_int << temp_int; if (match.length() <= sizeof(int) * 8)
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)); {
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, AST_Node_Type::Int, m_filename, prev_line, prev_col, m_line, m_col));
m_match_stack.push_back(t); m_match_stack.push_back(t);
return true; return true;
} }
if (Float_()) { if (Float_()) {
std::string match(start, m_input_pos); 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, AST_Node_Type::Float, m_filename, prev_line, prev_col, m_line, m_col));
m_match_stack.push_back(t); m_match_stack.push_back(t);
return true; return true;
} }
else { else {
IntSuffix_();
std::string match(start, m_input_pos); std::string match(start, m_input_pos);
if ((match.size() > 0) && (match[0] == '0')) { if ((match.size() > 0) && (match[0] == '0')) {
std::stringstream ss(match); Boxed_Value i = buildInt(std::oct, match);
unsigned int temp_int; AST_NodePtr t(new eval::Int_AST_Node(match, i, AST_Node_Type::Int, m_filename, prev_line, prev_col, m_line, m_col));
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));
m_match_stack.push_back(t); m_match_stack.push_back(t);
} }
else { 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, AST_Node_Type::Int, m_filename, prev_line, prev_col, m_line, m_col));
m_match_stack.push_back(t); m_match_stack.push_back(t);
} }
return true; return true;
@@ -655,7 +855,6 @@ namespace chaiscript
bool saw_interpolation_marker = false; bool saw_interpolation_marker = false;
size_t prev_stack_top = m_match_stack.size(); size_t prev_stack_top = m_match_stack.size();
//for (std::string::iterator s = start + 1, end = m_input_pos - 1; s != end; ++s) {
std::string::const_iterator s = start + 1, end = m_input_pos - 1; std::string::const_iterator s = start + 1, end = m_input_pos - 1;
while (s != end) { while (s != end) {
@@ -665,13 +864,11 @@ namespace chaiscript
if (is_interpolated) { if (is_interpolated) {
//If we've seen previous interpolation, add on instead of making a new one //If we've seen previous interpolation, add on instead of making a new one
AST_NodePtr plus(new eval::Str_AST_Node("+", AST_Node_Type::Str, m_filename, prev_line, prev_col, m_line, m_col));
m_match_stack.push_back(plus);
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, AST_Node_Type::Quoted_String, m_filename, prev_line, prev_col, m_line, m_col));
m_match_stack.push_back(t); m_match_stack.push_back(t);
build_match(AST_NodePtr(new eval::Additive_AST_Node()), prev_stack_top); build_match(AST_NodePtr(new eval::Addition_AST_Node()), prev_stack_top);
} }
else { 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, AST_Node_Type::Quoted_String, m_filename, prev_line, prev_col, m_line, m_col));
@@ -681,9 +878,6 @@ namespace chaiscript
//We've finished with the part of the string up to this point, so clear it //We've finished with the part of the string up to this point, so clear it
match = ""; match = "";
AST_NodePtr plus(new eval::Str_AST_Node("+", AST_Node_Type::Str, m_filename, prev_line, prev_col, m_line, m_col));
m_match_stack.push_back(plus);
std::string eval_match; std::string eval_match;
++s; ++s;
@@ -718,7 +912,7 @@ namespace chaiscript
build_match(AST_NodePtr(new eval::Fun_Call_AST_Node()), tostr_stack_top); build_match(AST_NodePtr(new eval::Fun_Call_AST_Node()), tostr_stack_top);
build_match(AST_NodePtr(new eval::Additive_AST_Node()), prev_stack_top); build_match(AST_NodePtr(new eval::Addition_AST_Node()), prev_stack_top);
} }
else { else {
throw exception::eval_error("Unclosed in-string eval", File_Position(prev_line, prev_col), *m_filename); throw exception::eval_error("Unclosed in-string eval", File_Position(prev_line, prev_col), *m_filename);
@@ -765,13 +959,10 @@ namespace chaiscript
} }
} }
if (is_interpolated) { if (is_interpolated) {
AST_NodePtr plus(new eval::Str_AST_Node("+", AST_Node_Type::Str, m_filename, prev_line, prev_col, m_line, m_col));
m_match_stack.push_back(plus);
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, AST_Node_Type::Quoted_String, m_filename, prev_line, prev_col, m_line, m_col));
m_match_stack.push_back(t); m_match_stack.push_back(t);
build_match(AST_NodePtr(new eval::Additive_AST_Node()), prev_stack_top); build_match(AST_NodePtr(new eval::Addition_AST_Node()), prev_stack_top);
} }
else { 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, AST_Node_Type::Quoted_String, m_filename, prev_line, prev_col, m_line, m_col));
@@ -1428,6 +1619,90 @@ namespace chaiscript
return retval; 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 * Reads a curly-brace C-style block from input
*/ */
@@ -1486,14 +1761,14 @@ namespace chaiscript
} }
/** /**
* Reads an identifier, then proceeds to check if it's a function or array call * Reads a dot expression(member access), then proceeds to check if it's a function or array call
*/ */
bool Id_Fun_Array() { bool Dot_Fun_Array() {
bool retval = false; bool retval = false;
std::string::const_iterator prev_pos = m_input_pos;
size_t prev_stack_top = m_match_stack.size(); size_t prev_stack_top = m_match_stack.size();
if (Id(true)) { if (Lambda() || Num(true) || Quoted_String(true) || Single_Quoted_String(true) ||
Paren_Expression() || Inline_Container() || Id(true)) {
retval = true; retval = true;
bool has_more = true; bool has_more = true;
@@ -1509,6 +1784,19 @@ namespace chaiscript
} }
build_match(AST_NodePtr(new eval::Fun_Call_AST_Node()), prev_stack_top); build_match(AST_NodePtr(new eval::Fun_Call_AST_Node()), prev_stack_top);
/// \todo Work around for method calls until we have a better solution
if (!m_match_stack.back()->children.empty()) {
if (m_match_stack.back()->children[0]->identifier == AST_Node_Type::Dot_Access) {
AST_NodePtr dot_access = m_match_stack.back()->children[0];
AST_NodePtr func_call = m_match_stack.back();
m_match_stack.pop_back();
func_call->children.erase(func_call->children.begin());
func_call->children.insert(func_call->children.begin(), dot_access->children.back());
dot_access->children.pop_back();
dot_access->children.push_back(func_call);
m_match_stack.push_back(dot_access);
}
}
} }
else if (Char('[')) { else if (Char('[')) {
has_more = true; has_more = true;
@@ -1519,6 +1807,14 @@ namespace chaiscript
build_match(AST_NodePtr(new eval::Array_Call_AST_Node()), prev_stack_top); build_match(AST_NodePtr(new eval::Array_Call_AST_Node()), prev_stack_top);
} }
else if (Symbol(".", true)) {
has_more = true;
if (!(Id(true))) {
throw exception::eval_error("Incomplete array access", File_Position(m_line, m_col), *m_filename);
}
build_match(AST_NodePtr(new eval::Dot_Access_AST_Node()), prev_stack_top);
}
} }
} }
@@ -1574,7 +1870,7 @@ namespace chaiscript
throw exception::eval_error("Incomplete expression", File_Position(m_line, m_col), *m_filename); throw exception::eval_error("Incomplete expression", File_Position(m_line, m_col), *m_filename);
} }
if (!Char(')')) { 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; return retval;
@@ -1592,7 +1888,7 @@ namespace chaiscript
retval = true; retval = true;
Container_Arg_List(); Container_Arg_List();
if (!Char(']')) { 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 ((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) { if (m_match_stack.back()->children[0]->identifier == AST_Node_Type::Value_Range) {
@@ -1683,8 +1979,7 @@ namespace chaiscript
* Parses any of a group of 'value' style ast_node groups from input * Parses any of a group of 'value' style ast_node groups from input
*/ */
bool Value() { bool Value() {
if (Var_Decl() || Lambda() || Id_Fun_Array() || Num(true) || Prefix() || Quoted_String(true) || Single_Quoted_String(true) || if (Var_Decl() || Dot_Fun_Array() || Prefix()) {
Paren_Expression() || Inline_Container()) {
return true; return true;
} }
else { else {
@@ -1703,7 +1998,7 @@ namespace chaiscript
bool Operator(size_t t_precedence = 0) { bool Operator(size_t t_precedence = 0) {
bool retval = false; bool retval = false;
AST_NodePtr oper;
size_t prev_stack_top = m_match_stack.size(); size_t prev_stack_top = m_match_stack.size();
if (t_precedence < m_operators.size()) { if (t_precedence < m_operators.size()) {
@@ -1711,50 +2006,84 @@ namespace chaiscript
retval = true; retval = true;
if (Operator_Helper(t_precedence)) { if (Operator_Helper(t_precedence)) {
do { do {
while (Eol()) {}
if (!Operator(t_precedence+1)) { if (!Operator(t_precedence+1)) {
throw exception::eval_error("Incomplete " throw exception::eval_error("Incomplete "
+ std::string(ast_node_type_to_string(m_operators[t_precedence])) + " expression", + std::string(ast_node_type_to_string(m_operators[t_precedence])) + " expression",
File_Position(m_line, m_col), *m_filename); File_Position(m_line, m_col), *m_filename);
} }
} while (Operator_Helper(t_precedence));
switch (m_operators[t_precedence]) { switch (m_operators[t_precedence]) {
case(AST_Node_Type::Comparison) : case(AST_Node_Type::Comparison) :
build_match(AST_NodePtr(new eval::Comparison_AST_Node()), prev_stack_top); build_match(AST_NodePtr(new eval::Comparison_AST_Node()), prev_stack_top);
break; break;
case(AST_Node_Type::Dot_Access) : case(AST_Node_Type::Ternary_Cond) :
build_match(AST_NodePtr(new eval::Dot_Access_AST_Node()), prev_stack_top); m_match_stack.erase(m_match_stack.begin() + m_match_stack.size() - 2,
break; m_match_stack.begin() + m_match_stack.size() - 1);
case(AST_Node_Type::Additive) : if (Symbol(":")) {
build_match(AST_NodePtr(new eval::Additive_AST_Node()), prev_stack_top); if (!Operator(t_precedence+1)) {
break; throw exception::eval_error("Incomplete "
case(AST_Node_Type::Multiplicative) : + std::string(ast_node_type_to_string(m_operators[t_precedence])) + " expression",
build_match(AST_NodePtr(new eval::Multiplicative_AST_Node()), prev_stack_top); File_Position(m_line, m_col), *m_filename);
break; }
case(AST_Node_Type::Shift) : build_match(AST_NodePtr(new eval::Ternary_Cond_AST_Node()), prev_stack_top);
build_match(AST_NodePtr(new eval::Shift_AST_Node()), prev_stack_top); }
break; else {
case(AST_Node_Type::Equality) : throw exception::eval_error("Incomplete "
build_match(AST_NodePtr(new eval::Equality_AST_Node()), prev_stack_top); + std::string(ast_node_type_to_string(m_operators[t_precedence])) + " expression",
break; File_Position(m_line, m_col), *m_filename);
case(AST_Node_Type::Bitwise_And) : }
build_match(AST_NodePtr(new eval::Bitwise_And_AST_Node()), prev_stack_top); break;
break; case(AST_Node_Type::Addition) :
case(AST_Node_Type::Bitwise_Xor) : oper = m_match_stack.at(m_match_stack.size()-2);
build_match(AST_NodePtr(new eval::Bitwise_Xor_AST_Node()), prev_stack_top); m_match_stack.erase(m_match_stack.begin() + m_match_stack.size() - 2,
break; m_match_stack.begin() + m_match_stack.size() - 1);
case(AST_Node_Type::Bitwise_Or) : if (oper->text == "+") {
build_match(AST_NodePtr(new eval::Bitwise_Or_AST_Node()), prev_stack_top); build_match(AST_NodePtr(new eval::Addition_AST_Node()), prev_stack_top);
break; }
case(AST_Node_Type::Logical_And) : else if (oper->text == "-") {
build_match(AST_NodePtr(new eval::Logical_And_AST_Node()), prev_stack_top); build_match(AST_NodePtr(new eval::Subtraction_AST_Node()), prev_stack_top);
break; }
case(AST_Node_Type::Logical_Or) : break;
build_match(AST_NodePtr(new eval::Logical_Or_AST_Node()), prev_stack_top); case(AST_Node_Type::Multiplication) :
break; oper = m_match_stack.at(m_match_stack.size()-2);
default: m_match_stack.erase(m_match_stack.begin() + m_match_stack.size() - 2,
throw exception::eval_error("Internal error: unhandled ast_node", File_Position(m_line, m_col), *m_filename); m_match_stack.begin() + m_match_stack.size() - 1);
} if (oper->text == "*") {
build_match(AST_NodePtr(new eval::Multiplication_AST_Node()), prev_stack_top);
}
else if (oper->text == "/") {
build_match(AST_NodePtr(new eval::Division_AST_Node()), prev_stack_top);
}
else if (oper->text == "%") {
build_match(AST_NodePtr(new eval::Modulus_AST_Node()), prev_stack_top);
}
break;
case(AST_Node_Type::Shift) :
build_match(AST_NodePtr(new eval::Shift_AST_Node()), prev_stack_top);
break;
case(AST_Node_Type::Equality) :
build_match(AST_NodePtr(new eval::Equality_AST_Node()), prev_stack_top);
break;
case(AST_Node_Type::Bitwise_And) :
build_match(AST_NodePtr(new eval::Bitwise_And_AST_Node()), prev_stack_top);
break;
case(AST_Node_Type::Bitwise_Xor) :
build_match(AST_NodePtr(new eval::Bitwise_Xor_AST_Node()), prev_stack_top);
break;
case(AST_Node_Type::Bitwise_Or) :
build_match(AST_NodePtr(new eval::Bitwise_Or_AST_Node()), prev_stack_top);
break;
case(AST_Node_Type::Logical_And) :
build_match(AST_NodePtr(new eval::Logical_And_AST_Node()), prev_stack_top);
break;
case(AST_Node_Type::Logical_Or) :
build_match(AST_NodePtr(new eval::Logical_Or_AST_Node()), prev_stack_top);
break;
default:
throw exception::eval_error("Internal error: unhandled ast_node", File_Position(m_line, m_col), *m_filename);
}
} while (Operator_Helper(t_precedence));
} }
} }
} }
@@ -1862,7 +2191,6 @@ namespace chaiscript
bool saw_eol = true; bool saw_eol = true;
while (has_more) { while (has_more) {
has_more = false;
int prev_line = m_line; int prev_line = m_line;
int prev_col = m_col; int prev_col = m_col;
if (Def()) { if (Def()) {
@@ -1905,6 +2233,14 @@ namespace chaiscript
retval = true; retval = true;
saw_eol = 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()) { else if (Return()) {
if (!saw_eol) { if (!saw_eol) {
throw exception::eval_error("Two expressions missing line separator", File_Position(prev_line, prev_col), *m_filename); throw exception::eval_error("Two expressions missing line separator", File_Position(prev_line, prev_col), *m_filename);
@@ -1961,7 +2297,7 @@ namespace chaiscript
while ((m_input_pos != m_input_end) && (!Eol())) { while ((m_input_pos != m_input_end) && (!Eol())) {
++m_input_pos; ++m_input_pos;
} }
// TODO: respect // -*- coding: utf-8 -*- on line 1 or 2 see: http://evanjones.ca/python-utf8.html) /// \todo respect // -*- coding: utf-8 -*- on line 1 or 2 see: http://evanjones.ca/python-utf8.html)
} }
if (Statements()) { if (Statements()) {

View File

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

View File

@@ -1,6 +1,6 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2011, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// and Jason Turner (jason@emptycrate.com) // and Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
@@ -49,10 +49,20 @@
CHAISCRIPT_CLASS_METHODS((_module)(_class_name)(_class_name_translator)(_method_name_translator), _methods) \ 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) \ #define CHAISCRIPT_CLASS(_module, _class_name, _constructors, _methods) \
CHAISCRIPT_CLASS_EX(_module, _class_name, chaiscript::utility::class_name_translator, \ CHAISCRIPT_CLASS_EX(_module, _class_name, chaiscript::utility::class_name_translator, \
chaiscript::utility::method_name_translator, _constructors, _methods) 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 namespace chaiscript
{ {
/// \brief Classes and functions which provide general utility to the end user. /// \brief Classes and functions which provide general utility to the end user.

View File

@@ -1,4 +1,4 @@
Copyright 2009-2010 Jason Turner and Jonathan Turner. All Rights Reserved. Copyright 2009-2012 Jason Turner and Jonathan Turner. All Rights Reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are modification, are permitted provided that the following conditions are
met: met:

82
readme.md Normal file
View File

@@ -0,0 +1,82 @@
ChaiScript
http://www.chaiscript.com
(c) 2009-2012 Jason Turner and Jonathan Turner
Release under the BSD license, see "license.txt" for details.
Introduction
============
ChaiScript is one of the only embedded scripting language designed from the
ground up to directly target C++ and take advantage of modern C++ development
techniques, working with the developer like he expects it to work. Being a
native C++ application, it has some advantages over existing embedded scripting
languages:
1) It uses a header-only approach, which makes it easy to integrate with
existing projects.
2) It maintains type safety between your C++ application and the user scripts.
3) It supports a variety of C++ techniques including callbacks, overloaded
functions, class methods, and stl containers.
Requirements
============
ChaiScript requires a 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 v2.3.3
http://www.chaiscript.com
(c) 2009-2010 Jason Turner and Jonathan Turner
Release under the BSD license, see "license.txt" for details.
[Introduction]
ChaiScript is the only embedded scripting language designed from the ground up to directly target C++ and take advantage of modern C++ development techniques, working with the developer like he expects it to work. Being a native C++ application, it has some advantages over existing embedded scripting languages:
1) It uses a header-only approach, which makes it easy to integrate with existing projects.
2) It maintains type safety between your C++ application and the user scripts.
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(&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(&function, "function");
double d = chai.eval<double>("function(3, 4.75);");
}

View File

@@ -1,3 +1,36 @@
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 Changes since 2.3.3
* Code simplifications * Code simplifications

View File

@@ -141,7 +141,9 @@ int main(int /*argc*/, char * /*argv*/[]) {
//Creating a functor on the stack and using it immediatly //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); 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.add(var(boost::shared_ptr<int>()), "nullvar");
chai("print(\"This should be true.\"); print(nullvar.is_var_null())"); chai("print(\"This should be true.\"); print(nullvar.is_var_null())");
@@ -165,7 +167,7 @@ int main(int /*argc*/, char * /*argv*/[]) {
//Dynamic objects test //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_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(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("var x = TestType()");
// chai.eval("x.attr = \"hi\""); // chai.eval("x.attr = \"hi\"");

View File

@@ -80,7 +80,18 @@ std::string get_next_command() {
char *input_raw = readline("eval> "); char *input_raw = readline("eval> ");
if ( input_raw ) { if ( input_raw ) {
add_history(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); ::free(input_raw);
} }
} }
@@ -215,21 +226,11 @@ int main(int argc, char *argv[])
case eInteractive : interactive(chai); break; case eInteractive : interactive(chai); break;
case eCommand : val = chai.eval(arg); break; case eCommand : val = chai.eval(arg); break;
case eFile : val = chai.eval_file(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) { catch (const chaiscript::exception::eval_error &ee) {
std::cout << ee.what(); std::cout << ee.pretty_print();
if (ee.call_stack.size() > 0) {
std::cout << "during evaluation at (" << *(ee.call_stack[0]->filename) << " " << ee.call_stack[0]->start.line << ", " << ee.call_stack[0]->start.column << ")";
for (size_t j = 1; j < ee.call_stack.size(); ++j) {
if (ee.call_stack[j]->identifier != chaiscript::AST_Node_Type::Block
&& ee.call_stack[j]->identifier != chaiscript::AST_Node_Type::File)
{
std::cout << std::endl;
std::cout << " from " << *(ee.call_stack[j]->filename) << " (" << ee.call_stack[j]->start.line << ", " << ee.call_stack[j]->start.column << ")";
}
}
}
std::cout << std::endl; std::cout << std::endl;
return EXIT_FAILURE; 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

@@ -49,12 +49,12 @@ CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_reflect
m->add(chaiscript::fun(&has_parse_tree), "has_parse_tree"); m->add(chaiscript::fun(&has_parse_tree), "has_parse_tree");
m->add(chaiscript::fun(&get_parse_tree), "get_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::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, chaiscript::exception::eval_error,
,
((reason)) ((reason))
((call_stack)) ((call_stack))
); );
@@ -67,9 +67,8 @@ CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_reflect
((column)) ((column))
); );
CHAISCRIPT_CLASS( m, CHAISCRIPT_CLASS_NO_CONSTRUCTOR( m,
chaiscript::AST_Node, chaiscript::AST_Node,
,
((text)) ((text))
((identifier)) ((identifier))
((filename)) ((filename))

View File

@@ -7,11 +7,22 @@ class TestBaseType
public: public:
TestBaseType() {} TestBaseType() {}
TestBaseType(int) {} TestBaseType(int) {}
TestBaseType(int *) {}
virtual ~TestBaseType() {} virtual ~TestBaseType() {}
virtual int func() { return 0; } virtual int func() { return 0; }
}; };
enum TestEnum
{
TestValue1 = 1
};
int to_int(TestEnum t)
{
return t;
}
class TestDerivedType : public TestBaseType class TestDerivedType : public TestBaseType
{ {
public: public:
@@ -24,6 +35,11 @@ std::string hello_world()
return "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 // 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 // but this is the best way to do it for cross platform compatibility
#ifdef BOOST_MSVC #ifdef BOOST_MSVC
@@ -44,6 +60,7 @@ CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_test_mo
m->add(chaiscript::constructor<TestBaseType ()>(), "TestBaseType"); m->add(chaiscript::constructor<TestBaseType ()>(), "TestBaseType");
// m->add(chaiscript::constructor<TestBaseType (int)>(), "TestBaseType"); // m->add(chaiscript::constructor<TestBaseType (int)>(), "TestBaseType");
m->add(chaiscript::constructor<TestBaseType (const TestBaseType &)>(), "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 ()>(), "TestDerivedType");
m->add(chaiscript::constructor<TestDerivedType (const TestDerivedType &)>(), "TestDerivedType"); m->add(chaiscript::constructor<TestDerivedType (const TestDerivedType &)>(), "TestDerivedType");
@@ -52,6 +69,15 @@ CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_test_mo
m->add(chaiscript::fun(&TestBaseType::func), "func"); m->add(chaiscript::fun(&TestBaseType::func), "func");
m->add(chaiscript::fun(&get_new_int), "get_new_int");
m->add_global_const(chaiscript::const_var(TestValue1), "TestValue1");
m->add(chaiscript::user_type<TestEnum>(), "TestEnum");
m->add(chaiscript::fun(&to_int), "to_int");
return m; return m;
} }

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

@@ -58,8 +58,8 @@ bool do_test(const Boxed_Value &bv, bool T, bool ConstT, bool TRef, bool ConstTR
bool ConstTPtrConst, bool SharedPtrT, bool SharedConstPtrT, bool ConstTPtrConst, bool SharedPtrT, bool SharedConstPtrT,
bool ConstSharedPtrT, bool ConstSharedConstPtrT, bool ConstSharedPtrTRef, bool ConstSharedPtrTConstRef, bool ConstSharedPtrT, bool ConstSharedConstPtrT, bool ConstSharedPtrTRef, bool ConstSharedPtrTConstRef,
bool BoostRef, bool BoostConstRef, bool ConstBoostRef, bool ConstBoostConstRef, bool BoostRef, bool BoostConstRef, bool ConstBoostRef, bool ConstBoostConstRef,
bool ConstBoostRefRef, bool ConstBoostConstRefRef, bool PODValue, bool ConstBoostRefRef, bool ConstBoostConstRefRef, bool Number,
bool ConstPODValue, bool ConstPODValueRef, bool TPtrConstRef, bool ConstTPtrConstRef) bool ConstNumber, bool ConstNumberRef, bool TPtrConstRef, bool ConstTPtrConstRef)
{ {
bool passed = true; bool passed = true;
passed &= test_type_conversion<Type>(bv, T); passed &= test_type_conversion<Type>(bv, T);
@@ -86,14 +86,14 @@ bool do_test(const Boxed_Value &bv, bool T, bool ConstT, bool TRef, bool ConstTR
passed &= test_type_conversion<const boost::reference_wrapper<const Type> >(bv, ConstBoostConstRef); passed &= test_type_conversion<const boost::reference_wrapper<const Type> >(bv, ConstBoostConstRef);
passed &= test_type_conversion<const boost::reference_wrapper<Type> &>(bv, ConstBoostRefRef); passed &= test_type_conversion<const boost::reference_wrapper<Type> &>(bv, ConstBoostRefRef);
passed &= test_type_conversion<const boost::reference_wrapper<const Type> &>(bv, ConstBoostConstRefRef); passed &= test_type_conversion<const boost::reference_wrapper<const Type> &>(bv, ConstBoostConstRefRef);
passed &= test_type_conversion<Boxed_POD_Value>(bv, PODValue); passed &= test_type_conversion<Boxed_Number>(bv, Number);
passed &= test_type_conversion<const Boxed_POD_Value>(bv, ConstPODValue); passed &= test_type_conversion<const Boxed_Number>(bv, ConstNumber);
passed &= test_type_conversion<Boxed_POD_Value &>(bv, false); passed &= test_type_conversion<Boxed_Number &>(bv, false);
passed &= test_type_conversion<const Boxed_POD_Value &>(bv, ConstPODValueRef); passed &= test_type_conversion<const Boxed_Number &>(bv, ConstNumberRef);
passed &= test_type_conversion<Boxed_POD_Value *>(bv, false); passed &= test_type_conversion<Boxed_Number *>(bv, false);
passed &= test_type_conversion<const Boxed_POD_Value *>(bv, false); passed &= test_type_conversion<const Boxed_Number *>(bv, false);
passed &= test_type_conversion<Boxed_POD_Value * const>(bv, false); passed &= test_type_conversion<Boxed_Number * const>(bv, false);
passed &= test_type_conversion<const Boxed_POD_Value *const>(bv, false); passed &= test_type_conversion<const Boxed_Number *const>(bv, false);
passed &= test_type_conversion<Type *&>(bv, false); passed &= test_type_conversion<Type *&>(bv, false);
passed &= test_type_conversion<const Type *&>(bv, false); passed &= test_type_conversion<const Type *&>(bv, false);
passed &= test_type_conversion<Type * const&>(bv, TPtrConstRef); passed &= test_type_conversion<Type * const&>(bv, TPtrConstRef);
@@ -295,13 +295,15 @@ int main()
bool ConstTPtr, bool TPtrConst, bool ConstTPtrConst, bool SharedPtrT, bool SharedConstPtrT, bool ConstTPtr, bool TPtrConst, bool ConstTPtrConst, bool SharedPtrT, bool SharedConstPtrT,
bool ConstSharedPtrT, bool ConstSharedConstPtrT, bool ConstSharedPtrTRef, bool ConstSharedPtrTConstRef, bool BoostRef, bool ConstSharedPtrT, bool ConstSharedConstPtrT, bool ConstSharedPtrTRef, bool ConstSharedPtrTConstRef, bool BoostRef,
bool BoostConstRef, bool ConstBoostRef, bool ConstBoostConstRef, bool ConstBoostRefRef, bool ConstBoostConstRefRef, bool BoostConstRef, bool ConstBoostRef, bool ConstBoostConstRef, bool ConstBoostRefRef, bool ConstBoostConstRefRef,
bool PODValue, bool ConstPODValue, bool ConstPODValueRef bool Number, bool ConstNumber, bool ConstNumberRef
*/ */
passed &= built_in_type_test<int>(5, true); passed &= built_in_type_test<int>(5, true);
passed &= built_in_type_test<double>(1.1, true); passed &= built_in_type_test<double>(1.1, true);
passed &= built_in_type_test<char>('a', true); passed &= built_in_type_test<char>('a', true);
passed &= built_in_type_test<bool>(false, 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); passed &= built_in_type_test<std::string>("Hello World", false);
// storing a pointer // storing a pointer

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

@@ -2,8 +2,7 @@
#include <chaiscript/chaiscript.hpp> #include <chaiscript/chaiscript.hpp>
int test_generic()
int main()
{ {
chaiscript::ChaiScript chai; chaiscript::ChaiScript chai;
@@ -17,5 +16,107 @@ int main()
} }
} }
std::cout << "test_generic failed" << std::endl;
return EXIT_FAILURE; return EXIT_FAILURE;
} }
int test_1()
{
chaiscript::ChaiScript chai;
try {
chai.eval("throw(1)", chaiscript::exception_specification<int>());
} catch (int e) {
if (e == 1)
{
return EXIT_SUCCESS;
}
}
std::cout << "test_1 failed" << std::endl;
return EXIT_FAILURE;
}
int test_2()
{
chaiscript::ChaiScript chai;
try {
chai.eval("throw(1.0)", chaiscript::exception_specification<int, double>());
} catch (const double e) {
if (e == 1.0)
{
return EXIT_SUCCESS;
}
}
std::cout << "test_2 failed" << std::endl;
return EXIT_FAILURE;
}
int test_5()
{
chaiscript::ChaiScript chai;
try {
chai.eval("throw(runtime_error(\"error\"))", chaiscript::exception_specification<int, double, float, const std::string &, const std::exception &>());
} catch (const double) {
std::cout << "test_5 failed with double" << std::endl;
return EXIT_FAILURE;
} catch (int) {
std::cout << "test_5 failed with int" << std::endl;
return EXIT_FAILURE;
} catch (float) {
std::cout << "test_5 failed with float" << std::endl;
return EXIT_FAILURE;
} catch (const std::string &) {
std::cout << "test_5 failed with string" << std::endl;
return EXIT_FAILURE;
} catch (const std::exception &) {
return EXIT_SUCCESS;
}
std::cout << "test_5 failed" << std::endl;
return EXIT_FAILURE;
}
int test_unhandled()
{
chaiscript::ChaiScript chai;
try {
chai.eval("throw(\"error\")", chaiscript::exception_specification<int, double, float, const std::exception &>());
} catch (double) {
std::cout << "test_unhandled failed with double" << std::endl;
return EXIT_FAILURE;
} catch (int) {
std::cout << "test_unhandled failed with int" << std::endl;
return EXIT_FAILURE;
} catch (float) {
std::cout << "test_unhandled failed with float" << std::endl;
return EXIT_FAILURE;
} catch (const std::exception &) {
std::cout << "test_unhandled failed with std::exception" << std::endl;
return EXIT_FAILURE;
} catch (const chaiscript::Boxed_Value &) {
return EXIT_SUCCESS;
}
std::cout << "test_unhandled failed" << std::endl;
return EXIT_FAILURE;
}
int main()
{
if (test_generic() == EXIT_SUCCESS
&& test_1() == EXIT_SUCCESS
&& test_2() == EXIT_SUCCESS
&& test_5() == EXIT_SUCCESS
&& test_unhandled() == EXIT_SUCCESS)
{
return EXIT_SUCCESS;
} else {
return EXIT_FAILURE;
}
}

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

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

View File

@@ -17,7 +17,7 @@ int main()
chaiscript::ChaiScript chai; chaiscript::ChaiScript chai;
chai.eval("def test_fun(x) { return 3; }"); chai.eval("def test_fun(x) { return 3; }");
chai.eval("def test_fun(x) : x == \"hi\" { return 4; }"); 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_one), "test_fun");
chai.add(chaiscript::fun(&test_two), "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

@@ -0,0 +1,10 @@
// tests more complex parses of the index operator
def Bob::bob3() { return [1,2,3]; }
def Bob::Bob() {}
var b = Bob();
assert_equal(b.bob3()[0], 1);
assert_equal((b.bob3())[1], 2);

View File

@@ -0,0 +1,90 @@
// Tests to make sure that the order in which function dispatches occur is correct
#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 +1,29 @@
assert_equal([true, false, true], map([1,2,3], odd)) 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"])

View File

@@ -1,3 +1,14 @@
var x = ["bob":1, "fred":2] var x = ["bob":1, "fred":2]
assert_equal(2, x.size()); 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,4 @@
var x = 3 +
4
assert_equal(x, 7);

View File

@@ -0,0 +1,101 @@
// 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 <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)
{
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() + ");");
}
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);
std::vector<boost::shared_ptr<boost::thread> > 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.push_back(boost::shared_ptr<boost::thread>(new boost::thread(boost::bind(do_work, boost::ref(chai), i))));
}
for (int i = 0; i < num_threads; ++i)
{
threads[i]->join();
}
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; chaiscript::ChaiScript chai;
chai.add(m); chai.add(m);
chai.add(chaiscript::fun(&Test::count), "count"); // chai.add(chaiscript::fun(&Test::count), "count");
int count = chai.eval<int>("count()"); int count = chai.eval<int>("count()");
int count2 = chai.eval<int>("var i = 0; { var t = Test(); } return i;"); 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 if (count == 0
&& count2 == 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 @@
assert_equal('b', "abc"[1])

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 // Passes
} else { } else {
// Fails // 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); exit(-1);
} }
} }
@@ -23,7 +23,7 @@ def assert_true(f)
{ {
if (!f) if (!f)
{ {
print("assert_false failure"); print("assert_true failure");
exit(-1); exit(-1);
} }
} }

View File

@@ -30,8 +30,8 @@ int main()
chaiscript::ChaiScript chai; chaiscript::ChaiScript chai;
chai.add(m); chai.add(m);
if (chai.eval<std::string>("var t = Test(); t.function2(); ") == "Function2" 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 t2 = Test(); t2.functionOverload(1); ") == "int"
&& chai.eval<std::string>("var t = Test(); t.functionOverload(1.1); ") == "double") && chai.eval<std::string>("var t3 = Test(); t3.functionOverload(1.1); ") == "double")
{ {
chai.eval("t = Test();"); chai.eval("t = Test();");
return EXIT_SUCCESS; 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] var x = [1, 2, 3]
assert_equal(3, x.size()) 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 @@
assert_equal(1, [1,2,3][0])

View File

@@ -0,0 +1,2 @@
var x = [1]
assert_equal(1, x[0])

View File

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