Compare commits

...

198 Commits

Author SHA1 Message Date
Jason Turner
799b3ef388 Update copyright for 2010 2010-05-15 22:48:54 +00:00
Jason Turner
fe6694297f Set version number to 2.3.3 2010-05-15 22:39:28 +00:00
Jason Turner
e77ec4b16a Clean up the vim syntax a bit, add escape characters and incorporate changes from bram 2010-04-01 19:01:18 +00:00
Jason Turner
f070575205 Cleanups of vim files to get them ready for submission 2010-03-31 20:11:19 +00:00
Jason Turner
43d0d6199a Clean up use recognition of backtick operator functions, add support for .. range operator 2010-03-31 01:01:45 +00:00
Jason Turner
65c5178549 Update copyright/version info for geshi filter 2010-03-31 00:23:02 +00:00
Jason Turner
c928e2992b Fix readline support for the eval 2010-03-30 18:40:55 +00:00
Jason Turner
7fef086cab Add geshi syntax highlighting (updated and cleaned up from the version that was hosted at chaiscript.com) 2010-03-30 16:50:18 +00:00
Jason Turner
791fd242e7 Add "throw" built in function to vim syntax highlighting 2010-03-30 16:38:20 +00:00
Jason Turner
e81b71ccc7 Add missing README for vim highlighting 2010-03-30 16:21:35 +00:00
Jason Turner
ef7a785214 Initial check-in of vim syntax highlighting 2010-03-30 16:21:06 +00:00
Jason Turner
f431d479fc Add support for using cmake to build RPMs 2010-03-30 02:01:59 +00:00
Jason Turner
e11eca406d Get cpack working for source and deb distribtions. Still need to check nsis and rpm 2010-03-29 15:32:20 +00:00
Jason Turner
7efb65a5c2 Move to using cmake for VisualStudio 2010-03-28 13:31:19 +00:00
Jason Turner
39339d769a Get the rest of the unit tests passing. Note: ChaiScript now requires CMake 2.8, which is almost a year old, so this is fair, but for the meantime we will have to either get it from backports in ubuntu or from cmake.org 2010-03-19 00:50:36 +00:00
Jason Turner
7ac9ea7249 Add the ability to specify "load_module" and "use" search paths. The capability is primitive and it is currently used by chaiscript_eval to set a single path from environment variables 2010-03-18 22:53:52 +00:00
Jason Turner
7080f5d681 Use ctest to run unit tests. run "make test" to run them. Note, anything "use"ing another file or loading a module will fail. Need to come up with some cross platform mechanism for specifying include dirs to solve this. Current thought: using environment variables "CHAI_USE_PATH" and "CHAI_MODULE_PATH" 2010-03-16 04:07:38 +00:00
Jason Turner
22d994009e Add missing unit_test.inc file 2010-03-14 14:54:00 +00:00
Jason Turner
567f911093 Move to a more standardized unit testing design which relies less on OS support and can soon be moved to a ctest implementation 2010-03-14 05:19:24 +00:00
Jason Turner
5c98a5d6e7 Add sync_cache to set_state code to fix logic flaw in resetting of state and memory leak. #92 2010-03-09 02:09:05 +00:00
Jason Turner
856b682e72 Testing of memberscope so we can close #91 2010-03-09 01:39:54 +00:00
Jason Turner
faaa964565 No longer allow a local variable to be used as a function during dot notation sugar lookup. It's far less confusing this way 2010-01-27 03:54:42 +00:00
Jason Turner
d8213a4206 Convert from #warning to #pragma message for notification of thread safety being disabled, so support more compilers portably 2010-01-19 01:54:00 +00:00
Jason Turner
3a4421a57c Fix empty array unit test by reimplementing the node->children.size() test erroneously removed in r466 2010-01-07 01:47:04 +00:00
Jonathan Turner
31fec2202c Add the answer to the unittest I added earlier 2010-01-06 19:42:09 +00:00
Jonathan Turner
13178e55e1 Add unit test that dies after r465 2010-01-06 19:39:04 +00:00
Jason Turner
968da650b2 Clean up leaking #define's for iterations (n, m) that could mess up subsequently included files such as boost/signals2.hpp 2010-01-03 15:48:17 +00:00
Jason Turner
fb5ba0be26 Remove std::swap implementation that was not supported for multiple file compilation. 2010-01-03 15:03:26 +00:00
Jason Turner
39a2c39d90 Minor fixes to example.cpp to avoid exceptions 2009-12-30 15:29:36 +00:00
Jason Turner
70047424f9 Get compiling with Visual Studio 10 beta 2. Had to work around issues with conflicts between boost::function and VisualStudio's std::tr1::mem_fn (http://social.msdn.microsoft.com/Forums/en/vcprerelease/thread/e04d93ed-d686-4ef6-9939-26e34c0955eb). Also had to work around non-standard overloaded std member functions in std::map (http://msdn.microsoft.com/en-us/library/fe72hft9(VS.100).aspx)
Strongly consider rolling this back when the issues are resolved between microsoft and boost. Also, needs to be tested across all platforms.
2009-12-28 17:16:03 +00:00
Jason Turner
2805af1ed2 move from std::numeric_limits::min() to boost::integer_traits::const_min - avoids runtime overhead of the function call. 2009-12-11 15:35:59 +00:00
Jonathan Turner
e5a29ede5f Added 0b1010 binary format. Fixed hex and octal to allow negative ints 2009-12-11 14:46:12 +00:00
Jason Turner
0c0df2c982 VS 2008 related corrections. 2009-12-08 15:57:31 +00:00
Jason Turner
4457df9ff5 Fix NO_THREADS related issues 2009-12-06 05:12:02 +00:00
Jason Turner
e601de9d18 Reduce use of Param_List_Builder by providing call_function implementations for 0,1,2 arity 2009-12-06 01:31:58 +00:00
Jason Turner
37b2ac2056 Implement proper swap for Boxed_Value 2009-12-05 19:30:09 +00:00
Jason Turner
645cdddd70 Small but measurable eval performance increase (in optimized builds) by managing the number of Boxed_Values copies and assignments 2009-12-05 18:54:55 +00:00
Jonathan Turner
ac8462fb67 Fix up some broken sample files 2009-12-02 14:29:42 +00:00
Jason Turner
636c55493c Smartly size the integer returned from a Boxed_POD_Value operation to return an "int" if the resulting value is small enough 2009-12-01 03:52:57 +00:00
Jason Turner
e2a2c14c0d Eliminate use of size_t in stl related wrappings 2009-12-01 02:56:02 +00:00
Jonathan Turner
c418644a5b Fix for single-line comments stopping at semicolon. 2009-11-27 22:52:55 +00:00
Jason Turner
fbf8f53e04 Add Type_Info type and add *_type objects at time of type registration. 2009-11-21 22:47:44 +00:00
Jason Turner
a0c6366479 Added introspecition/classification of types 2009-11-21 06:39:35 +00:00
Jason Turner
15ffbd200a Fixed unittests broken by last checkin 2009-11-21 06:39:11 +00:00
Jason Turner
1c6b2725b3 Provide some hints for dispatches with lhs (first param) that is const 2009-11-21 06:02:17 +00:00
Jason Turner
95c124ca35 Support better tracking of loaded modules for saving and setting of state 2009-11-21 05:28:00 +00:00
Jason Turner
1bd73884b2 Add documentation to the set_state get_state functions 2009-11-18 05:05:40 +00:00
Jason Turner
d3e4af433e Add support for saving/restoring of chaiscript engine state. 2009-11-18 04:43:08 +00:00
Jason Turner
9f65303370 Handle case of const & return values (should probably be investigated a bit more) 2009-11-18 04:42:43 +00:00
Jason Turner
391eaa9e11 VC++ 2008 warnings cleanups 2009-11-15 03:26:47 +00:00
Jason Turner
ed11f48847 More robust handling of potential class object member types 2009-11-15 00:37:01 +00:00
Jason Turner
9dddb49850 Added support for const attribute access 2009-11-14 19:02:00 +00:00
Jason Turner
cca477dae6 Only share const globals between threads. Require all globals to be const. 2009-11-11 05:47:54 +00:00
Jason Turner
07352a16a3 Operators unittests 2009-11-11 03:03:24 +00:00
Jonathan Turner
e14931f389 Move completely over to new operators 2009-11-10 14:07:51 +00:00
Jason Turner
f4a680a582 Add missing operators.hpp file 2009-11-10 13:27:44 +00:00
Jason Turner
e6c6223c5b Operator handling rewrite and fleshing out of operators to include all standard C++ operators 2009-11-10 05:55:58 +00:00
Jason Turner
cbc61d898c Add "is_null" for boxed_values to see if they contain a null shared_ptr value 2009-11-08 16:30:12 +00:00
Jason Turner
3a37ceedb7 Rollback to r437 for bind_first implementation. The "cleaned up" version was a no-go in some cases 2009-11-08 16:28:35 +00:00
Jonathan Turner
1bc968e788 Add initial unaries 2009-11-08 16:27:39 +00:00
Jason Turner
fe5a935abd add is_undef functionality to boxed_value 2009-11-08 15:16:15 +00:00
Jason Turner
4e5c972e66 Simplify implementation of bind_first and add some detail namespacing 2009-11-08 14:46:44 +00:00
Jonathan Turner
d946cb7e9d Small fix to the casting of values in boolean logical statements 2009-11-07 14:50:41 +00:00
Jonathan Turner
18bfead387 Move to a better operator parser, add support for most of the C++ binary operators 2009-11-07 14:43:12 +00:00
Jason Turner
4c015d7e44 Simplification of bootstrap_stl code resulting in slightly better engine start up performance and compile time performance 2009-10-21 01:48:21 +00:00
Jason Turner
1122f2c818 Clean up reference counting implementation while improving compile time and compromising runtime slightly 2009-10-20 00:34:15 +00:00
Jason Turner
d2d752ecd4 Fix registration of module loading functions 2009-10-19 14:00:48 +00:00
Jason Turner
a18c701866 Fix type-shifting of bind_first for free function pointer types 2009-10-16 15:49:46 +00:00
Jason Turner
9871604a48 Make sure example.cpp compilable with new setup 2009-10-15 15:55:16 +00:00
Jason Turner
b1d12fdc91 Further updates to the new bound function support, plus general cleanup of how it is used 2009-10-15 15:27:16 +00:00
Jason Turner
24e717d532 Fix "bind_first" for non member functions 2009-10-14 22:42:45 +00:00
Jason Turner
1568fedebd Reduce # of required versions for bound_fun and enhance it to work with non-member functions 2009-10-14 17:19:42 +00:00
Jonathan Turner
c88578d537 Add another unit test for operator overloading 2009-10-14 14:00:22 +00:00
Jonathan Turner
9827345213 Fix Id Literals so that they are keyed off an Id search. This allows us to add operator overloading on the parse side. 2009-10-14 13:51:35 +00:00
Jonathan Turner
c51d14fb13 Add some missing unit tests for number formats and block starting 2009-10-14 12:25:21 +00:00
Jason Turner
480761c1f7 Add bound_fun helper and put it to use cleaning up the engine bootstrapping 2009-10-14 02:34:09 +00:00
Jonathan Turner
12e909d9aa Add bit shifting operators 2009-10-13 03:35:01 +00:00
Jason Turner
b1e892487f Enhance "is_type" to be more accurate and to work with Dynamic_Object types 2009-10-13 03:31:56 +00:00
Jason Turner
720eabcb16 Impliment range find functions and add unit test for contains and find. 2009-10-13 02:05:18 +00:00
Jason Turner
1fde71f3f4 Add type generic comparison operations "eq", "gt", and "lt" and port the "contains" operation to use it 2009-10-13 00:18:59 +00:00
Jonathan Turner
90f8b77171 Added .contains() to ranges 2009-10-11 20:02:21 +00:00
Jonathan Turner
315d7521a7 Clean up warnings. Add simple blocks. 2009-10-08 03:01:19 +00:00
Jonathan Turner
ff177b5eaf Add octal support 2009-10-06 21:17:23 +00:00
Jonathan Turner
46fd7e9a58 Add hex value parsing support 2009-10-06 16:04:05 +00:00
Jason Turner
edd274ccce Fix some more obscure warnings 2009-10-06 02:26:47 +00:00
Jonathan Turner
a5b2ec3006 Start code cleanups by moving chaiscript common structures into their own file. 2009-09-23 05:00:14 +00:00
Jason Turner
cd3c0d4fd7 Update property page to something more in line with normal boost installs. 2009-09-23 00:42:08 +00:00
Jason Turner
3bdd79a3fd Correct Windows unicode build issues. 2009-09-22 23:03:16 +00:00
Jason Turner
b04e01cda7 Ensure that __EVAL__ is in the list of loaded files and be smarter about accessing it 2009-09-22 21:06:02 +00:00
Jason Turner
bad5384c96 Fix multi-file compilation issues 2009-09-22 20:59:10 +00:00
Jason Turner
443902f787 Reduce overhead necessary for internal_eval. Desirable due to the use of "eval" during cloning operations 2009-09-22 01:58:16 +00:00
Jason Turner
d3cdd6959d Add unit tests for range lookups 2009-09-22 01:36:13 +00:00
Jason Turner
9762e15460 Fix some range/retro issues and update the visual studio files 2009-09-22 01:23:02 +00:00
Jonathan Turner
33897e2c0f Add unit tests for multiline and inner outer loops 2009-09-21 17:31:10 +00:00
Jonathan Turner
9528e44b88 Add unit tests for multiline and inner outer loops 2009-09-21 17:30:55 +00:00
Jonathan Turner
03746e7606 Add keywords for NaN and Infinity 2009-09-21 16:50:30 +00:00
Jason Turner
50eace16da Allow "Module" to contain chaiscript snippets to be executed when a module is initialized. Update dynamic_object to use the new feature to clean up some of the _prelude.hpp 2009-09-21 03:07:01 +00:00
Jason Turner
8241e46680 Further refine how clone calls are dynamically generated, to avoid accidentally matching when we should not 2009-09-20 21:49:53 +00:00
Jason Turner
160f64e9c2 Enabled short hand for adding new methods to existing C++ types 2009-09-20 21:32:39 +00:00
Jason Turner
593c6c68ee Port "retro" to use the new built in object typing, add unit test for retro'ing a retro 2009-09-20 03:50:25 +00:00
Jason Turner
991753a492 Add support for cloning of dynamic objects 2009-09-19 23:12:56 +00:00
Jason Turner
7cdd772f2b Add const correctness for proxy functions. Add unit tests for function variable assignment scenarios 2009-09-19 21:13:12 +00:00
Jonathan Turner
c5f837fd19 Added 'finally' to try/catch block 2009-09-19 18:12:22 +00:00
Jonathan Turner
7c244d25b5 Add support for chai objects by adding methods and attrs 2009-09-19 15:32:12 +00:00
Jonathan Turner
18fc4d419f Fix to catch block handling that would have lost the scope of the boost::ref of the exception 2009-09-19 13:40:48 +00:00
Jonathan Turner
813fa055a3 Added guarded exception catches 2009-09-19 13:30:11 +00:00
Jason Turner
6a47846b84 Add runtime_error support, for throwing a normal std::exception. Also, move bootstrap for Dynamic_Object into its proper place. 2009-09-19 12:15:17 +00:00
Jason Turner
b0041217b0 initial checkin of dynamic object support with example usage in example.cpp 2009-09-19 02:36:27 +00:00
Jonathan Turner
fedcd28ecc Add exception unit test 2009-09-19 02:21:36 +00:00
Jonathan Turner
b17c6b9748 Add support for std::exception and what() 2009-09-18 22:26:07 +00:00
Jonathan Turner
204d379176 Fix default cmake build to use readline and gdb. Add simple try/catch/throw exceptions 2009-09-18 22:04:07 +00:00
Jason Turner
a754ce9eb6 Initial check in of code analysis tool 2009-09-16 01:46:04 +00:00
Jonathan Turner
99b5f46a9e Fix type in help. 2009-09-15 20:32:16 +00:00
Jason Turner
394d8c3bf6 Allow the user to choose the build type using CMAKE_BUILD_TYPE by eliminating the overrides in the CMakeLists.txt file 2009-09-15 02:53:23 +00:00
Jason Turner
4bdbcf30ff Move std::list<> support from main.cpp into a module, stl_extra.cpp, to better allow for measuring of core compile times / performance. 2009-09-15 01:30:51 +00:00
Jonathan Turner
63de0fd33c Add a couple more in-string eval unit tests to check for proper escaping 2009-09-13 12:53:12 +00:00
Jonathan Turner
0fbb7c44bd Add some unit tests for in-string eval 2009-09-12 14:55:14 +00:00
Jonathan Turner
5092713876 Add in-string eval 2009-09-12 14:52:46 +00:00
Jason Turner
f369afed77 Decrease compile times by 30% and runtimes by 10% by eliminating use of boost::bind during function dispatch 2009-09-10 03:44:42 +00:00
Jonathan Turner
f23f0edc70 Fix parser to handle shortform equations (fix bad operator parsing). Add back lines to prelude for line numbers 2009-09-09 14:11:03 +00:00
Jason Turner
daee00da95 Minor performance enhancement for caching function and cleanup of minor windows warning in same function. 2009-09-09 13:17:20 +00:00
Jason Turner
e2cdac0406 Decrease compilation time by removing "Retro" from c++ compiled and making a chaiscript version instead 2009-09-09 03:11:47 +00:00
Jason Turner
cc44ec99ba Fix reversed logic in printing output during eval 2009-09-08 23:39:34 +00:00
Jonathan Turner
1bf3b1ed37 Couple changes for module loading in mingw 2009-09-08 21:22:37 +00:00
Jason Turner
f7b530ebae Quick fix to (hopefully) module support on mingw 2009-09-08 19:21:11 +00:00
Jason Turner
b185e2e792 Make Type_Info internal data private and provide more rigorous definitions for comparisions of objects 2009-09-08 13:31:14 +00:00
Jonathan Turner
73ec2abd43 Add unit test script for windows 2009-09-08 02:22:49 +00:00
Jonathan Turner
cfee4c6bc1 Bugfix: cached the wrong boolean value. Fixed. 2009-09-08 02:15:41 +00:00
Jonathan Turner
2d4b9c0d93 Another Touchup fix to CMakeLists.txt for cleanliness 2009-09-07 21:25:10 +00:00
Jonathan Turner
f522d3697c Touchup fix to CMakeLists.txt for cleanliness 2009-09-07 21:09:18 +00:00
Jonathan Turner
48e96b2f3b Add readline support to eval. 2009-09-07 20:52:31 +00:00
Jason Turner
798908f127 Add loadable module support for ms Visual C++ and fix visual studio specific type identification problems, (while making the C++ more correct) 2009-09-07 17:05:57 +00:00
Jonathan Turner
7e3127549f Added simple const value caching. Fix CMake to default back to debug mode 2009-09-07 15:48:32 +00:00
Jonathan Turner
4713325877 Touchup to cmake project file to prevent error msg in OS X 2009-09-07 14:13:28 +00:00
Jason Turner
7cc6a3cab9 Add support for loadable modules on POSIX systems 2009-09-06 23:33:03 +00:00
Jonathan Turner
cba5731576 Fixing the last of the const change issues 2009-09-06 02:55:39 +00:00
Jonathan Turner
b3656c95f5 Correcting unit tests that are inc/dec temporaries. This is no longer allowed 2009-09-06 02:50:36 +00:00
Jonathan Turner
e9539dfee2 BROKEN./run_unit_tests.sh ! This is to help repair unit tests broken in move to consts. Should be fixed shortly. 2009-09-06 02:24:46 +00:00
Jason Turner
4b40812e26 Add const_var helper function for making const values. 2009-09-06 02:09:19 +00:00
Jason Turner
ef8cd1f591 Add more robust support for handling of const ptr values 2009-09-05 23:46:21 +00:00
Jason Turner
46cdb89921 Add missing chaiscript_threading.hpp 2009-09-05 13:10:27 +00:00
Jason Turner
3094ff6e3b Made thread saftey a compilation option for performance and dependencies reasons 2009-09-05 00:16:46 +00:00
Jason Turner
4d42d6ff33 Add shared objects that can be used by all threads at their root scope only 2009-09-03 11:42:23 +00:00
Jason Turner
a427d2c1a9 Correct function pointer casts to more correct static_cast<>() 2009-09-03 00:15:56 +00:00
Jason Turner
efb7a8d453 Create local thread caches of registered function objects to reduce thread contention 2009-09-02 02:28:38 +00:00
Jason Turner
6c4872eae9 Initial check in of multithreaded support for chaiscript 2009-08-31 19:50:41 +00:00
Jason Turner
ff639a267d Shave a few cycles off by reducing copies and assignments of objects in eval 2009-08-30 02:24:11 +00:00
Jason Turner
94e4b671f3 Make sure to invalidate the cache when a new function name is added 2009-08-30 01:06:21 +00:00
Jason Turner
096c8aab50 Provide for caching of objects in the dispatch get get_object side. Also, update chaiscript_eval to not explicitly add a new stack object to each scope as it is created 2009-08-30 00:48:17 +00:00
Jason Turner
89186a86c8 speed up operator calls by about 10% by reducing Proxy_Function copies and such 2009-08-29 19:19:31 +00:00
Jason Turner
c8c1c65e8c Add std::list support 2009-08-29 14:00:07 +00:00
Jonathan Turner
c5e1d5fa20 Add ref equal unit test 2009-08-27 15:03:49 +00:00
Jonathan Turner
91011695f0 Allow simple multiline commands in arg list and container arg list 2009-08-26 20:34:32 +00:00
Jason Turner
3a951cea99 Extend the reserved object name registration to include some missing values such as break and return and such 2009-08-26 02:21:41 +00:00
Jonathan Turner
8620f4eaf9 Fix for issue 23, makes for and while loops live in their own deeper scope 2009-08-26 02:02:41 +00:00
Jonathan Turner
59ecf32f9b Add Eval_Error end extents and reserved word errors 2009-08-25 01:10:28 +00:00
Jason Turner
541e453098 check in of reserved word handling 2009-08-25 00:36:02 +00:00
Jason Turner
0b780593a6 Make for better error messages when a clone fails 2009-08-22 13:55:06 +00:00
Jason Turner
2e7c5f413e Cleanup get_function implementation 2009-08-21 22:51:12 +00:00
Jonathan Turner
7e5b7cbd7a Switch get_function to default to not doing object lookup. Correct method eval to maintain method lambda syntax. Add unit test for method lambda 2009-08-21 20:05:05 +00:00
Jonathan Turner
c539e0b458 Add unittest for 'use' feature 2009-08-21 18:26:34 +00:00
Jason Turner
1f011f3d5b Add "use" function for loading chai files from inside of ChaiScript and fix potential memory bug with filename const char * pointers being passed around 2009-08-21 03:33:57 +00:00
Jason Turner
a136236179 Fix dispatch for const boost::shared_ptr<> & parameters for functions, add a test to example.cpp and fix some issues with building example.cpp 2009-08-20 21:35:56 +00:00
Jonathan Turner
8840f06053 Allow floating point numbers without a zero before the decimal point 2009-08-20 14:50:13 +00:00
Jason Turner
00e4de774f Move "fun_helper" into detail namespace 2009-08-09 19:12:01 +00:00
Jason Turner
bc3a17b3b7 Port VC++ fix from last rev back to Linux 2009-08-09 18:42:32 +00:00
Jason Turner
4a57efde25 Correct bug with bootstrapping of Map type on windows. Also, make it easier to specify the type of a function being added at the time it is being added. 2009-08-09 16:49:14 +00:00
Jason Turner
cf94817869 Add missing new files from last checkin 2009-08-08 16:38:32 +00:00
Jason Turner
6775863415 Clean up chaiscript namespace by adding the "detail" namespace for internal functions/classes 2009-08-08 16:38:04 +00:00
Jason Turner
a3d4b6698a Favor filtering of functions during dispatch over exceptions to determine appropriate function to call. Results in approximately 50% reduction in runtime for long running scripts 2009-08-06 04:22:13 +00:00
Jason Turner
0ff107a818 Rename types_match to call_match in Proxy_Function to more closely match the semantics of the call 2009-08-06 01:35:12 +00:00
Jason Turner
ba6b392174 Approximate 20% reduction in runtime on long running scripts, based on profiling data. Reduce number of execution of object cache culling, reduction of copies of the stack and reduction of Boxed_Value copies 2009-08-05 02:43:13 +00:00
Jonathan Turner
5b424be4ed Add error to CMakeList.txt on missing Boost. Fix if sample 2009-07-26 13:33:58 +00:00
Jason Turner
669d6e9495 Cleanup comment in example.cpp 2009-07-25 13:48:44 +00:00
Jonathan Turner
9f614bba33 Update ticks in example to proper quotes 2009-07-24 13:31:15 +00:00
Jason Turner
0b789004e9 Make "clone" a chaiscript based operation instead of forcing the user to register a clone method. 2009-07-24 13:17:00 +00:00
Jason Turner
0d3c90a245 Add "type_name" function and port the "new" in prelude to use it instead of clone/clear. 2009-07-24 04:01:28 +00:00
Jonathan Turner
2f591a25a6 Add ltrim, rtrim, and trim 2009-07-23 17:35:39 +00:00
Jonathan Turner
4127a6ed41 Added 'clear'. Added 'push_back' to string. Added char. Added simple reverse 2009-07-23 17:01:07 +00:00
Jason Turner
4e412c0f6a Fix compilation error for G++ 2009-07-23 13:03:57 +00:00
Jason Turner
370121a9ff add example.cpp to build for VC++, fix minor bug in passing of & parameters to functor<>, move bootstrap functions into bootstrap namespace and clean up function names and add "retro" support for reversing of ranges. 2009-07-23 04:35:15 +00:00
Jason Turner
00ac8113c0 Add additional support for boost::shared_ptr as a return type 2009-07-21 02:00:39 +00:00
Jonathan Turner
72b6647718 Add missing return value 2009-07-20 19:53:31 +00:00
Jason Turner
daacbaa9e0 Correct for warnings and errors for the VC++ port. 2009-07-19 03:59:58 +00:00
Jason Turner
a5a1e3ee1b Revamped method for bootstrapping of types, using a new Module class that collects everything related to a type or group of types 2009-07-19 03:04:46 +00:00
Jason Turner
5a5b2929b0 Add additional functor example 2009-07-18 23:41:01 +00:00
Jason Turner
82bd46bb1a More usage cleansups 2009-07-18 23:34:08 +00:00
Jason Turner
4d4c26bf73 Major updates to the C++ API. Please see trunk/src/example.cpp to follow along 2009-07-18 18:05:54 +00:00
Jonathan Turner
ac817ff33a Change 'elseif' to 'else if' to better support C++ expectations 2009-07-17 14:16:27 +00:00
Jason Turner
689143aba5 Fix broken push_back in prelude, to correct for unit tests. 2009-07-16 23:53:13 +00:00
Jason Turner
9b733b2621 Correct g++ compilation error caused by r308, fix for casting to const boost::shared_ptr<> &. 2009-07-16 23:46:19 +00:00
Jason Turner
727dc7b0d6 Add support for boxed_cast<> to const boost::shared_ptr<Type> &, fixing the problem Jon was having 2009-07-16 21:30:01 +00:00
Jonathan Turner
3fc5f8e8e1 Guard push_back to ensure we have the push_back_ref before we call it 2009-07-16 20:32:33 +00:00
Jonathan Turner
aed493322b Clean up exception story so that there is only one exception type and one thing the user needs to catch 2009-07-16 13:24:15 +00:00
Jason Turner
8dbb43f45f Clean up last bug fix with full support for const & (and presumably some support for const *) contained types. 2009-07-15 23:36:10 +00:00
Jason Turner
ec2f81c674 Fix bug that jon discovered that affects attempting to return a reference to an object that shares a memory location with a containing object but has a different type. 2009-07-15 23:12:49 +00:00
Jonathan Turner
724ffdcb20 Oops, resetting CMakeList.txt to the correct one 2009-07-15 14:41:21 +00:00
Jonathan Turner
7c7e437b10 Clean up unnecessary Boxed_Value copies in eval 2009-07-15 14:40:53 +00:00
236 changed files with 7135 additions and 3370 deletions

View File

@@ -1,23 +1,113 @@
cmake_minimum_required(VERSION 2.6) cmake_minimum_required(VERSION 2.8)
project(chaiscript) project(chaiscript)
SET (CMAKE_BUILD_TYPE gdb) list(APPEND CPACK_SOURCE_IGNORE_FILES "${CMAKE_CURRENT_BINARY_DIR}")
SET (CMAKE_C_FLAGS_GDB " -Wall -ggdb") list(APPEND CPACK_SOURCE_IGNORE_FILES "\\\\.svn")
SET (CMAKE_CXX_FLAGS_GDB " -Wall -ggdb") list(APPEND CPACK_SOURCE_IGNORE_FILES ".swp")
list(APPEND CPACK_SOURCE_IGNORE_FILES ".*~")
#SET (CMAKE_BUILD_TYPE rel) set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/license.txt")
#SET (CMAKE_C_FLAGS_REL " -Wall -O3") set(CPACK_RESOURCE_FILE_README "${CMAKE_CURRENT_SOURCE_DIR}/readme.txt")
#SET (CMAKE_CXX_FLAGS_REL " -Wall -O3") set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/description.txt")
set(CPACK_PACKAGE_VERSION_MAJOR 2)
set(CPACK_PACKAGE_VERSION_MINOR 3)
set(CPACK_PACKAGE_VERSION_PATCH 3)
set(CPACK_PACKAGE_EXECUTABLES "chai;ChaiScript Eval")
set(CPACK_PACKAGE_VENDOR "ChaiScript.com")
set(CPACK_PACKAGE_CONTACT "contact@chaiscript.com")
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "An embedded scripting language for C++")
set(CPACK_DEBIAN_PACKAGE_DEPENDS "libboost-dev (>=1.36.0)")
set(CPACK_DEBIAN_PACKAGE_SECTION "devel")
set(CPACK_DEBIAN_PACKAGE_PRIORITY "optional")
set(CPACK_RPM_PACKAGE_LICENSE "BSD")
set(CPACK_RPM_PACKAGE_GROUP "Programming")
set(CPACK_RPM_PACKAGE_REQUIRES "boost-devel >= 1.36.0, boost-thread >= 1.36.0")
include(CTest)
include(CPack)
FIND_LIBRARY(READLINE_LIBRARY NAMES readline PATH /usr/lib /usr/local/lib /opt/local/lib)
enable_testing()
MESSAGE(STATUS "Detecting readline support")
if (READLINE_LIBRARY)
MESSAGE(STATUS "Found: ${READLINE_LIBRARY}")
SET (READLINE_LIB readline)
ADD_DEFINITIONS(/DREADLINE_AVAILABLE)
else(READLINE_LIBRARY)
MESSAGE(STATUS "Not Found")
SET (READLINE_LIB )
SET (READLINE_FLAG )
endif(READLINE_LIBRARY)
#SET (CMAKE_C_FLAGS_REL " -Wall -O3 ${READLINE_FLAG}")
#SET (CMAKE_CXX_FLAGS_REL " -Wall -O3 ${READLINE_FLAG}")
#SET (CMAKE_C_FLAGS " -Wall -ggdb ${READLINE_FLAG}")
#SET (CMAKE_CXX_FLAGS " -Wall -ggdb ${READLINE_FLAG}")
include_directories(include) include_directories(include)
find_package(Boost 1.36.0) SET(Boost_ADDITIONAL_VERSIONS "1.43" "1.43.0" "1.42" "1.42.0" "1.41")
SET(Boost_USE_MULTITHREADED ON)
find_package(Boost 1.36.0 COMPONENTS thread)
if (Boost_FOUND) if (Boost_FOUND)
include_directories(${Boost_INCLUDE_DIRS}) link_directories( ${Boost_LIBRARY_DIRS} )
add_executable(chaiscript_eval src/main.cpp) else()
#add_executable(dispatchkit_test contrib/test/dispatchkit_test.cpp) message(FATAL_ERROR "Can not find Boost")
target_link_libraries(chaiscript_eval ${Boost_LIBRARIES})
install(TARGETS chaiscript_eval DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/bin)
endif(Boost_FOUND) endif(Boost_FOUND)
if (CMAKE_HOST_UNIX)
SET(DYNAMIC_LOADER "dl")
endif(CMAKE_HOST_UNIX)
include_directories(${Boost_INCLUDE_DIRS})
add_executable(chai src/main.cpp)
#add_executable(dispatchkit_test contrib/test/dispatchkit_test.cpp)
target_link_libraries(chai ${DYNAMIC_LOADER} ${Boost_LIBRARIES} ${READLINE_LIB})
add_library(test_module MODULE src/test_module.cpp)
target_link_libraries(test_module ${Boost_LIBRARIES})
add_library(stl_extra MODULE src/stl_extra.cpp)
target_link_libraries(stl_extra ${Boost_LIBRARIES})
file(GLOB UNIT_TESTS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/unittests/ ${CMAKE_CURRENT_SOURCE_DIR}/unittests/*.chai)
IF(BUILD_TESTING)
foreach(filename ${UNIT_TESTS})
message(STATUS "Adding test ${filename}")
add_test(${filename} chai ${CMAKE_CURRENT_SOURCE_DIR}/unittests/unit_test.inc ${CMAKE_CURRENT_SOURCE_DIR}/unittests/${filename})
endforeach(filename)
SET_PROPERTY(TEST ${UNIT_TESTS}
PROPERTY ENVIRONMENT
"CHAI_USE_PATH=${CMAKE_CURRENT_SOURCE_DIR}/unittests/"
"CHAI_MODULE_PATH=${CMAKE_CURRENT_BINARY_DIR}/"
)
ENDIF(BUILD_TESTING)
install(TARGETS chai stl_extra test_module RUNTIME DESTINATION bin LIBRARY DESTINATION lib/chaiscript )
install(DIRECTORY include/chaiscript DESTINATION include
PATTERN "*.hpp"
PATTERN "*/.svn*" EXCLUDE)
install(DIRECTORY unittests DESTINATION share/chaiscript
PATTERN "*.chai"
PATTERN "*.inc"
PATTERN "*/.svn*" EXCLUDE)
install(DIRECTORY samples DESTINATION share/chaiscript
PATTERN "*.chai"
PATTERN "*/.svn*" EXCLUDE)

View File

@@ -1 +0,0 @@
This is a placeholder

View File

@@ -1,8 +0,0 @@
#!/bin/bash
cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo .
make install
INCLUDED_FILES="include/chaiscript/*.hpp include/chaiscript/dispatchkit/*.hpp include/chaiscript/language/*.hpp bin/chaiscript_eval"
zip -r chaiscript-1.0.zip $INCLUDED_FILES

View File

@@ -0,0 +1,43 @@
function analyze_data
{
echo -n "$1," >> $2
awk 'END {printf "%s,", $1}' r$1-codesize.out >> $2
awk '{printf "%s,", $1}' r$1-numunittests.out >> $2
awk 'END {printf "%s,", $1}' r$1-unittestsoutput.out >> $2
awk '{printf "%s,", $1}' r$1-debugbinarysize.out >> $2
awk 'NR>1{exit} 1 {printf "%s,", $2}' r$1-debugbuildtime.out >> $2
awk 'NR>1{exit} 1 {printf "%s,", $2}' r$1-debugprofiletime.out >> $2
awk '{printf "%s,", $1}' r$1-releasebinarysize.out >> $2
awk 'NR>1{exit} 1 {printf "%s,", $2}' r$1-releasebuildtime.out >> $2
awk 'NR>1{exit} 1 {printf "%s,", $2}' r$1-releasemodulesbuildtime.out >> $2
awk 'NR>1{exit} 1 {printf "%s,", $2}' r$1-releaseprofiletime.out >> $2
awk 'NR>1{exit} 1 {printf "%s,", $2}' r$1-releaseunittestruntime.out >> $2
if [ -x r$1-threadfreebinarysize.out ]
then
awk '{printf "%s,", $1}' r$1-threadfreebinarysize.out >> $2
awk 'NR>1{exit} 1 {printf "%s,", $2}' r$1-threadfreeprofiletime.out >> $2
awk 'NR>1{exit} 1 {printf "%s,", $2}' r$1-1threadruntime.out >> $2
awk 'NR>1{exit} 1 {printf "%s,", $2}' r$1-2threadruntime.out >> $2
awk 'NR>1{exit} 1 {printf "%s,", $2}' r$1-4threadruntime.out >> $2
awk 'NR>1{exit} 1 {printf "%s,", $2}' r$1-8threadruntime.out >> $2
else
echo -n ",,,,,," >> $2
fi
awk -F "\n" 'NR>1{exit} 1 {printf "\"%s\"\n", $1}' r$1-revisionlog.out >> $2
}
filename=output-$1-$2.csv
echo "Revision, LOC, Num Unit Tests, Successful Unit Tests, Debug Binary Size, Debug Build Time, Debug Profile Time, Release Binary Size, Release Core Build Time, Release Modules Build Time, Release Profile Time, Release Unit Tests Time, Threadless Binary Size, Threadless Profile Time, 1 Thread Profile Time, 2 Threads Profile Time, 4 Threads Profile Time, 8 Threads Profile Time, Revision Log" > $filename
for i in `seq $1 $2`
do
analyze_data $i $filename
done

View File

@@ -0,0 +1,81 @@
function run_test
{
echo "****Getting r$1 from SVN"
svn export --quiet -r$1 http://chaiscript.googlecode.com/svn/trunk chaiscript-r$1
pushd chaiscript-r$1
echo "****Getting svn revision log"
svn propget svn:log --revprop -r$1 http://chaiscript.googlecode.com/svn/trunk > ../r$1-revisionlog.out
echo "****Editing CMakeLists.txt to allow for build type switching"
# Clean up CMakeLists.txt so that we can set the build type at configure time
sed -i -e "s/SET (CMAKE_BUILD_TYPE.*//" CMakeLists.txt
echo "****Compiling Debug Build"
cmake -D CMAKE_BUILD_TYPE=Debug CMakeLists.txt
/usr/bin/time -p make chaiscript_eval 2> ../r$1-debugbuildtime.out
echo "****Analyzing Debug Build"
/usr/bin/time -p ./chaiscript_eval ../profile.chai 2>../r$1-debugprofiletime.out
ls -s --block-size=1 ./chaiscript_eval > ../r$1-debugbinarysize.out
make clean
echo "****Compiling Release Build"
cmake -D CMAKE_BUILD_TYPE=Release CMakeLists.txt
/usr/bin/time -p make chaiscript_eval 2> ../r$1-releasebuildtime.out
echo "****Analyzing Release Build"
/usr/bin/time -p ./chaiscript_eval ../profile.chai 2>../r$1-releaseprofiletime.out
ls -s --block-size=1 ./chaiscript_eval > ../r$1-releasebinarysize.out
echo "****Analyzing Code Size"
find ./include -name "*.hpp" | xargs wc > ../r$1-codesize.out
echo "****Building Remaining Modules"
/usr/bin/time -p make 2> ../r$1-releasemodulesbuildtime.out
echo "****Running unit tests"
/usr/bin/time -p ./run_unit_tests.sh 2> ../r$1-releaseunittestruntime.out > ../r$1-unittestsoutput.out
echo "****Counting number of unit tests"
find unittests/ -name "*.chai" | wc | awk '{print $1}' > ../r$1-numunittests.out
echo "****Running multithreaded tests"
if [ -e src/multithreaded.cpp ]
then
# Run multithreaded tests
echo "****Building multithreaded test"
pushd src
g++ multithreaded.cpp -lboost_thread-mt -ldl -omultithreaded -I../include -O3
echo "****Testing 1 thread runtime"
/usr/bin/time -p ./multithreaded 1 2> ../../r$1-1threadruntime.out
echo "****Testing 2 thread runtime"
/usr/bin/time -p ./multithreaded 1 1 2> ../../r$1-2threadruntime.out
echo "****Testing 4 thread runtime"
/usr/bin/time -p ./multithreaded 1 1 1 1 2> ../../r$1-4threadruntime.out
echo "****Testing 8 thread runtime"
/usr/bin/time -p ./multithreaded 1 1 1 1 1 1 1 1 2> ../../r$1-8threadruntime.out
echo "****Compiling thread-free version"
g++ main.cpp -ldl -othreadfree -I../include -O3 -DCHAISCRIPT_NO_THREADS
echo "****Analyzing thread-free version"
/usr/bin/time -p ./threadfree ../../profile.chai 2>../../r$1-threadfreeprofiletime.out
ls -s --block-size=1 ./threadfree > ../../r$1-threadfreebinarysize.out
popd
else
echo "Multithreaded test non-existent"
fi
popd
}
for i in `seq $1 $2`
do
run_test $i
done

View File

@@ -0,0 +1,15 @@
var total = 0
for (var i = 0.0; i < 10000.0; i += 0.1) {
total += int(double(i) + int(10));
if (i < 9000.0)
{
total += double(11);
if (i > double(4000.0))
{
total += double(10);
}
}
}
print(total)

View File

@@ -0,0 +1,136 @@
<?php
/*************************************************************************************
* chaiscript.php
* --------------
* Author: Jason Turner & Jonathan Turner (based on JavaScript by Ben Keen (ben.keen@gmail.com))
* Copyright: (c) 2010 Jason Turner (lefticus@gmail.com) (c) 2009 Jonathan Turner
* (c) 2004 Ben Keen (ben.keen@gmail.com), Nigel McNie (http://qbnz.com/highlighter)
* Release Version: 1.0
* Date Started: 2009/07/03
*
* ChaiScript language file for GeSHi.
*
* CHANGES
* -------
* 2009/07/03 (1.0.0)
* - First Release
* 2010/03/30 (1.1.0)
* - Updated to include more language features and remove left over pieces from JavaScript
*
*************************************************************************************
*
* This file is part of GeSHi.
*
* GeSHi is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* GeSHi is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GeSHi; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
************************************************************************************/
$language_data = array (
'LANG_NAME' => 'Chaiscript',
'COMMENT_SINGLE' => array(1 => '//'),
'COMMENT_MULTI' => array('/*' => '*/'),
//Regular Expressions
'COMMENT_REGEXP' => array(2 => "/(?<=[\\s^])s\\/(?:\\\\.|(?!\n)[^\\/\\\\])+\\/(?:\\\\.|(?!\n)[^\\/\\\\])+\\/[gimsu]*(?=[\\s$\\.\\;])|(?<=[\\s^(=])m?\\/(?:\\\\.|(?!\n)[^\\/\\\\])+\\/[gimsu]*(?=[\\s$\\.\\,\\;\\)])/iU"),
'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE,
'QUOTEMARKS' => array("'", '"'),
'ESCAPE_CHAR' => '\\',
'KEYWORDS' => array(
1 => array(
'break', 'else', 'else if', 'eval', 'for', 'if', 'return', 'while', 'try', 'catch', 'finally',
),
2 => array(
'def', 'false', 'fun', 'true', 'var', 'attr',
),
3 => array(
// built in functions
'throw',
)
),
'SYMBOLS' => array(
'(', ')', '[', ']', '{', '}',
'+', '-', '*', '/', '%',
'!', '@', '&', '|', '^',
'<', '>', '=',
',', ';', '?', ':'
),
'CASE_SENSITIVE' => array(
GESHI_COMMENTS => false,
1 => false,
2 => false,
3 => false
),
'STYLES' => array(
'KEYWORDS' => array(
1 => 'color: #000066; font-weight: bold;',
2 => 'color: #003366; font-weight: bold;',
3 => 'color: #000066;'
),
'COMMENTS' => array(
1 => 'color: #006600; font-style: italic;',
2 => 'color: #009966; font-style: italic;',
'MULTI' => 'color: #006600; font-style: italic;'
),
'ESCAPE_CHAR' => array(
0 => 'color: #000099; font-weight: bold;'
),
'BRACKETS' => array(
0 => 'color: #009900;'
),
'STRINGS' => array(
0 => 'color: #3366CC;'
),
'NUMBERS' => array(
0 => 'color: #CC0000;'
),
'METHODS' => array(
1 => 'color: #660066;'
),
'SYMBOLS' => array(
0 => 'color: #339933;'
),
'REGEXPS' => array(
),
'SCRIPT' => array(
0 => '',
1 => '',
2 => '',
3 => ''
)
),
'URLS' => array(
1 => '',
2 => '',
3 => ''
),
'OOLANG' => true,
'OBJECT_SPLITTERS' => array(
1 => '.'
),
'REGEXPS' => array(
),
'STRICT_MODE_APPLIES' => GESHI_MAYBE,
'SCRIPT_DELIMITERS' => array(
0 => array(
),
1 => array(
)
),
'HIGHLIGHT_STRICT_BLOCK' => array(
0 => true,
1 => true
)
);
?>

7
contrib/vim/README.txt Normal file
View File

@@ -0,0 +1,7 @@
Install ftdetect, indent and syntax subdirectories to:
~/.vim/
See the vim documentation on this:
http://vimdoc.sourceforge.net/htmldoc/syntax.html#mysyntaxfile

View File

@@ -0,0 +1,2 @@
au BufRead,BufNewFile *.chai set filetype=chaiscript

View File

@@ -0,0 +1,50 @@
" Vim indent file
" Language: ChaiScript
" Maintainer: Jason Turner <lefticus 'at' gmail com>
" Only load this indent file when no other was loaded.
if exists("b:did_indent")
finish
endif
let b:did_indent = 1
setlocal indentexpr=GetChaiScriptIndent()
setlocal autoindent
" Only define the function once.
if exists("*GetChaiScriptIndent")
finish
endif
function! GetChaiScriptIndent()
" Find a non-blank line above the current line.
let lnum = prevnonblank(v:lnum - 1)
" Hit the start of the file, use zero indent.
if lnum == 0
return 0
endif
" Add a 'shiftwidth' after lines that start a block:
" lines containing a {
let ind = indent(lnum)
let flag = 0
let prevline = getline(lnum)
if prevline =~ '^.*{.*'
let ind = ind + &shiftwidth
let flag = 1
endif
" Subtract a 'shiftwidth' after lines containing a { followed by a }
" to keep it balanced
if flag == 1 && prevline =~ '.*{.*}.*'
let ind = ind - &shiftwidth
endif
" Subtract a 'shiftwidth' on lines ending with }
if getline(v:lnum) =~ '^\s*\%(}\)'
let ind = ind - &shiftwidth
endif
return ind
endfunction

View File

@@ -0,0 +1,94 @@
" Vim syntax file
" Language: ChaiScript
" Maintainer: Jason Turner <lefticus 'at' gmail com>
" Quit when a (custom) syntax file was already loaded
if exists("b:current_syntax")
finish
end
syn case match
" syncing method
syn sync fromstart
" Strings
syn region chaiscriptString start=+"+ end=+"+ skip=+\\\\\|\\"+ contains=chaiscriptSpecial,chaiscriptEval,@Spell
" Escape characters
syn match chaiscriptSpecial contained "\\[\\abfnrtv\'\"]\|\\\d\{,3}"
" String evals
syn region chaiscriptEval contained start="${" end="}"
" integer number
syn match chaiscriptNumber "\<\d\+\>"
" floating point number, with dot, optional exponent
syn match chaiscriptFloat "\<\d\+\.\d*\%(e[-+]\=\d\+\)\=\>"
" floating point number, starting with a dot, optional exponent
syn match chaiscriptFloat "\.\d\+\%(e[-+]\=\d\+\)\=\>"
" floating point number, without dot, with exponent
syn match chaiscriptFloat "\<\d\+e[-+]\=\d\+\>"
" Hex strings
syn match chaiscriptNumber "\<0x\x\+\>"
" Binary strings
syn match chaiscriptNumber "\<0b[01]\+\>"
" Various language features
syn keyword chaiscriptCond if else
syn keyword chaiscriptRepeat while for do
syn keyword chaiscriptStatement break continue return
syn keyword chaiscriptExceptions try catch throw
"Keyword
syn keyword chaiscriptKeyword def true false attr
"Built in types
syn keyword chaiscriptType fun var
"Built in funcs, keep it simple
syn keyword chaiscriptFunc eval throw
"Let's treat all backtick operator function lookups as built in too
syn region chaiscriptFunc matchgroup=chaiscriptFunc start="`" end="`"
" Account for the "[1..10]" syntax, treating it as an operator
" Intentionally leaving out all of the normal, well known operators
syn match chaiscriptOperator "\.\."
" Guard seperator as an operator
syn match chaiscriptOperator ":"
" Comments
syn match chaiscriptComment "//.*$" contains=@Spell
syn region chaiscriptComment matchgroup=chaiscriptComment start="/\*" end="\*/" contains=@Spell
hi def link chaiscriptExceptions Exception
hi def link chaiscriptKeyword Keyword
hi def link chaiscriptStatement Statement
hi def link chaiscriptRepeat Repeat
hi def link chaiscriptString String
hi def link chaiscriptNumber Number
hi def link chaiscriptFloat Float
hi def link chaiscriptOperator Operator
hi def link chaiscriptConstant Constant
hi def link chaiscriptCond Conditional
hi def link chaiscriptFunction Function
hi def link chaiscriptComment Comment
hi def link chaiscriptTodo Todo
hi def link chaiscriptError Error
hi def link chaiscriptSpecial SpecialChar
hi def link chaiscriptFunc Identifier
hi def link chaiscriptType Type
hi def link chaiscriptEval Special
let b:current_syntax = "chaiscript"
" vim: nowrap sw=2 sts=2 ts=8 noet

1
description.txt Normal file
View File

@@ -0,0 +1 @@
ChaiScript is a header-only C++ embedded scripting language loosely based on ECMA script. It is designed for ease of use and tight integration with C++. See http://www.chaiscript.com for more details.

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, Jonathan Turner (jturner@minnow-lang.org) // Copyright 2009-2010, Jonathan Turner (jturner@minnow-lang.org)
// and Jason Turner (lefticus@gmail.com) // and Jason Turner (lefticus@gmail.com)
// http://www.chaiscript.com // http://www.chaiscript.com
@@ -20,126 +20,14 @@
#include "dispatchkit/dispatchkit.hpp" #include "dispatchkit/dispatchkit.hpp"
#include "dispatchkit/bootstrap.hpp" #include "dispatchkit/bootstrap.hpp"
#include "dispatchkit/bootstrap_stl.hpp" #include "dispatchkit/bootstrap_stl.hpp"
#include "dispatchkit/function_call.hpp"
#include "dispatchkit/dynamic_object.hpp"
namespace chaiscript #ifdef BOOST_HAS_DECLSPEC
{ #define CHAISCRIPT_MODULE_EXPORT extern "C" __declspec(dllexport)
/** #else
* Types of AST nodes available to the parser and eval #define CHAISCRIPT_MODULE_EXPORT extern "C"
*/ #endif
class Token_Type { public: enum Type { Error, Int, Float, Id, Char, Str, Eol, Fun_Call, Arg_List, Variable, Equation, Var_Decl,
Expression, Comparison, Additive, Multiplicative, Negate, Not, Array_Call, Dot_Access, Quoted_String, Single_Quoted_String,
Lambda, Block, Def, While, If, For, Inline_Array, Inline_Map, Return, File, Prefix, Break, Map_Pair, Value_Range,
Inline_Range, Annotation }; };
/**
* Helper lookup to get the name of each node type
*/
const char *token_type_to_string(int tokentype) {
const char *token_types[] = { "Internal Parser Error", "Int", "Float", "Id", "Char", "Str", "Eol", "Fun_Call", "Arg_List", "Variable", "Equation", "Var_Decl",
"Expression", "Comparison", "Additive", "Multiplicative", "Negate", "Not", "Array_Call", "Dot_Access", "Quoted_String", "Single_Quoted_String",
"Lambda", "Block", "Def", "While", "If", "For", "Inline_Array", "Inline_Map", "Return", "File", "Prefix", "Break", "Map_Pair", "Value_Range",
"Inline_Range", "Annotation"};
return token_types[tokentype];
}
/**
* Convenience type for file positions
*/
struct File_Position {
int line;
int column;
File_Position(int file_line, int file_column)
: line(file_line), column(file_column) { }
File_Position() : line(0), column(0) { }
};
typedef boost::shared_ptr<struct Token> TokenPtr;
/**
* The struct that doubles as both a parser token and an AST node
*/
struct Token {
std::string text;
int identifier;
const char *filename;
File_Position start, end;
std::vector<TokenPtr> children;
TokenPtr annotation;
Token(const std::string &token_text, int id, const char *fname) : text(token_text), identifier(id), filename(fname) { }
Token(const std::string &token_text, int id, const char *fname, int start_line, int start_col, int end_line, int end_col) :
text(token_text), identifier(id), filename(fname) {
start.line = start_line;
start.column = start_col;
end.line = end_line;
end.column = end_col;
}
};
/**
* Errors generated inside the parser
*/
struct Parse_Error : public std::runtime_error {
std::string reason;
File_Position position;
const char *filename;
Parse_Error(const std::string &why, const File_Position &where, const char *fname) :
std::runtime_error("Parse error: \"" + why + "\" in '"
+ std::string(fname) + "' at: (" + boost::lexical_cast<std::string>(where.line+1) + ", " +
boost::lexical_cast<std::string>(where.column) + ")"),
reason(why), position(where), filename(fname)
{ }
Parse_Error(const std::string &why, const TokenPtr &where)
: std::runtime_error("Parse error: \"" + why + "\" in '"
+ where->filename + "' line: " + boost::lexical_cast<std::string>(where->start.line+1)),
reason(why), position(where->start), filename(where->filename) {
}
virtual ~Parse_Error() throw() {}
};
/**
* Errors generated inside the evaluator
*/
struct Eval_Error : public std::runtime_error {
std::string reason;
TokenPtr location;
Eval_Error(const std::string &why, const TokenPtr where)
: std::runtime_error("Eval error: \"" + why + "\" in '"
+ where->filename + "' line: " + boost::lexical_cast<std::string>(where->start.line+1)),
reason(why), location(where) { }
virtual ~Eval_Error() throw() {}
};
/**
* Special type for returned values
*/
struct Return_Value {
dispatchkit::Boxed_Value retval;
TokenPtr location;
Return_Value(const dispatchkit::Boxed_Value &return_value, const TokenPtr where) : retval(return_value), location(where) { }
};
/**
* Special type indicating a call to 'break'
*/
struct Break_Loop {
TokenPtr location;
Break_Loop(const TokenPtr where) : location(where) { }
};
}
#include "language/chaiscript_eval.hpp" #include "language/chaiscript_eval.hpp"
#include "language/chaiscript_engine.hpp" #include "language/chaiscript_engine.hpp"

View File

@@ -0,0 +1,73 @@
#ifndef __chaiscript_threading_hpp__
#define __chaiscript_threading_hpp__
#ifndef CHAISCRIPT_NO_THREADS
#include <boost/thread.hpp>
#else
#pragma message ("ChaiScript is compiling without thread safety.")
#endif
namespace chaiscript
{
namespace threading
{
#ifndef CHAISCRIPT_NO_THREADS
template<typename T>
class Thread_Storage
{
public:
~Thread_Storage()
{
m_thread_storage.reset();
}
inline T *operator->() const
{
if (!m_thread_storage.get())
{
m_thread_storage.reset(new T());
}
return m_thread_storage.get();
}
inline T &operator*() const
{
return *(this->operator->());
}
private:
mutable boost::thread_specific_ptr<T> m_thread_storage;
};
#else
template<typename T>
class Thread_Storage
{
public:
inline T *operator->() const
{
return &obj;
}
inline T &operator*() const
{
return obj;
}
private:
mutable T obj;
};
#endif
}
}
#endif

View File

@@ -0,0 +1,66 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2010, Jonathan Turner (jturner@minnow-lang.org)
// and Jason Turner (lefticus@gmail.com)
// http://www.chaiscript.com
#include <boost/preprocessor.hpp>
#include <boost/preprocessor/arithmetic/inc.hpp>
#define param(z,n,text) BOOST_PP_CAT(text, BOOST_PP_INC(n))
#ifndef BOOST_PP_IS_ITERATING
#ifndef __bind_first_hpp__
#define __bind_first_hpp__
#include <boost/function.hpp>
#include <boost/bind.hpp>
#include <boost/ref.hpp>
#define BOOST_PP_ITERATION_LIMITS ( 0, 8 )
#define BOOST_PP_FILENAME_1 <chaiscript/dispatchkit/bind_first.hpp>
#include BOOST_PP_ITERATE()
# endif
#else
# define n BOOST_PP_ITERATION()
# define m BOOST_PP_INC(n)
namespace chaiscript
{
template<typename Ret, typename O, typename Class BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param) >
boost::function<Ret (BOOST_PP_ENUM_PARAMS(n, Param))>
bind_first(Ret (Class::*f)(BOOST_PP_ENUM_PARAMS(n, Param)), const O &o)
{
return boost::bind(boost::mem_fn(f), o BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM(n, param, _));
}
template<typename Ret, typename O, typename Class BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param) >
boost::function<Ret (BOOST_PP_ENUM_PARAMS(n, Param))>
bind_first(Ret (Class::*f)(BOOST_PP_ENUM_PARAMS(n, Param))const, const O &o)
{
return boost::bind(boost::mem_fn(f), o BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM(n, param, _));
}
template<typename Ret,typename O BOOST_PP_COMMA_IF(m) BOOST_PP_ENUM_PARAMS(m, typename Param) >
boost::function<Ret (BOOST_PP_ENUM(n, param, Param))>
bind_first(Ret (*f)(BOOST_PP_ENUM_PARAMS(m, Param)), const O &o)
{
return boost::bind(f, o BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM(n, param, _));
}
template<typename Ret,typename O BOOST_PP_COMMA_IF(m) BOOST_PP_ENUM_PARAMS(m, typename Param) >
boost::function<Ret (BOOST_PP_ENUM(n, param, Param))>
bind_first(const boost::function<Ret (BOOST_PP_ENUM_PARAMS(m, Param))> &f, const O &o)
{
return boost::bind(f, o BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM(n, param, _));
}
}
#undef n
#undef m
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -1,47 +1,41 @@
// 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, Jonathan Turner (jturner@minnow-lang.org) // Copyright 2009-2010, Jonathan Turner (jturner@minnow-lang.org)
// and Jason Turner (lefticus@gmail.com) // and Jason Turner (lefticus@gmail.com)
// http://www.chaiscript.com // http://www.chaiscript.com
/** /**
* This file contains utility functions for registration of STL container * This file contains utility functions for registration of STL container
* classes. The methodology used is based on the SGI STL concepts. * classes. The methodology used is based on the SGI STL concepts.
* http://www.sgi.com/tech/stl/table_of_contents.html * http://www.sgi.com/tech/stl/table_of_contents.html
*/ */
#ifndef __bootstrap_stl_hpp #ifndef __bootstrap_stl_hpp__
#define __bootstrap_stl_hpp__ #define __bootstrap_stl_hpp__
#include "dispatchkit.hpp" #include "dispatchkit.hpp"
#include "register_function.hpp" #include "register_function.hpp"
namespace dispatchkit namespace chaiscript
{ {
/** namespace bootstrap
* Input_Range, based on the D concept of ranges. {
* \todo Update the Range code to base its capabilities on /**
* the type_traits of the iterator passed in * Bidir_Range, based on the D concept of ranges.
*/ * \todo Update the Range code to base its capabilities on
template<typename Container> * the user_typetraits of the iterator passed in
struct Input_Range */
template<typename Container>
struct Bidir_Range
{ {
Input_Range(Container &c) typedef typename std::iterator_traits<typename Container::iterator>::reference reference_type;
Bidir_Range(Container &c)
: m_begin(c.begin()), m_end(c.end()) : m_begin(c.begin()), m_end(c.end())
{ {
} }
Input_Range(typename Container::iterator itr)
: m_begin(itr), m_end(itr)
{
}
Input_Range(const std::pair<typename Container::iterator, typename Container::iterator> &t_p)
: m_begin(t_p.first), m_end(t_p.second)
{
}
bool empty() const bool empty() const
{ {
return m_begin == m_end; return m_begin == m_end;
@@ -56,7 +50,16 @@ namespace dispatchkit
++m_begin; ++m_begin;
} }
typename std::iterator_traits<typename Container::iterator>::reference front() const void pop_back()
{
if (empty())
{
throw std::range_error("Range empty");
}
--m_end;
}
reference_type front() const
{ {
if (empty()) if (empty())
{ {
@@ -65,120 +68,123 @@ namespace dispatchkit
return *m_begin; return *m_begin;
} }
reference_type back() const
{
if (empty())
{
throw std::range_error("Range empty");
}
typename Container::iterator pos = m_end;
--pos;
return *(pos);
}
typename Container::iterator m_begin; typename Container::iterator m_begin;
typename Container::iterator m_end; typename Container::iterator m_end;
}; };
template<typename Range>
/** struct Retro
* Add Input_Range support for the given ContainerType
*/
template<typename ContainerType>
void bootstrap_input_range(Dispatch_Engine &system, const std::string &type)
{ {
system.register_type<Input_Range<ContainerType> >(type+"_Range"); Retro(const Range &r)
system.register_type<typename ContainerType::iterator>(type+"_Iterator"); : m_r(r)
{}
system.register_function(build_constructor<Input_Range<ContainerType>, ContainerType &>(), "range"); bool empty() { return m_r.empty(); }
system.register_function(build_constructor<Input_Range<ContainerType>, void pop_front() { m_r.pop_back(); }
typename ContainerType::iterator>(), "range"); void pop_back() { m_r.pop_front(); }
typename Range::reference_type front() { return m_r.back(); }
typename Range::reference_type back() { return m_r.front(); }
typedef std::pair<typename ContainerType::iterator, typename ContainerType::iterator> ItrPair; private:
Range m_r;
system.register_function(build_constructor<Input_Range<ContainerType>, };
const ItrPair &>(), "range");
system.register_type<ItrPair>(type+"_Iterator_Pair");
register_function(system, &Input_Range<ContainerType>::empty, "empty"); /**
register_function(system, &Input_Range<ContainerType>::pop_front, "pop_front"); * Add Bidir_Range support for the given ContainerType
register_function(system, &Input_Range<ContainerType>::front, "front"); */
system.register_function(build_constructor<Input_Range<ContainerType>, const Input_Range<ContainerType> &>(), "clone"); template<typename ContainerType>
ModulePtr input_range_type(const std::string &type, ModulePtr m = ModulePtr(new Module()))
{
m->add(user_type<Bidir_Range<ContainerType> >(), type + "_Range");
copy_constructor<Bidir_Range<ContainerType> >(type + "_Range", m);
m->add(constructor<Bidir_Range<ContainerType> (ContainerType &)>(), "range");
m->add(fun(&Bidir_Range<ContainerType>::empty), "empty");
m->add(fun(&Bidir_Range<ContainerType>::pop_front), "pop_front");
m->add(fun(&Bidir_Range<ContainerType>::front), "front");
m->add(fun(&Bidir_Range<ContainerType>::pop_back), "pop_back");
m->add(fun(&Bidir_Range<ContainerType>::back), "back");
return m;
} }
/**
* Add reversible_container concept to the given ContainerType
* http://www.sgi.com/tech/stl/ReversibleContainer.html
*/
template<typename ContainerType>
void bootstrap_reversible_container(Dispatch_Engine &/*system*/, const std::string &/*type*/)
{
}
/** /**
* Add random_access_container concept to the given ContainerType * Add random_access_container concept to the given ContainerType
* http://www.sgi.com/tech/stl/RandomAccessContainer.html * http://www.sgi.com/tech/stl/RandomAccessContainer.html
*/ */
template<typename ContainerType> template<typename ContainerType>
void bootstrap_random_access_container(Dispatch_Engine &system, const std::string &type) ModulePtr random_access_container_type(const std::string &/*type*/, ModulePtr m = ModulePtr(new Module()))
{ {
bootstrap_reversible_container<ContainerType>(system, type); typedef typename ContainerType::reference(ContainerType::*indexoper)(size_t);
typedef typename ContainerType::reference(ContainerType::*indexoper)(size_t);
//In the interest of runtime safety for the system, we prefer the at() method for [] access, //In the interest of runtime safety for the m, we prefer the at() method for [] access,
//to throw an exception in an out of bounds condition. //to throw an exception in an out of bounds condition.
system.register_function( m->add(
boost::function<typename ContainerType::reference (ContainerType *, int)>(indexoper(&ContainerType::at)), "[]"); fun(boost::function<typename ContainerType::reference (ContainerType *, int)>(boost::mem_fn(static_cast<indexoper>(&ContainerType::at)))), "[]");
system.register_function(
boost::function<typename ContainerType::reference (ContainerType *, int)>(indexoper(&ContainerType::operator[])), "at");
} return m;
}
/** /**
* Add assignable concept to the given ContainerType * Add assignable concept to the given ContainerType
* http://www.sgi.com/tech/stl/Assignable.html * http://www.sgi.com/tech/stl/Assignable.html
*/ */
template<typename ContainerType> template<typename ContainerType>
void bootstrap_assignable(Dispatch_Engine &system, const std::string &type) ModulePtr assignable_type(const std::string &type, ModulePtr m = ModulePtr(new Module()))
{ {
add_basic_constructors<ContainerType>(system, type); basic_constructors<ContainerType>(type, m);
add_oper_assign<ContainerType>(system); operators::assign<ContainerType>(m);
} return m;
}
/** /**
* Add container concept to the given ContainerType * Add container concept to the given ContainerType
* http://www.sgi.com/tech/stl/Container.html * http://www.sgi.com/tech/stl/Container.html
*/ */
template<typename ContainerType> template<typename ContainerType>
void bootstrap_container(Dispatch_Engine &system, const std::string &type) ModulePtr container_type(const std::string &/*type*/, ModulePtr m = ModulePtr(new Module()))
{ {
bootstrap_assignable<ContainerType>(system, type); m->add(fun(boost::function<int (const ContainerType *)>(boost::mem_fn(&ContainerType::size))), "size");
m->add(fun<bool (ContainerType::*)() const>(&ContainerType::empty), "empty");
m->add(fun<void (ContainerType::*)()>(&ContainerType::clear), "clear");
register_function(system, &ContainerType::size, "size"); return m;
register_function(system, &ContainerType::max_size, "max_size"); }
register_function(system, &ContainerType::empty, "empty");
}
/** /**
* Add forward container concept to the given ContainerType * Add default constructable concept to the given Type
* http://www.sgi.com/tech/stl/ForwardContainer.html * http://www.sgi.com/tech/stl/DefaultConstructible.html
*/ */
template<typename ContainerType> template<typename Type>
void bootstrap_forward_container(Dispatch_Engine &system, const std::string &type) ModulePtr default_constructible_type(const std::string &type, ModulePtr m = ModulePtr(new Module()))
{ {
bootstrap_input_range<ContainerType>(system, type); m->add(constructor<Type ()>(), type);
bootstrap_container<ContainerType>(system, type); return m;
} }
/** /**
* Add default constructable concept to the given Type * Algorithm for inserting at a specific position into a container
* http://www.sgi.com/tech/stl/DefaultConstructible.html */
*/ template<typename Type>
template<typename Type>
void bootstrap_default_constructible(Dispatch_Engine &system, const std::string &type)
{
system.register_function(build_constructor<Type>(), type);
}
/**
* Algorithm for inserting at a specific position into a container
*/
template<typename Type>
void insert_at(Type &container, int pos, const typename Type::value_type &v) void insert_at(Type &container, int pos, const typename Type::value_type &v)
{ {
typename Type::iterator itr = container.begin(); typename Type::iterator itr = container.begin();
typename Type::iterator end = container.end(); typename Type::iterator end = container.end();
if (pos < 0 || std::distance(itr, end) < pos) if (pos < 0 || std::distance(itr, end) < pos)
{ {
throw std::range_error("Cannot insert past end of range"); throw std::range_error("Cannot insert past end of range");
@@ -188,15 +194,15 @@ namespace dispatchkit
container.insert(itr, v); container.insert(itr, v);
} }
/** /**
* Algorithm for erasing a specific position from a container * Algorithm for erasing a specific position from a container
*/ */
template<typename Type> template<typename Type>
void erase_at(Type &container, int pos) void erase_at(Type &container, int pos)
{ {
typename Type::iterator itr = container.begin(); typename Type::iterator itr = container.begin();
typename Type::iterator end = container.end(); typename Type::iterator end = container.end();
if (pos < 0 || std::distance(itr, end) < (pos-1)) if (pos < 0 || std::distance(itr, end) < (pos-1))
{ {
throw std::range_error("Cannot erase past end of range"); throw std::range_error("Cannot erase past end of range");
@@ -206,178 +212,246 @@ namespace dispatchkit
container.erase(itr); container.erase(itr);
} }
/** /**
* Add sequence concept to the given ContainerType * Add sequence concept to the given ContainerType
* http://www.sgi.com/tech/stl/Sequence.html * http://www.sgi.com/tech/stl/Sequence.html
*/ */
template<typename ContainerType> template<typename ContainerType>
void bootstrap_sequence(Dispatch_Engine &system, const std::string &type) ModulePtr sequence_type(const std::string &/*type*/, ModulePtr m = ModulePtr(new Module()))
{
bootstrap_forward_container<ContainerType>(system, type);
bootstrap_default_constructible<ContainerType>(system, type);
std::string insert_name;
if (typeid(typename ContainerType::value_type) == typeid(Boxed_Value))
{ {
insert_name = "insert_ref_at"; std::string insert_name;
} else { if (typeid(typename ContainerType::value_type) == typeid(Boxed_Value))
insert_name = "insert_at"; {
insert_name = "insert_ref_at";
} else {
insert_name = "insert_at";
}
m->add(fun(&insert_at<ContainerType>), insert_name);
m->add(fun(&erase_at<ContainerType>), "erase_at");
return m;
} }
register_function(system, &insert_at<ContainerType>, insert_name); /**
register_function(system, &erase_at<ContainerType>, "erase_at"); * Add back insertion sequence concept to the given ContainerType
* http://www.sgi.com/tech/stl/BackInsertionSequence.html
*/
template<typename ContainerType>
ModulePtr back_insertion_sequence_type(const std::string &/*type*/, ModulePtr m = ModulePtr(new Module()))
{
typedef typename ContainerType::reference (ContainerType::*backptr)();
m->add(fun(static_cast<backptr>(&ContainerType::back)), "back");
std::string push_back_name;
if (typeid(typename ContainerType::value_type) == typeid(Boxed_Value))
{
push_back_name = "push_back_ref";
} else {
push_back_name = "push_back";
}
typedef void (ContainerType::*pushback)(const typename ContainerType::value_type &);
m->add(fun(static_cast<pushback>(&ContainerType::push_back)), push_back_name);
m->add(fun(&ContainerType::pop_back), "pop_back");
return m;
}
/**
*Front insertion sequence
*http://www.sgi.com/tech/stl/FrontInsertionSequence.html
*/
template<typename ContainerType>
ModulePtr front_insertion_sequence_type(const std::string &type, ModulePtr m = ModulePtr(new Module()))
{
typedef typename ContainerType::reference (ContainerType::*frontptr)();
m->add(fun(static_cast<frontptr>(&ContainerType::front)), "front");
std::string push_front_name;
if (typeid(typename ContainerType::value_type) == typeid(Boxed_Value))
{
push_front_name = "push_front_ref";
} else {
push_front_name = "push_front";
}
m->add(fun(&ContainerType::push_front), push_front_name);
m->add(fun(&ContainerType::pop_front), "pop_front");
return m;
}
/**
* bootstrap a given PairType
* http://www.sgi.com/tech/stl/pair.html
*/
template<typename PairType>
ModulePtr pair_type(const std::string &type, ModulePtr m = ModulePtr(new Module()))
{
m->add(user_type<PairType>(), type);
m->add(fun(&PairType::first), "first");
m->add(fun(&PairType::second), "second");
basic_constructors<PairType>(type, m);
m->add(constructor<PairType (const typename PairType::first_type &, const typename PairType::second_type &)>(), type);
return m;
}
/**
* Add pair associative container concept to the given ContainerType
* http://www.sgi.com/tech/stl/PairAssociativeContainer.html
*/
template<typename ContainerType>
ModulePtr pair_associative_container_type(const std::string &type, ModulePtr m = ModulePtr(new Module()))
{
pair_type<typename ContainerType::value_type>(type + "_Pair", m);
return m;
}
/**
* Add unique associative container concept to the given ContainerType
* http://www.sgi.com/tech/stl/UniqueAssociativeContainer.html
*/
template<typename ContainerType>
ModulePtr unique_associative_container_type(const std::string &/*type*/, ModulePtr m = ModulePtr(new Module()))
{
m->add(fun(boost::function<int (const ContainerType *, const typename ContainerType::key_type &)>(boost::mem_fn(&ContainerType::count))), "count");
return m;
}
/**
* Add a MapType container
* http://www.sgi.com/tech/stl/Map.html
*/
template<typename MapType>
ModulePtr map_type(const std::string &type, ModulePtr m = ModulePtr(new Module()))
{
m->add(user_type<MapType>(), type);
typedef typename MapType::mapped_type &(MapType::*elemaccess)(const typename MapType::key_type &);
m->add(fun(static_cast<elemaccess>(&MapType::operator[])), "[]");
container_type<MapType>(type, m);
assignable_type<MapType>(type, m);
unique_associative_container_type<MapType>(type, m);
pair_associative_container_type<MapType>(type, m);
input_range_type<MapType>(type, m);
return m;
}
/**
* hopefully working List type
* http://www.sgi.com/tech/stl/List.html
*/
template<typename ListType>
ModulePtr list_type(const std::string &type, ModulePtr m = ModulePtr(new Module()))
{
m->add(user_type<ListType>(), type);
front_insertion_sequence_type<ListType>(type, m);
back_insertion_sequence_type<ListType>(type, m);
sequence_type<ListType>(type, m);
container_type<ListType>(type, m);
default_constructible_type<ListType>(type, m);
assignable_type<ListType>(type, m);
input_range_type<ListType>(type, m);
return m;
}
/**
* Create a vector type with associated concepts
* http://www.sgi.com/tech/stl/Vector.html
*/
template<typename VectorType>
ModulePtr vector_type(const std::string &type, ModulePtr m = ModulePtr(new Module()))
{
m->add(user_type<VectorType>(), type);
typedef typename VectorType::reference (VectorType::*frontptr)();
m->add(fun(static_cast<frontptr>(&VectorType::front)), "front");
back_insertion_sequence_type<VectorType>(type, m);
sequence_type<VectorType>(type, m);
random_access_container_type<VectorType>(type, m);
container_type<VectorType>(type, m);
default_constructible_type<VectorType>(type, m);
assignable_type<VectorType>(type, m);
input_range_type<VectorType>(type, m);
m->eval("def Vector::`==`(rhs) : type_match(rhs, this) { \
if ( rhs.size() != this.size() ) { \
return false; \
} else { \
var r1 = range(this); \
var r2 = range(rhs); \
while (!r1.empty()) \
{ \
if (!eq(r1.front(), r2.front())) \
{ \
return false; \
} \
r1.pop_front(); \
r2.pop_front(); \
} \
return true; \
} \
}");
return m;
}
/**
* Add a String container
* http://www.sgi.com/tech/stl/basic_string.html
*/
template<typename String>
ModulePtr string_type(const std::string &type, ModulePtr m = ModulePtr(new Module()))
{
m->add(user_type<String>(), type);
operators::addition<String>(m);
operators::assign_sum<String>(m);
opers_comparison<String>(m);
random_access_container_type<String>(type, m);
sequence_type<String>(type, m);
default_constructible_type<String>(type, m);
container_type<String>(type, m);
assignable_type<String>(type, m);
input_range_type<String>(type, m);
//Special case: add push_back to string (which doesn't support other back_insertion operations
std::string push_back_name;
if (typeid(typename String::value_type) == typeid(Boxed_Value))
{
push_back_name = "push_back_ref";
} else {
push_back_name = "push_back";
}
m->add(fun(&String::push_back), push_back_name);
typedef typename String::size_type (String::*find_func_ptr)(const String &, typename String::size_type) const;
typedef boost::function<int (const String *, const String &, int)> find_func;
m->add(fun(find_func(boost::mem_fn(static_cast<find_func_ptr>(&String::find)))), "find");
m->add(fun(find_func(boost::mem_fn(static_cast<find_func_ptr>(&String::rfind)))), "rfind");
m->add(fun(find_func(boost::mem_fn(static_cast<find_func_ptr>(&String::find_first_of)))), "find_first_of");
m->add(fun(find_func(boost::mem_fn(static_cast<find_func_ptr>(&String::find_last_of)))), "find_last_of");
m->add(fun(find_func(boost::mem_fn(static_cast<find_func_ptr>(&String::find_first_not_of)))), "find_first_not_of");
m->add(fun(find_func(boost::mem_fn(static_cast<find_func_ptr>(&String::find_last_not_of)))), "find_last_not_of");
return m;
}
} }
/**
* Add back insertion sequence concept to the given ContainerType
* http://www.sgi.com/tech/stl/BackInsertionSequence.html
*/
template<typename ContainerType>
void bootstrap_back_insertion_sequence(Dispatch_Engine &system, const std::string &type)
{
bootstrap_sequence<ContainerType>(system, type);
typedef typename ContainerType::reference (ContainerType::*backptr)();
register_function(system, (backptr(&ContainerType::back)), "back");
std::string push_back_name;
if (typeid(typename ContainerType::value_type) == typeid(Boxed_Value))
{
push_back_name = "push_back_ref";
} else {
push_back_name = "push_back";
}
register_function(system, &ContainerType::push_back, push_back_name);
register_function(system, &ContainerType::pop_back, "pop_back");
}
/**
* Create a vector type with associated concepts
* http://www.sgi.com/tech/stl/Vector.html
*/
template<typename VectorType>
void bootstrap_vector(Dispatch_Engine &system, const std::string &type)
{
system.register_type<VectorType>(type);
bootstrap_random_access_container<VectorType>(system, type);
bootstrap_back_insertion_sequence<VectorType>(system, type);
}
/**
* Create a vector type with associated concepts
* http://www.sgi.com/tech/stl/Vector.html
*/
template<typename ContainerType>
void bootstrap_associative_container(Dispatch_Engine &system, const std::string &type)
{
bootstrap_forward_container<ContainerType>(system, type);
bootstrap_default_constructible<ContainerType>(system, type);
}
/**
* bootstrap a given PairType
* http://www.sgi.com/tech/stl/pair.html
*/
template<typename PairType>
void bootstrap_pair(Dispatch_Engine &system, const std::string &type)
{
system.register_type<PairType>(type);
register_member(system, &PairType::first, "first");
register_member(system, &PairType::second, "second");
system.register_function(build_constructor<PairType >(), type);
system.register_function(build_constructor<PairType, const PairType &>(), type);
system.register_function(build_constructor<PairType, const PairType &>(), "clone");
system.register_function(build_constructor<PairType, const typename PairType::first_type &, const typename PairType::second_type &>(), type);
}
/**
* Add pair associative container concept to the given ContainerType
* http://www.sgi.com/tech/stl/PairAssociativeContainer.html
*/
template<typename ContainerType>
void bootstrap_pair_associative_container(Dispatch_Engine &system, const std::string &type)
{
bootstrap_associative_container<ContainerType>(system, type);
bootstrap_pair<typename ContainerType::value_type>(system, type + "_Pair");
}
/**
* Add unique associative container concept to the given ContainerType
* http://www.sgi.com/tech/stl/UniqueAssociativeContainer.html
*/
template<typename ContainerType>
void bootstrap_unique_associative_container(Dispatch_Engine &system, const std::string &type)
{
bootstrap_associative_container<ContainerType>(system, type);
register_function(system, &ContainerType::count, "count");
}
/**
* Add sorted associative container concept to the given ContainerType
* http://www.sgi.com/tech/stl/SortedAssociativeContainer.html
*/
template<typename ContainerType>
void bootstrap_sorted_associative_container(Dispatch_Engine &system, const std::string &type)
{
typedef std::pair<typename ContainerType::iterator, typename ContainerType::iterator>
(ContainerType::*eq_range)(const typename ContainerType::key_type &);
bootstrap_reversible_container<ContainerType>(system, type);
bootstrap_associative_container<ContainerType>(system, type);
register_function(system, eq_range(&ContainerType::equal_range), "equal_range");
}
/**
* Add unique sorted associative container concept to the given ContainerType
* http://www.sgi.com/tech/stl/UniqueSortedAssociativeContainer.html
*/
template<typename ContainerType>
void bootstrap_unique_sorted_associative_container(Dispatch_Engine &system, const std::string &type)
{
bootstrap_sorted_associative_container<ContainerType>(system, type);
bootstrap_unique_associative_container<ContainerType>(system, type);
}
/**
* Add a MapType container
* http://www.sgi.com/tech/stl/Map.html
*/
template<typename MapType>
void bootstrap_map(Dispatch_Engine &system, const std::string &type)
{
system.register_type<MapType>(type);
register_function(system, &MapType::operator[], "[]");
bootstrap_unique_sorted_associative_container<MapType>(system, type);
bootstrap_pair_associative_container<MapType>(system, type);
}
/**
* Add a String container
* http://www.sgi.com/tech/stl/basic_string.html
*/
template<typename String>
void bootstrap_string(Dispatch_Engine &system, const std::string &type)
{
system.register_type<String>(type);
add_oper_add<String>(system);
add_oper_add_equals<String>(system);
add_opers_comparison<String>(system);
bootstrap_random_access_container<String>(system, type);
bootstrap_sequence<String>(system, type);
typedef typename String::size_type (String::*find_func)(const String &, typename String::size_type) const;
register_function(system, find_func(&String::find), "find");
register_function(system, find_func(&String::rfind), "rfind");
register_function(system, find_func(&String::find_first_of), "find_first_of");
register_function(system, find_func(&String::find_last_of), "find_last_of");
register_function(system, find_func(&String::find_first_not_of), "find_first_not_of");
register_function(system, find_func(&String::find_last_not_of), "find_last_not_of");
}
} }
#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, Jonathan Turner (jturner@minnow-lang.org) // Copyright 2009-2010, Jonathan Turner (jturner@minnow-lang.org)
// and Jason Turner (lefticus@gmail.com) // and Jason Turner (lefticus@gmail.com)
// http://www.chaiscript.com // http://www.chaiscript.com
@@ -8,6 +8,7 @@
#define __boxed_value_hpp__ #define __boxed_value_hpp__
#include "type_info.hpp" #include "type_info.hpp"
#include "../chaiscript_threading.hpp"
#include <map> #include <map>
#include <boost/shared_ptr.hpp> #include <boost/shared_ptr.hpp>
#include <boost/any.hpp> #include <boost/any.hpp>
@@ -16,8 +17,9 @@
#include <boost/bind.hpp> #include <boost/bind.hpp>
#include <boost/cstdint.hpp> #include <boost/cstdint.hpp>
#include <boost/type_traits/add_const.hpp> #include <boost/type_traits/add_const.hpp>
#include <boost/integer_traits.hpp>
namespace dispatchkit namespace chaiscript
{ {
/** /**
* Boxed_Value is the main tool of the dispatchkit. It allows * Boxed_Value is the main tool of the dispatchkit. It allows
@@ -41,49 +43,27 @@ namespace dispatchkit
*/ */
struct Data struct Data
{ {
/**
* used to provide type-erased access to the internal boost::shared_ptr
* reference count information
*/
struct Shared_Ptr_Proxy
{
virtual ~Shared_Ptr_Proxy()
{
}
virtual bool unique(boost::any *) = 0;
virtual long use_count(boost::any *) = 0;
};
/**
* Typed implementation of the Shared_Ptr_Proxy
*/
template<typename T> template<typename T>
struct Shared_Ptr_Proxy_Impl : Shared_Ptr_Proxy static bool unique(boost::any *a)
{
virtual ~Shared_Ptr_Proxy_Impl()
{
}
virtual bool unique(boost::any *a)
{ {
boost::shared_ptr<T> *ptr = boost::any_cast<boost::shared_ptr<T> >(a); boost::shared_ptr<T> *ptr = boost::any_cast<boost::shared_ptr<T> >(a);
return ptr->unique(); return ptr->unique();
} }
virtual long use_count(boost::any *a) template<typename T>
static bool is_null(boost::any *a)
{ {
boost::shared_ptr<T> *ptr = boost::any_cast<boost::shared_ptr<T> >(a); boost::shared_ptr<T> *ptr = boost::any_cast<boost::shared_ptr<T> >(a);
return ptr->use_count(); 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::shared_ptr<Shared_Ptr_Proxy> &t_proxy = boost::shared_ptr<Shared_Ptr_Proxy>()) const boost::function<bool (boost::any*)> &t_unique = boost::function<bool (boost::any*)>(),
const boost::function<bool (boost::any*)> &t_is_null = boost::function<bool (boost::any*)>())
: m_type_info(ti), m_obj(to), : m_type_info(ti), m_obj(to),
m_is_ref(tr), m_ptr_proxy(t_proxy) m_is_ref(tr), m_unique(t_unique), m_is_null(t_is_null)
{ {
} }
@@ -92,20 +72,17 @@ namespace dispatchkit
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_ptr_proxy = rhs.m_ptr_proxy; m_unique = rhs.m_unique;
m_is_null = rhs.m_is_null;
return *this; return *this;
} }
static bool get_false()
{
return false;
}
Type_Info m_type_info; Type_Info m_type_info;
boost::any m_obj; boost::any m_obj;
bool m_is_ref; bool m_is_ref;
boost::shared_ptr<Shared_Ptr_Proxy> m_ptr_proxy; boost::function<bool (boost::any*)> m_unique;
boost::function<bool (boost::any*)> m_is_null;
}; };
/** /**
@@ -116,51 +93,81 @@ namespace dispatchkit
*/ */
struct Object_Cache struct Object_Cache
{ {
Object_Cache()
: m_cullcount(0)
{
}
boost::shared_ptr<Data> get(Boxed_Value::Void_Type) boost::shared_ptr<Data> get(Boxed_Value::Void_Type)
{ {
return boost::shared_ptr<Data> (new Data( return boost::shared_ptr<Data> (new Data(
Get_Type_Info<void>::get(), detail::Get_Type_Info<void>::get(),
boost::any(), boost::any(),
false) false)
); );
} }
template<typename T> template<typename T>
boost::shared_ptr<Data> get(boost::shared_ptr<T> obj) boost::shared_ptr<Data> get(const boost::shared_ptr<T> *obj)
{ {
return get(*obj);
}
template<typename T>
boost::shared_ptr<Data> get(const boost::shared_ptr<T> &obj)
{
bool b_const = boost::is_const<T>::value;
boost::shared_ptr<Data> data(new Data( boost::shared_ptr<Data> data(new Data(
Get_Type_Info<T>::get(), detail::Get_Type_Info<T>::get(),
boost::any(obj), boost::any(obj),
false, false,
boost::shared_ptr<Data::Shared_Ptr_Proxy>(new Data::Shared_Ptr_Proxy_Impl<T>())) &Data::unique<T>,
&Data::is_null<T>)
); );
std::map<void *, Data >::iterator itr std::map<std::pair<const void *, bool>, Data>::iterator itr
= m_ptrs.find(obj.get()); = m_ptrs.find(std::make_pair(obj.get(), b_const));
if (itr != m_ptrs.end()) if (itr != m_ptrs.end())
{ {
(*data) = (itr->second); (*data) = (itr->second);
} else { } else {
m_ptrs.insert(std::make_pair(obj.get(), *data)); m_ptrs.insert(std::make_pair(std::make_pair(obj.get(), b_const), *data));
} }
return data; return data;
} }
template<typename T>
boost::shared_ptr<Data> get(T *t)
{
return get(boost::ref(*t));
}
template<typename T> template<typename T>
boost::shared_ptr<Data> get(boost::reference_wrapper<T> obj) boost::shared_ptr<Data> get(boost::reference_wrapper<T> obj)
{ {
bool b_const = boost::is_const<T>::value;
boost::shared_ptr<Data> data(new Data( boost::shared_ptr<Data> data(new Data(
Get_Type_Info<T>::get(), detail::Get_Type_Info<T>::get(),
boost::any(obj), boost::any(obj),
true) true)
); );
std::map<void *, Data >::iterator itr std::map<std::pair<const void *, bool>, Data >::iterator itr
= m_ptrs.find(obj.get_pointer()); = m_ptrs.find(std::make_pair(obj.get_pointer(), b_const) );
if (itr != m_ptrs.end()) // If the ptr is found in the cache and it is the correct type,
// return it. It may be the incorrect type when two variables share the
// same memory location. Example:
// struct test { int x; };
// test t;
// Both t and t.x share the same memory location, but do not represent
// objects of the same type.
if (itr != m_ptrs.end()
&& itr->second.m_type_info.bare_equal(data->m_type_info))
{ {
(*data) = (itr->second); (*data) = (itr->second);
} }
@@ -172,15 +179,16 @@ namespace dispatchkit
boost::shared_ptr<Data> get(const T& t) boost::shared_ptr<Data> get(const T& t)
{ {
boost::shared_ptr<Data> data(new Data( boost::shared_ptr<Data> data(new Data(
Get_Type_Info<T>::get(), detail::Get_Type_Info<T>::get(),
boost::any(boost::shared_ptr<T>(new T(t))), boost::any(boost::shared_ptr<T>(new T(t))),
false, false,
boost::shared_ptr<Data::Shared_Ptr_Proxy>(new Data::Shared_Ptr_Proxy_Impl<T>())) &Data::unique<T>,
&Data::is_null<T>)
); );
boost::shared_ptr<T> *ptr = boost::any_cast<boost::shared_ptr<T> >(&data->m_obj); boost::shared_ptr<T> *ptr = boost::any_cast<boost::shared_ptr<T> >(&data->m_obj);
m_ptrs.insert(std::make_pair(ptr->get(), *data)); m_ptrs.insert(std::make_pair(std::make_pair(ptr->get(), false), *data));
return data; return data;
} }
@@ -197,15 +205,23 @@ namespace dispatchkit
* Drop objects from the cache where there is only one (ie, our) * Drop objects from the cache where there is only one (ie, our)
* reference to it, so it may be destructed * reference to it, so it may be destructed
*/ */
void cull() void cull(bool force = false)
{ {
std::map<void *, Data >::iterator itr = m_ptrs.begin();
++m_cullcount;
if (force || m_cullcount % 20 != 0)
{
return;
}
std::map<std::pair<const void *, bool>, Data>::iterator itr = m_ptrs.begin();
while (itr != m_ptrs.end()) while (itr != m_ptrs.end())
{ {
if (itr->second.m_ptr_proxy->unique(&itr->second.m_obj) == 1) if (itr->second.m_unique(&itr->second.m_obj))
{ {
std::map<void *, Data >::iterator todel = itr; std::map<std::pair<const void *, bool>, Data >::iterator todel = itr;
++itr; ++itr;
m_ptrs.erase(todel); m_ptrs.erase(todel);
} else { } else {
@@ -214,7 +230,8 @@ namespace dispatchkit
} }
} }
std::map<void *, Data > m_ptrs; std::map<std::pair<const void *, bool>, Data> m_ptrs;
int m_cullcount;
}; };
public: public:
@@ -248,14 +265,24 @@ namespace dispatchkit
{ {
} }
void swap(Boxed_Value &rhs)
{
std::swap(m_data, rhs.m_data);
}
/** /**
* Return a reference to the static global Object_Cache * Return a reference to the static global Object_Cache
*/ */
Object_Cache &get_object_cache() static Object_Cache &get_object_cache()
{ {
static Object_Cache oc; static chaiscript::threading::Thread_Storage<Object_Cache> oc;
return oc; return *oc;
} }
static void clear_cache()
{
get_object_cache().m_ptrs.clear();
}
/** /**
* copy the values stored in rhs.m_data to m_data * copy the values stored in rhs.m_data to m_data
@@ -272,7 +299,8 @@ namespace dispatchkit
*/ */
Boxed_Value &operator=(const Boxed_Value &rhs) Boxed_Value &operator=(const Boxed_Value &rhs)
{ {
m_data = rhs.m_data; Boxed_Value temp(rhs);
swap(temp);
return *this; return *this;
} }
@@ -284,9 +312,29 @@ namespace dispatchkit
/** /**
* return true if the object is uninitialized * return true if the object is uninitialized
*/ */
bool is_unknown() const bool is_undef() const
{ {
return m_data->m_type_info.m_is_unknown; return m_data->m_type_info.is_undef();
}
bool is_const() const
{
return m_data->m_type_info.is_const();
}
bool is_type(const Type_Info &ti) const
{
return m_data->m_type_info.bare_equal(ti);
}
bool is_null() const
{
if (m_data->m_is_null)
{
return m_data->m_is_null(&m_data->m_obj);
} else {
return false;
}
} }
boost::any get() const boost::any get() const
@@ -299,150 +347,242 @@ namespace dispatchkit
return m_data->m_is_ref; return m_data->m_is_ref;
} }
bool is_pointer() const
{
return !is_ref();
}
private: private:
boost::shared_ptr<Data> m_data; boost::shared_ptr<Data> m_data;
}; };
// Cast_Helper helper classes namespace detail
{
// Cast_Helper helper classes
/** /**
* Generic Cast_Helper, for casting to any type * Generic Cast_Helper, for casting to any type
*/ */
template<typename Result> template<typename Result>
struct Cast_Helper struct Cast_Helper
{
typedef typename boost::reference_wrapper<typename boost::add_const<Result>::type > Result_Type;
static Result_Type cast(const Boxed_Value &ob)
{ {
if (ob.is_ref()) typedef typename boost::reference_wrapper<typename boost::add_const<Result>::type > Result_Type;
static Result_Type cast(const Boxed_Value &ob)
{ {
return boost::cref((boost::any_cast<boost::reference_wrapper<Result> >(ob.get())).get()); if (ob.is_ref())
} else { {
return boost::cref(*(boost::any_cast<boost::shared_ptr<Result> >(ob.get()))); if (!ob.get_type_info().is_const())
{
return boost::cref((boost::any_cast<boost::reference_wrapper<Result> >(ob.get())).get());
} else {
return boost::any_cast<boost::reference_wrapper<const Result> >(ob.get());
}
} else {
if (!ob.get_type_info().is_const())
{
return boost::cref(*(boost::any_cast<boost::shared_ptr<Result> >(ob.get())));
} else {
return boost::cref(*(boost::any_cast<boost::shared_ptr<const Result> >(ob.get())));
}
}
} }
} };
};
/** /**
* Cast_Helper for casting to a const & type * Cast_Helper for casting to a const & type
*/ */
template<typename Result> template<typename Result>
struct Cast_Helper<const Result &> struct Cast_Helper<const Result &>
{
typedef typename boost::reference_wrapper<typename boost::add_const<Result>::type > Result_Type;
static Result_Type cast(const Boxed_Value &ob)
{ {
if (ob.is_ref()) typedef typename boost::reference_wrapper<typename boost::add_const<Result>::type > Result_Type;
static Result_Type cast(const Boxed_Value &ob)
{ {
return boost::cref((boost::any_cast<boost::reference_wrapper<Result> >(ob.get())).get()); if (ob.is_ref())
} else { {
return boost::cref(*(boost::any_cast<boost::shared_ptr<Result> >(ob.get()))); if (!ob.get_type_info().is_const())
{
return boost::cref((boost::any_cast<boost::reference_wrapper<Result> >(ob.get())).get());
} else {
return boost::any_cast<boost::reference_wrapper<const Result> >(ob.get());
}
} else {
if (!ob.get_type_info().is_const())
{
return boost::cref(*(boost::any_cast<boost::shared_ptr<Result> >(ob.get())));
} else {
return boost::cref(*(boost::any_cast<boost::shared_ptr<const Result> >(ob.get())));
}
}
} }
} };
};
/** /**
* Cast_Helper for casting to a const * type * Cast_Helper for casting to a const * type
*/ */
template<typename Result> template<typename Result>
struct Cast_Helper<const Result *> struct Cast_Helper<const Result *>
{
typedef const Result * Result_Type;
static Result_Type cast(const Boxed_Value &ob)
{ {
if (ob.is_ref()) typedef const Result * Result_Type;
static Result_Type cast(const Boxed_Value &ob)
{ {
return (boost::any_cast<boost::reference_wrapper<Result> >(ob.get())).get_pointer(); if (ob.is_ref())
} else { {
return (boost::any_cast<boost::shared_ptr<Result> >(ob.get())).get(); if (!ob.get_type_info().is_const())
{
return (boost::any_cast<boost::reference_wrapper<Result> >(ob.get())).get_pointer();
} else {
return (boost::any_cast<boost::reference_wrapper<const Result> >(ob.get())).get_pointer();
}
} else {
if (!ob.get_type_info().is_const())
{
return (boost::any_cast<boost::shared_ptr<Result> >(ob.get())).get();
} else {
return (boost::any_cast<boost::shared_ptr<const Result> >(ob.get())).get();
}
}
} }
} };
};
/** /**
* Cast_Helper for casting to a * type * Cast_Helper for casting to a * type
*/ */
template<typename Result> template<typename Result>
struct Cast_Helper<Result *> struct Cast_Helper<Result *>
{
typedef Result * Result_Type;
static Result_Type cast(const Boxed_Value &ob)
{ {
if (ob.is_ref()) typedef Result * Result_Type;
static Result_Type cast(const Boxed_Value &ob)
{ {
return (boost::any_cast<boost::reference_wrapper<Result> >(ob.get())).get_pointer(); if (ob.is_ref())
} else { {
return (boost::any_cast<boost::shared_ptr<Result> >(ob.get())).get(); return (boost::any_cast<boost::reference_wrapper<Result> >(ob.get())).get_pointer();
} else {
return (boost::any_cast<boost::shared_ptr<Result> >(ob.get())).get();
}
} }
} };
};
/** /**
* Cast_Helper for casting to a & type * Cast_Helper for casting to a & type
*/ */
template<typename Result> template<typename Result>
struct Cast_Helper<Result &> struct Cast_Helper<Result &>
{
typedef typename boost::reference_wrapper<Result> Result_Type;
static Result_Type cast(const Boxed_Value &ob)
{ {
if (ob.is_ref()) typedef typename boost::reference_wrapper<Result> Result_Type;
static Result_Type cast(const Boxed_Value &ob)
{ {
return boost::any_cast<boost::reference_wrapper<Result> >(ob.get()); if (ob.is_ref())
} else { {
return boost::ref(*(boost::any_cast<boost::shared_ptr<Result> >(ob.get()))); return boost::any_cast<boost::reference_wrapper<Result> >(ob.get());
} else {
return boost::ref(*(boost::any_cast<boost::shared_ptr<Result> >(ob.get())));
}
} }
} };
};
/** /**
* Cast_Helper for casting to a boost::shared_ptr<> type * Cast_Helper for casting to a boost::shared_ptr<> type
*/ */
template<typename Result> template<typename Result>
struct Cast_Helper<typename boost::shared_ptr<Result> > struct Cast_Helper<typename boost::shared_ptr<Result> >
{
typedef typename boost::shared_ptr<Result> Result_Type;
static Result_Type cast(const Boxed_Value &ob)
{ {
return boost::any_cast<boost::shared_ptr<Result> >(ob.get()); typedef typename boost::shared_ptr<Result> Result_Type;
}
};
static Result_Type cast(const Boxed_Value &ob)
{
return boost::any_cast<boost::shared_ptr<Result> >(ob.get());
}
};
/** /**
* Cast_Helper for casting to a Boxed_Value type * Cast_Helper for casting to a boost::shared_ptr<const> type
*/ */
template<> template<typename Result>
struct Cast_Helper<Boxed_Value> struct Cast_Helper<typename boost::shared_ptr<const Result> >
{
typedef Boxed_Value Result_Type;
static Result_Type cast(const Boxed_Value &ob)
{ {
return ob; typedef typename boost::shared_ptr<const Result> Result_Type;
}
};
/** static Result_Type cast(const Boxed_Value &ob)
* Cast_Helper for casting to a const Boxed_Value & type {
*/ if (!ob.get_type_info().is_const())
template<> {
struct Cast_Helper<const Boxed_Value &> return boost::const_pointer_cast<const Result>(boost::any_cast<boost::shared_ptr<Result> >(ob.get()));
{ } else {
typedef Boxed_Value Result_Type; return boost::any_cast<boost::shared_ptr<const Result> >(ob.get());
}
}
};
static Result_Type cast(const Boxed_Value &ob) /**
* Cast_Helper for casting to a const boost::shared_ptr<> & type
*/
template<typename Result>
struct Cast_Helper<const boost::shared_ptr<Result> &>
{ {
return ob; typedef typename boost::shared_ptr<Result> Result_Type;
}
}; static Result_Type cast(const Boxed_Value &ob)
{
return boost::any_cast<boost::shared_ptr<Result> >(ob.get());
}
};
/**
* Cast_Helper for casting to a const boost::shared_ptr<const> & type
*/
template<typename Result>
struct Cast_Helper<const boost::shared_ptr<const Result> &>
{
typedef typename boost::shared_ptr<const Result> Result_Type;
static Result_Type cast(const Boxed_Value &ob)
{
if (!ob.get_type_info().is_const())
{
return boost::const_pointer_cast<const Result>(boost::any_cast<boost::shared_ptr<Result> >(ob.get()));
} else {
return boost::any_cast<boost::shared_ptr<const Result> >(ob.get());
}
}
};
/**
* Cast_Helper for casting to a Boxed_Value type
*/
template<>
struct Cast_Helper<Boxed_Value>
{
typedef const Boxed_Value & Result_Type;
static Result_Type cast(const Boxed_Value &ob)
{
return ob;
}
};
/**
* Cast_Helper for casting to a const Boxed_Value & type
*/
template<>
struct Cast_Helper<const Boxed_Value &>
{
typedef const Boxed_Value & Result_Type;
static Result_Type cast(const Boxed_Value &ob)
{
return ob;
}
};
}
/** /**
* class that is thrown in the event of a bad_boxed_cast. That is, * class that is thrown in the event of a bad_boxed_cast. That is,
@@ -452,7 +592,7 @@ namespace dispatchkit
{ {
public: public:
bad_boxed_cast(const Type_Info &t_from, const std::type_info &t_to) throw() bad_boxed_cast(const Type_Info &t_from, const std::type_info &t_to) throw()
: from(t_from.m_type_info), to(&t_to), m_what("Cannot perform boxed_cast") : from(t_from), to(&t_to), m_what("Cannot perform boxed_cast")
{ {
} }
@@ -467,7 +607,8 @@ namespace dispatchkit
{ {
return m_what.c_str(); return m_what.c_str();
} }
const std::type_info *from;
Type_Info from;
const std::type_info *to; const std::type_info *to;
private: private:
@@ -480,10 +621,10 @@ namespace dispatchkit
* int &i = boxed_cast<int &>(boxedvalue); * int &i = boxed_cast<int &>(boxedvalue);
*/ */
template<typename Type> template<typename Type>
typename Cast_Helper<Type>::Result_Type boxed_cast(const Boxed_Value &bv) typename detail::Cast_Helper<Type>::Result_Type boxed_cast(const Boxed_Value &bv)
{ {
try { try {
return Cast_Helper<Type>::cast(bv); return detail::Cast_Helper<Type>::cast(bv);
} catch (const boost::bad_any_cast &) { } catch (const boost::bad_any_cast &) {
throw bad_boxed_cast(bv.get_type_info(), typeid(Type)); throw bad_boxed_cast(bv.get_type_info(), typeid(Type));
} }
@@ -498,12 +639,12 @@ namespace dispatchkit
Boxed_POD_Value(const Boxed_Value &v) Boxed_POD_Value(const Boxed_Value &v)
: d(0), i(0), m_isfloat(false) : d(0), i(0), m_isfloat(false)
{ {
if (!v.get_type_info().m_type_info) if (v.get_type_info().is_undef())
{ {
throw boost::bad_any_cast(); throw boost::bad_any_cast();
} }
const std::type_info &inp_ = *v.get_type_info().m_type_info; const Type_Info &inp_ = v.get_type_info();
if (inp_ == typeid(double)) if (inp_ == typeid(double))
{ {
@@ -577,62 +718,194 @@ namespace dispatchkit
{ {
if (!m_isfloat && !r.m_isfloat) if (!m_isfloat && !r.m_isfloat)
{ {
return Boxed_Value(i + r.i); return smart_size(i + r.i);
} }
return Boxed_Value(((m_isfloat)?d:i) + ((r.m_isfloat)?r.d:r.i)); return Boxed_Value(((m_isfloat)?d:i) + ((r.m_isfloat)?r.d:r.i));
} }
Boxed_Value operator*(const Boxed_POD_Value &r) const
{
if (!m_isfloat && !r.m_isfloat)
{
return Boxed_Value(i * r.i);
}
return Boxed_Value(((m_isfloat)?d:i) * ((r.m_isfloat)?r.d:r.i));
}
Boxed_Value operator/(const Boxed_POD_Value &r) const
{
if (!m_isfloat && !r.m_isfloat)
{
return Boxed_Value(i / r.i);
}
return Boxed_Value(((m_isfloat)?d:i) / ((r.m_isfloat)?r.d:r.i));
}
Boxed_Value operator-(const Boxed_POD_Value &r) const Boxed_Value operator-(const Boxed_POD_Value &r) const
{ {
if (!m_isfloat && !r.m_isfloat) if (!m_isfloat && !r.m_isfloat)
{ {
return Boxed_Value(i - r.i); return smart_size(i - r.i);
} }
return Boxed_Value(((m_isfloat)?d:i) - ((r.m_isfloat)?r.d:r.i)); return Boxed_Value(((m_isfloat)?d:i) - ((r.m_isfloat)?r.d:r.i));
} }
Boxed_Value operator&(const Boxed_POD_Value &r) const
{
if (!m_isfloat && !r.m_isfloat)
{
return Boxed_Value(i & r.i);
}
throw bad_boxed_cast("& only valid for integer types");
}
Boxed_Value operator^(const Boxed_POD_Value &r) const
{
if (!m_isfloat && !r.m_isfloat)
{
return Boxed_Value(i ^ r.i);
}
throw bad_boxed_cast("^ only valid for integer types");
}
Boxed_Value operator|(const Boxed_POD_Value &r) const
{
if (!m_isfloat && !r.m_isfloat)
{
return Boxed_Value(i | r.i);
}
throw bad_boxed_cast("| only valid for integer types");
}
Boxed_Value operator/(const Boxed_POD_Value &r) const
{
if (!m_isfloat && !r.m_isfloat)
{
return smart_size(i / r.i);
}
return Boxed_Value(((m_isfloat)?d:i) / ((r.m_isfloat)?r.d:r.i));
}
Boxed_Value operator<<(const Boxed_POD_Value &r) const
{
if (!m_isfloat && !r.m_isfloat)
{
return smart_size(i << r.i);
}
throw bad_boxed_cast("<< only valid for integer types");
}
Boxed_Value operator*(const Boxed_POD_Value &r) const
{
if (!m_isfloat && !r.m_isfloat)
{
return smart_size(i * r.i);
}
return Boxed_Value(((m_isfloat)?d:i) * ((r.m_isfloat)?r.d:r.i));
}
Boxed_Value operator%(const Boxed_POD_Value &r) const
{
if (!m_isfloat && !r.m_isfloat)
{
return smart_size(i % r.i);
}
throw bad_boxed_cast("% only valid for integer types");
}
Boxed_Value operator>>(const Boxed_POD_Value &r) const
{
if (!m_isfloat && !r.m_isfloat)
{
return smart_size(i >> r.i);
}
throw bad_boxed_cast(">> only valid for integer types");
}
Boxed_Value smart_size(boost::int64_t i) const
{
if (i < boost::integer_traits<int>::const_min
|| i > boost::integer_traits<int>::const_max)
{
return Boxed_Value(i);
} else {
return Boxed_Value(static_cast<int>(i));
}
}
double d; double d;
boost::int64_t i; boost::int64_t i;
bool m_isfloat; bool m_isfloat;
}; };
/** namespace detail
* Cast_Helper for converting from Boxed_Value to Boxed_POD_Value {
*/ /**
template<> * Cast_Helper for converting from Boxed_Value to Boxed_POD_Value
struct Cast_Helper<Boxed_POD_Value> */
{ template<>
typedef Boxed_POD_Value Result_Type; struct Cast_Helper<Boxed_POD_Value>
static Result_Type cast(const Boxed_Value &ob)
{ {
return Boxed_POD_Value(ob); typedef Boxed_POD_Value Result_Type;
}
}; static Result_Type cast(const Boxed_Value &ob)
{
return Boxed_POD_Value(ob);
}
};
/**
* Cast_Helper for converting from Boxed_Value to Boxed_POD_Value
*/
template<>
struct Cast_Helper<const Boxed_POD_Value &>
{
typedef Boxed_POD_Value Result_Type;
static Result_Type cast(const Boxed_Value &ob)
{
return Boxed_POD_Value(ob);
}
};
}
template<typename T>
Boxed_Value var(T t)
{
return Boxed_Value(t);
}
template<typename T>
Boxed_Value const_var(T *t)
{
return Boxed_Value( const_cast<typename boost::add_const<T>::type>(t) );
}
template<typename T>
Boxed_Value const_var(const boost::shared_ptr<T> &t)
{
return Boxed_Value( boost::const_pointer_cast<typename boost::add_const<T>::type>(t) );
}
template<typename T>
Boxed_Value const_var(const boost::reference_wrapper<T> &t)
{
return Boxed_Value( boost::cref(t.get()) );
}
template<typename T>
Boxed_Value const_var(const T &t)
{
return Boxed_Value(boost::shared_ptr<typename boost::add_const<T>::type >(new T(t)));
}
/**
* Return true if the two Boxed_Values share the same internal type
*/
static bool type_match(Boxed_Value l, Boxed_Value r)
{
return l.get_type_info() == r.get_type_info();
}
} }
#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, Jonathan Turner (jturner@minnow-lang.org) // Copyright 2009-2010, Jonathan Turner (jturner@minnow-lang.org)
// and Jason Turner (lefticus@gmail.com) // and Jason Turner (lefticus@gmail.com)
// http://www.chaiscript.com // http://www.chaiscript.com
@@ -13,6 +13,7 @@
#include <set> #include <set>
#include <boost/shared_ptr.hpp> #include <boost/shared_ptr.hpp>
#include <boost/lexical_cast.hpp> #include <boost/lexical_cast.hpp>
#include <boost/tuple/tuple.hpp>
#include <stdexcept> #include <stdexcept>
#include <vector> #include <vector>
#include <iostream> #include <iostream>
@@ -22,49 +23,119 @@
#include "type_info.hpp" #include "type_info.hpp"
#include "proxy_functions.hpp" #include "proxy_functions.hpp"
#include "proxy_constructors.hpp" #include "proxy_constructors.hpp"
#include "dynamic_object.hpp"
#include "../chaiscript_threading.hpp"
namespace dispatchkit namespace chaiscript
{ {
class Module
{
public:
Module &add(const Type_Info &ti, const std::string &name)
{
m_typeinfos.push_back(std::make_pair(ti, name));
return *this;
}
Module &add(const Proxy_Function &f, const std::string &name)
{
m_funcs.push_back(std::make_pair(f, name));
return *this;
}
//Add a bit of chaiscript to eval during module implementation
Module &eval(const std::string &str)
{
m_evals.push_back(str);
return *this;
}
Module &add(const boost::shared_ptr<Module> &m)
{
m->apply(*this, *this);
return *m;
}
template<typename Eval, typename Engine>
void apply(Eval &t_eval, Engine &t_engine) const
{
apply(m_typeinfos.begin(), m_typeinfos.end(), t_engine);
apply(m_funcs.begin(), m_funcs.end(), t_engine);
apply_eval(m_evals.begin(), m_evals.end(), t_eval);
}
private:
std::vector<std::pair<Type_Info, std::string> > m_typeinfos;
std::vector<std::pair<Proxy_Function, std::string> > m_funcs;
std::vector<std::string> m_evals;
template<typename T, typename InItr>
void apply(InItr begin, InItr end, T &t) const
{
while (begin != end)
{
t.add(begin->first, begin->second);
++begin;
}
}
template<typename T, typename InItr>
void apply_eval(InItr begin, InItr end, T &t) const
{
while (begin != end)
{
t.eval(*begin);
++begin;
}
}
};
typedef boost::shared_ptr<Module> ModulePtr;
/** /**
* A Proxy_Function implementation that is able to take * A Proxy_Function implementation that is able to take
* a vector of Proxy_Functions and perform a dispatch on them. It is * a vector of Proxy_Functions and perform a dispatch on them. It is
* used specifically in the case of dealing with Function object variables * used specifically in the case of dealing with Function object variables
*/ */
class Dispatch_Function : public Proxy_Function class Dispatch_Function : public Proxy_Function_Base
{ {
public: public:
Dispatch_Function(const std::vector<std::pair<std::string, boost::shared_ptr<Proxy_Function> > > &t_funcs) Dispatch_Function(const std::vector<std::pair<std::string, Proxy_Function > > &t_funcs)
: m_funcs(t_funcs) : Proxy_Function_Base(std::vector<Type_Info>()),
m_funcs(t_funcs)
{ {
} }
virtual bool operator==(const Proxy_Function &) const virtual bool operator==(const Proxy_Function_Base &) const
{ {
return false; return false;
} }
virtual ~Dispatch_Function() {} virtual ~Dispatch_Function() {}
virtual Boxed_Value operator()(const std::vector<Boxed_Value> &params) virtual Boxed_Value operator()(const std::vector<Boxed_Value> &params) const
{ {
return dispatch(m_funcs, params); return dispatch(m_funcs.begin(), m_funcs.end(), params);
} }
virtual std::vector<Type_Info> get_param_types() const virtual int get_arity() const
{ {
return std::vector<Type_Info>(); return -1;
} }
virtual bool types_match(const std::vector<Boxed_Value> &types) const virtual bool call_match(const std::vector<Boxed_Value> &vals) const
{ {
typedef std::vector<std::pair<std::string, boost::shared_ptr<Proxy_Function> > > function_vec; typedef std::vector<std::pair<std::string, Proxy_Function > > function_vec;
function_vec::const_iterator begin = m_funcs.begin(); function_vec::const_iterator begin = m_funcs.begin();
function_vec::const_iterator end = m_funcs.end(); function_vec::const_iterator end = m_funcs.end();
while (begin != end) while (begin != end)
{ {
if (begin->second->types_match(types)) if (begin->second->call_match(vals))
{ {
return true; return true;
} else { } else {
@@ -81,9 +152,39 @@ namespace dispatchkit
} }
private: private:
std::vector<std::pair<std::string, boost::shared_ptr<Proxy_Function> > > m_funcs; std::vector<std::pair<std::string, Proxy_Function > > m_funcs;
}; };
/**
* Exception thrown in the case that a multi method dispatch fails
* because no matching function was found
* at runtime due to either an arity_error, a guard_error or a bad_boxed_cast
* exception
*/
struct reserved_word_error : std::runtime_error
{
reserved_word_error(const std::string &word) throw()
: std::runtime_error("Reserved word not allowed in object name: " + word)
{
}
virtual ~reserved_word_error() throw() {}
};
/**
* Exception thrown in the case that a non-const object was added as a shared object
*/
struct global_non_const : std::runtime_error
{
global_non_const() throw()
: std::runtime_error("a global object must be const")
{
}
virtual ~global_non_const() throw() {}
};
/** /**
* Main class for the dispatchkit. Handles management * Main class for the dispatchkit. Handles management
@@ -92,68 +193,105 @@ namespace dispatchkit
class Dispatch_Engine class Dispatch_Engine
{ {
public: public:
typedef std::map<std::string, dispatchkit::Type_Info> Type_Name_Map; typedef std::map<std::string, chaiscript::Type_Info> Type_Name_Map;
typedef std::map<std::string, Boxed_Value> Scope; typedef std::map<std::string, Boxed_Value> Scope;
typedef std::deque<Scope> Stack; typedef boost::tuples::tuple<std::map<std::string, Boxed_Value>, std::deque<Scope>, bool> StackData;
typedef boost::shared_ptr<StackData> Stack;
struct State
{
std::multimap<std::string, Proxy_Function> m_functions;
std::map<std::string, Boxed_Value> m_global_objects;
Type_Name_Map m_types;
std::set<std::string> m_reserved_words;
};
Dispatch_Engine() Dispatch_Engine()
: m_place_holder(boost::shared_ptr<Placeholder_Object>(new Placeholder_Object())) : m_place_holder(boost::shared_ptr<Placeholder_Object>(new Placeholder_Object()))
{ {
m_scopes.push_back(Scope()); StackData &stack = get_stack_data();
stack.get<1>().push_back(Scope());
}
~Dispatch_Engine()
{
Boxed_Value::clear_cache();
} }
/** /**
* Add a new named Proxy_Function to the system * Add a new named Proxy_Function to the system
*/ */
bool register_function(const boost::shared_ptr<Proxy_Function> &f, const std::string &name) bool add(const Proxy_Function &f, const std::string &name)
{ {
validate_object_name(name);
StackData &stack = get_stack_data();
stack.get<0>().erase(name);
return add_function(f, name); return add_function(f, name);
} }
/**
* Add a generic, named boost::function() to the system
*/
template<typename Function>
bool register_function(const Function &func, const std::string &name)
{
return add_function(boost::shared_ptr<Proxy_Function>(new Proxy_Function_Impl<Function>(func)), name);
}
/** /**
* Set the value of an object, by name. If the object * Set the value of an object, by name. If the object
* is not available in the current scope it is created * is not available in the current scope it is created
*/ */
template<typename Class> void add(const Boxed_Value &obj, const std::string &name)
void set_object(const std::string &name, const Class &obj) {
{ validate_object_name(name);
for (int i = m_scopes.size()-1; i >= 0; --i) StackData &stack = get_stack_data();
{
std::map<std::string, Boxed_Value>::const_iterator itr = m_scopes[i].find(name);
if (itr != m_scopes[i].end())
{
m_scopes[i][name] = Boxed_Value(obj);
return;
}
}
add_object(name, obj); for (int i = stack.get<1>().size()-1; i >= 0; --i)
{
std::map<std::string, Boxed_Value>::const_iterator itr = (stack.get<1>())[i].find(name);
if (itr != (stack.get<1>())[i].end())
{
stack.get<0>().erase(name);
(stack.get<1>())[i][name] = obj;
return;
}
} }
add_object(name, obj);
}
/** /**
* Adds a named object to the current scope * Adds a named object to the current scope
*/ */
template<typename Class> void add_object(const std::string &name, const Boxed_Value &obj)
void add_object(const std::string &name, const Class &obj) {
StackData &stack = get_stack_data();
validate_object_name(name);
stack.get<0>().erase(name);
stack.get<1>().back()[name] = obj;
}
/**
* Adds a new global shared object, between all the threads
*/
void add_global_const(const Boxed_Value &obj, const std::string &name)
{
StackData &stack = get_stack_data();
validate_object_name(name);
if (!obj.is_const())
{ {
m_scopes.back()[name] = Boxed_Value(obj); throw global_non_const();
} }
stack.get<0>().erase(name);
#ifndef CHAISCRIPT_NO_THREADS
boost::unique_lock<boost::shared_mutex> l(m_global_object_mutex);
#endif
m_state.m_global_objects[name] = obj;
}
/** /**
* Adds a new scope to the stack * Adds a new scope to the stack
*/ */
void new_scope() void new_scope()
{ {
m_scopes.push_back(Scope()); StackData &stack = get_stack_data();
stack.get<1>().push_back(Scope());
} }
/** /**
@@ -161,33 +299,55 @@ namespace dispatchkit
*/ */
void pop_scope() void pop_scope()
{ {
if (m_scopes.size() > 1) StackData &stack = get_stack_data();
if (stack.get<1>().size() > 1)
{ {
m_scopes.pop_back(); Scope &scope(stack.get<1>().back());
for (Scope::const_iterator itr = scope.begin();
itr != scope.end();
++itr)
{
stack.get<0>().erase(itr->first);
}
stack.get<1>().pop_back();
} else { } else {
throw std::range_error("Unable to pop global stack"); throw std::range_error("Unable to pop global stack");
} }
} }
/**
* Returns the current stack
*/
Stack get_stack()
{
return m_scopes;
}
/** /**
* Swaps out the stack with a new stack * Swaps out the stack with a new stack
* \returns the old stack * \returns the old stack
* \param[in] s The new stack * \param[in] s The new stack
*/ */
Stack set_stack(Stack s) Stack set_stack(const Stack &s)
{ {
std::swap(s, m_scopes); Stack old = m_stack_holder->stack;
m_stack_holder->stack = s;
return old;
}
Stack new_stack() const
{
Stack s(new Stack::element_type());
s->get<1>().push_back(Scope());
s->get<2>() = false;
return s; return s;
} }
Stack get_stack() const
{
return m_stack_holder->stack;
}
void sync_cache()
{
#ifndef CHAISCRIPT_NO_THREADS
boost::shared_lock<boost::shared_mutex> l(m_mutex);
#endif
sync_cache_no_lock();
}
/** /**
* Searches the current stack for an object of the given name * Searches the current stack for an object of the given name
* includes a special overload for the _ place holder object to * includes a special overload for the _ place holder object to
@@ -195,47 +355,86 @@ namespace dispatchkit
*/ */
Boxed_Value get_object(const std::string &name) const Boxed_Value get_object(const std::string &name) const
{ {
// Is it a placeholder object?
if (name == "_") if (name == "_")
{ {
return m_place_holder; return m_place_holder;
} }
for (int i = m_scopes.size()-1; i >= 0; --i) StackData &stack = get_stack_data();
std::map<std::string, Boxed_Value> &cache = stack.get<0>();
// Is it in the cache?
std::map<std::string, Boxed_Value>::const_iterator itr = cache.find(name);
if (itr != cache.end())
{ {
std::map<std::string, Boxed_Value>::const_iterator itr = m_scopes[i].find(name); return itr->second;
if (itr != m_scopes[i].end()) }
// Is it in the stack?
for (int i = stack.get<1>().size()-1; i >= 0; --i)
{
std::map<std::string, Boxed_Value>::const_iterator stackitr = (stack.get<1>())[i].find(name);
if (stackitr != (stack.get<1>())[i].end())
{ {
cache[name] = stackitr->second;
return stackitr->second;
}
}
// Is the value we are looking for a global?
{
#ifndef CHAISCRIPT_NO_THREADS
boost::shared_lock<boost::shared_mutex> l(m_global_object_mutex);
#endif
itr = m_state.m_global_objects.find(name);
if (itr != m_state.m_global_objects.end())
{
cache[name] = itr->second;
return itr->second; return itr->second;
} }
} }
std::vector<std::pair<std::string, std::multimap<std::string, boost::shared_ptr<Proxy_Function> >::mapped_type> > funcs = get_function_impl(name, false); // If all that failed, then check to see if it's a function
std::vector<std::pair<std::string, std::multimap<std::string, Proxy_Function >::mapped_type> > funcs = get_function(name);
if (funcs.empty()) if (funcs.empty())
{ {
throw std::range_error("Object not known: " + name); throw std::range_error("Object not known: " + name);
} else { } else {
return Boxed_Value(boost::shared_ptr<Proxy_Function>(new Dispatch_Function(funcs))); Boxed_Value f(Const_Proxy_Function(new Dispatch_Function(funcs)));
cache[name] = f;
return f;
} }
} }
/** /**
* Registers a new named type * Registers a new named type
*/ */
template<typename Type> void add(const Type_Info &ti, const std::string &name)
void register_type(const std::string &name) {
{ add_global_const(const_var(ti), name + "_type");
m_types.insert(std::make_pair(name, Get_Type_Info<Type>::get()));
} #ifndef CHAISCRIPT_NO_THREADS
boost::unique_lock<boost::shared_mutex> l(m_mutex);
#endif
m_state.m_types.insert(std::make_pair(name, ti));
}
/** /**
* Returns the type info for a named type * Returns the type info for a named type
*/ */
Type_Info get_type(const std::string &name) const Type_Info get_type(const std::string &name) const
{ {
Type_Name_Map::const_iterator itr = m_types.find(name); #ifndef CHAISCRIPT_NO_THREADS
boost::shared_lock<boost::shared_mutex> l(m_mutex);
#endif
if (itr != m_types.end()) Type_Name_Map::const_iterator itr = m_state.m_types.find(name);
if (itr != m_state.m_types.end())
{ {
return itr->second; return itr->second;
} }
@@ -250,17 +449,21 @@ namespace dispatchkit
*/ */
std::string get_type_name(const Type_Info &ti) const std::string get_type_name(const Type_Info &ti) const
{ {
for (Type_Name_Map::const_iterator itr = m_types.begin(); #ifndef CHAISCRIPT_NO_THREADS
itr != m_types.end(); boost::shared_lock<boost::shared_mutex> l(m_mutex);
#endif
for (Type_Name_Map::const_iterator itr = m_state.m_types.begin();
itr != m_state.m_types.end();
++itr) ++itr)
{ {
if (itr->second.m_bare_type_info == ti.m_bare_type_info) if (itr->second.bare_equal(ti))
{ {
return itr->first; return itr->first;
} }
} }
return ti.m_bare_type_info->name(); return ti.bare_name();
} }
/** /**
@@ -268,55 +471,242 @@ namespace dispatchkit
*/ */
std::vector<std::pair<std::string, Type_Info> > get_types() const std::vector<std::pair<std::string, Type_Info> > get_types() const
{ {
return std::vector<std::pair<std::string, Type_Info> >(m_types.begin(), m_types.end()); #ifndef CHAISCRIPT_NO_THREADS
boost::shared_lock<boost::shared_mutex> l(m_mutex);
#endif
return std::vector<std::pair<std::string, Type_Info> >(m_state.m_types.begin(), m_state.m_types.end());
} }
/** /**
* Return a function by name * Return a function by name
*/ */
std::vector<std::pair<std::string, std::multimap<std::string, boost::shared_ptr<Proxy_Function> >::mapped_type> > std::vector<std::pair<std::string, std::multimap<std::string, Proxy_Function >::mapped_type> >
get_function(const std::string &t_name) const get_function(const std::string &t_name) const
{ {
return get_function_impl(t_name, true); std::pair<std::multimap<std::string, Proxy_Function >::const_iterator, std::multimap<std::string, Proxy_Function >::const_iterator> range
= get_function_cache().equal_range(t_name);
return std::vector<std::pair<std::string, std::multimap<std::string, Proxy_Function >::mapped_type> >(range.first, range.second);
} }
/**
* Return true if a function exists
*/
bool function_exists(const std::string &name) const
{
std::multimap<std::string, Proxy_Function> &functions = get_function_cache();
return functions.find(name) != functions.end();
}
/** /**
* Get a vector of all registered functions * Get a vector of all registered functions
*/ */
std::vector<std::pair<std::string, boost::shared_ptr<Proxy_Function> > > get_functions() const std::vector<std::pair<std::string, Proxy_Function > > get_functions() const
{ {
return std::vector<std::pair<std::string, boost::shared_ptr<Proxy_Function> > >(m_functions.begin(), m_functions.end()); std::multimap<std::string, Proxy_Function> &functions = get_function_cache();
return std::vector<std::pair<std::string, Proxy_Function > >(functions.begin(), functions.end());
} }
void add_reserved_word(const std::string &name)
{
#ifndef CHAISCRIPT_NO_THREADS
boost::unique_lock<boost::shared_mutex> l(m_mutex);
#endif
m_state.m_reserved_words.insert(name);
}
Boxed_Value call_function(const std::string &t_name, const std::vector<Boxed_Value> &params) const
{
std::multimap<std::string, Proxy_Function> &functions = get_function_cache();
std::pair<std::multimap<std::string, Proxy_Function >::const_iterator, std::multimap<std::string, Proxy_Function >::const_iterator> range
= functions.equal_range(t_name);
return dispatch(range.first, range.second, params);
}
Boxed_Value call_function(const std::string &t_name) const
{
return call_function(t_name, std::vector<Boxed_Value>());
}
Boxed_Value call_function(const std::string &t_name, const Boxed_Value &p1) const
{
std::vector<Boxed_Value> params;
params.push_back(p1);
return call_function(t_name, params);
}
Boxed_Value call_function(const std::string &t_name, const Boxed_Value &p1, const Boxed_Value &p2) const
{
std::vector<Boxed_Value> params;
params.push_back(p1);
params.push_back(p2);
return call_function(t_name, params);
}
/**
* Dump object info to stdout
*/
void dump_object(Boxed_Value o) const
{
Type_Info ti = o.get_type_info();
std::cout << (ti.is_const()?"const ":"") << get_type_name(ti) << std::endl;
}
/**
* Dump type info to stdout
*/
void dump_type(const Type_Info &type) const
{
std::cout << (type.is_const()?"const ":"") << get_type_name(type);
}
/**
* Dump function to stdout
*/
void dump_function(const std::pair<const std::string, Proxy_Function > &f) const
{
std::vector<Type_Info> params = f.second->get_param_types();
std::string annotation = f.second->annotation();
if (annotation.size() > 0) {
std::cout << annotation;
}
dump_type(params.front());
std::cout << " " << f.first << "(";
for (std::vector<Type_Info>::const_iterator itr = params.begin() + 1;
itr != params.end();
)
{
dump_type(*itr);
++itr;
if (itr != params.end())
{
std::cout << ", ";
}
}
std::cout << ") " << std::endl;
}
/**
* Dump all system info to stdout
*/
void dump_system() const
{
std::cout << "Registered Types: " << std::endl;
std::vector<std::pair<std::string, Type_Info> > types = get_types();
for (std::vector<std::pair<std::string, Type_Info> >::const_iterator itr = types.begin();
itr != types.end();
++itr)
{
std::cout << itr->first << ": ";
std::cout << itr->second.bare_name();
std::cout << std::endl;
}
std::cout << std::endl;
std::vector<std::pair<std::string, Proxy_Function > > funcs = get_functions();
std::cout << "Functions: " << std::endl;
for (std::vector<std::pair<std::string, Proxy_Function > >::const_iterator itr = funcs.begin();
itr != funcs.end();
++itr)
{
dump_function(*itr);
}
std::cout << std::endl;
}
/**
* return true if the Boxed_Value matches the registered type by name
*/
bool is_type(Boxed_Value r, const std::string &user_typename) const
{
try {
if (get_type(user_typename).bare_equal(r.get_type_info()))
{
return true;
}
} catch (const std::range_error &) {
}
try {
const Dynamic_Object &d = boxed_cast<const Dynamic_Object &>(r);
return d.get_type_name() == user_typename;
} catch (const std::bad_cast &) {
}
return false;
}
std::string type_name(Boxed_Value obj) const
{
return get_type_name(obj.get_type_info());
}
State get_state()
{
#ifndef CHAISCRIPT_NO_THREADS
boost::unique_lock<boost::shared_mutex> l(m_mutex);
boost::unique_lock<boost::shared_mutex> l2(m_global_object_mutex);
#endif
return m_state;
}
void set_state(const State &t_state)
{
#ifndef CHAISCRIPT_NO_THREADS
boost::unique_lock<boost::shared_mutex> l(m_mutex);
boost::unique_lock<boost::shared_mutex> l2(m_global_object_mutex);
#endif
m_state = t_state;
sync_cache_no_lock();
}
private: private:
/** /**
* Implementation detail for searching for a function by name. * Returns the current stack
* Looks for all registered global functions and optionally for an object * make const/non const versions
* in scope with the same name
*/ */
std::vector<std::pair<std::string, std::multimap<std::string, boost::shared_ptr<Proxy_Function> >::mapped_type> > StackData &get_stack_data() const
get_function_impl(const std::string &t_name, bool include_objects) const
{ {
std::vector<std::pair<std::string, std::multimap<std::string, boost::shared_ptr<Proxy_Function> >::mapped_type> > funcs; return *(m_stack_holder->stack);
}
if (include_objects) std::multimap<std::string, Proxy_Function> &get_function_cache() const
{
return m_stack_holder->function_cache;
}
void sync_cache_no_lock()
{
m_stack_holder->stack->get<0>().clear();
get_function_cache() = m_state.m_functions;
}
/**
* Throw a reserved_word exception if the name is not allowed
*/
void validate_object_name(const std::string &name) const
{
#ifndef CHAISCRIPT_NO_THREADS
boost::shared_lock<boost::shared_mutex> l(m_mutex);
#endif
if (m_state.m_reserved_words.find(name) != m_state.m_reserved_words.end())
{ {
try { throw reserved_word_error(name);
funcs.insert(funcs.end(),
std::make_pair(
t_name,
boxed_cast<std::multimap<std::string, boost::shared_ptr<Proxy_Function> >::mapped_type>(get_object(t_name)))
);
} catch (const bad_boxed_cast &) {
} catch (const std::range_error &) {
}
} }
std::pair<std::multimap<std::string, boost::shared_ptr<Proxy_Function> >::const_iterator, std::multimap<std::string, boost::shared_ptr<Proxy_Function> >::const_iterator> range
= m_functions.equal_range(t_name);
funcs.insert(funcs.end(), range.first, range.second);
return funcs;
} }
/** /**
@@ -324,10 +714,14 @@ namespace dispatchkit
* true if the function was added, false if a function with the * true if the function was added, false if a function with the
* same signature and name already exists. * same signature and name already exists.
*/ */
bool add_function(const boost::shared_ptr<Proxy_Function> &f, const std::string &t_name) bool add_function(const Proxy_Function &f, const std::string &t_name)
{ {
std::pair<std::multimap<std::string, boost::shared_ptr<Proxy_Function> >::const_iterator, std::multimap<std::string, boost::shared_ptr<Proxy_Function> >::const_iterator> range #ifndef CHAISCRIPT_NO_THREADS
= m_functions.equal_range(t_name); boost::unique_lock<boost::shared_mutex> l(m_mutex);
#endif
std::pair<std::multimap<std::string, Proxy_Function >::const_iterator, std::multimap<std::string, Proxy_Function >::const_iterator> range
= m_state.m_functions.equal_range(t_name);
while (range.first != range.second) while (range.first != range.second)
{ {
@@ -338,91 +732,38 @@ namespace dispatchkit
++range.first; ++range.first;
} }
m_functions.insert(std::make_pair(t_name, f)); m_state.m_functions.insert(std::make_pair(t_name, f));
get_function_cache().insert(std::make_pair(t_name, f));
return true; return true;
} }
std::deque<Scope> m_scopes; #ifndef CHAISCRIPT_NO_THREADS
mutable boost::shared_mutex m_mutex;
mutable boost::shared_mutex m_global_object_mutex;
#endif
struct Stack_Holder
{
Stack_Holder()
: stack(new StackData())
{
stack->get<2>() = true;
}
Stack stack;
std::multimap<std::string, Proxy_Function> function_cache;
};
chaiscript::threading::Thread_Storage<Stack_Holder> m_stack_holder;
State m_state;
std::multimap<std::string, boost::shared_ptr<Proxy_Function> > m_functions;
Type_Name_Map m_types;
Boxed_Value m_place_holder; Boxed_Value m_place_holder;
}; };
/**
* Dump object info to stdout
*/
void dump_object(Boxed_Value o, const Dispatch_Engine &e)
{
std::cout << e.get_type_name(o.get_type_info()) << std::endl;
}
/**
* Dump type info to stdout
*/
void dump_type(const Type_Info &type, const Dispatch_Engine &e)
{
std::cout << e.get_type_name(type);
}
/**
* Dump function to stdout
*/
void dump_function(const std::pair<const std::string, boost::shared_ptr<Proxy_Function> > &f, const Dispatch_Engine &e)
{
std::vector<Type_Info> params = f.second->get_param_types();
std::string annotation = f.second->annotation();
if (annotation.size() > 0) {
std::cout << annotation;
}
dump_type(params.front(), e);
std::cout << " " << f.first << "(";
for (std::vector<Type_Info>::const_iterator itr = params.begin() + 1;
itr != params.end();
)
{
dump_type(*itr, e);
++itr;
if (itr != params.end())
{
std::cout << ", ";
}
}
std::cout << ") " << std::endl;
}
/**
* Dump all system info to stdout
*/
void dump_system(const Dispatch_Engine &s)
{
std::cout << "Registered Types: " << std::endl;
std::vector<std::pair<std::string, Type_Info> > types = s.get_types();
for (std::vector<std::pair<std::string, Type_Info> >::const_iterator itr = types.begin();
itr != types.end();
++itr)
{
std::cout << itr->first << ": ";
std::cout << itr->second.m_bare_type_info->name();
std::cout << std::endl;
}
std::cout << std::endl;
std::vector<std::pair<std::string, boost::shared_ptr<Proxy_Function> > > funcs = s.get_functions();
std::cout << "Functions: " << std::endl;
for (std::vector<std::pair<std::string, boost::shared_ptr<Proxy_Function> > >::const_iterator itr = funcs.begin();
itr != funcs.end();
++itr)
{
dump_function(*itr, s);
}
std::cout << std::endl;
}
} }
#endif #endif

View File

@@ -0,0 +1,226 @@
#ifndef __DYNAMIC_OBJECT_HPP__
#define __DYNAMIC_OBJECT_HPP__
#include <boost/optional.hpp>
namespace chaiscript
{
class Dynamic_Object
{
public:
Dynamic_Object(const std::string &t_type_name)
: m_type_name(t_type_name)
{
}
std::string get_type_name() const
{
return m_type_name;
}
Boxed_Value get_attr(const std::string &t_attr_name)
{
return m_attrs[t_attr_name];
}
std::map<std::string, Boxed_Value> get_attrs()
{
return m_attrs;
}
private:
std::string m_type_name;
std::map<std::string, Boxed_Value> m_attrs;
};
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 bad_boxed_cast("Dynamic object type mismatch");
}
return t_do.get_attr(t_attr_name);
}
};
/**
* A Proxy_Function implementation designed for calling a function
* that is automatically guarded based on the first param based on the
* param's type name
*/
class Dynamic_Object_Function : public Proxy_Function_Base
{
public:
Dynamic_Object_Function(
const std::string &t_type_name,
const Proxy_Function &t_func,
const boost::optional<Type_Info> &t_ti = boost::optional<Type_Info>())
: Proxy_Function_Base(t_func->get_param_types()),
m_type_name(t_type_name), m_func(t_func), m_ti(t_ti)
{
assert( (t_func->get_arity() > 0 || t_func->get_arity() < 0)
&& "Programming error, Dynamic_Object_Function must have at least one parameter (this)");
}
virtual ~Dynamic_Object_Function() {}
virtual bool operator==(const Proxy_Function_Base &f) const
{
try
{
const Dynamic_Object_Function &df = dynamic_cast<const Dynamic_Object_Function &>(f);
return df.m_type_name == m_type_name && (*df.m_func) == (*m_func);
} catch (const std::bad_cast &) {
return false;
}
}
virtual bool call_match(const std::vector<Boxed_Value> &vals) const
{
if (dynamic_object_typename_match(vals, m_type_name, m_ti))
{
return m_func->call_match(vals);
} else {
return false;
}
}
virtual Boxed_Value operator()(const std::vector<Boxed_Value> &params) const
{
if (dynamic_object_typename_match(params, m_type_name, m_ti))
{
return (*m_func)(params);
} else {
throw guard_error();
}
}
virtual int get_arity() const
{
return m_func->get_arity();
}
virtual std::string annotation() const
{
return m_func->annotation();
}
private:
static bool dynamic_object_typename_match(const std::vector<Boxed_Value> &bvs, const std::string &name,
const boost::optional<Type_Info> &ti)
{
if (bvs.size() > 0)
{
try {
const Dynamic_Object &d = boxed_cast<const Dynamic_Object &>(bvs[0]);
return name == "Dynamic_Object" || d.get_type_name() == name;
} catch (const std::bad_cast &) {
if (ti)
{
return bvs[0].get_type_info().bare_equal(*ti);
} else {
return false;
}
}
} else {
return false;
}
}
std::string m_type_name;
Proxy_Function m_func;
boost::optional<Type_Info> m_ti;
};
/**
* A Proxy_Function implementation designed for creating a new
* Dynamic_Object
* that is automatically guarded based on the first param based on the
* param's type name
*/
class Dynamic_Object_Constructor : public Proxy_Function_Base
{
public:
Dynamic_Object_Constructor(
const std::string &t_type_name,
const Proxy_Function &t_func)
: Proxy_Function_Base(build_type_list(t_func->get_param_types())),
m_type_name(t_type_name), m_func(t_func)
{
assert( (t_func->get_arity() > 0 || t_func->get_arity() < 0)
&& "Programming error, Dynamic_Object_Function must have at least one parameter (this)");
}
static std::vector<Type_Info> build_type_list(const std::vector<Type_Info> &tl)
{
std::vector<Type_Info>::const_iterator begin = tl.begin();
std::vector<Type_Info>::const_iterator end = tl.end();
if (begin != end)
{
++begin;
}
return std::vector<Type_Info>(begin, end);
}
virtual ~Dynamic_Object_Constructor() {}
virtual bool operator==(const Proxy_Function_Base &f) const
{
try
{
const Dynamic_Object_Constructor &dc = dynamic_cast<const Dynamic_Object_Constructor&>(f);
return dc.m_type_name == m_type_name && (*dc.m_func) == (*m_func);
} catch (const std::bad_cast &) {
return false;
}
}
virtual bool call_match(const std::vector<Boxed_Value> &vals) const
{
std::vector<Boxed_Value> new_vals;
new_vals.push_back(Boxed_Value(Dynamic_Object(m_type_name)));
new_vals.insert(new_vals.end(), vals.begin(), vals.end());
return m_func->call_match(new_vals);
}
virtual Boxed_Value operator()(const std::vector<Boxed_Value> &params) const
{
std::vector<Boxed_Value> new_params;
chaiscript::Boxed_Value bv = var(Dynamic_Object(m_type_name));
new_params.push_back(bv);
new_params.insert(new_params.end(), params.begin(), params.end());
(*m_func)(new_params);
return bv;
}
virtual int get_arity() const
{
// "this" is not considered part of the arity
return m_func->get_arity() - 1;
}
virtual std::string annotation() const
{
return m_func->annotation();
}
private:
std::string m_type_name;
Proxy_Function m_func;
};
}
#endif

View File

@@ -1,16 +1,9 @@
// 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, Jonathan Turner (jturner@minnow-lang.org) // Copyright 2009-2010, Jonathan Turner (jturner@minnow-lang.org)
// and Jason Turner (lefticus@gmail.com) // and Jason Turner (lefticus@gmail.com)
// http://www.chaiscript.com // http://www.chaiscript.com
#include <boost/preprocessor.hpp>
#define addparam(z,n,text) params.push_back(Boxed_Value(BOOST_PP_CAT(p, n) ));
#define curry(z,n,text) BOOST_PP_CAT(_, BOOST_PP_INC(n))
#ifndef BOOST_PP_IS_ITERATING
#ifndef __function_call_hpp__ #ifndef __function_call_hpp__
#define __function_call_hpp__ #define __function_call_hpp__
@@ -20,52 +13,9 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include "proxy_functions.hpp" #include "proxy_functions.hpp"
#include "function_call_detail.hpp"
namespace dispatchkit namespace chaiscript
{
/**
* Internal helper class for handling the return
* value of a build_function_caller
*/
template<typename Ret>
class Function_Caller_Ret
{
public:
Function_Caller_Ret()
{
}
Ret call(const std::vector<std::pair<std::string, boost::shared_ptr<Proxy_Function> > > &t_funcs,
const std::vector<Boxed_Value> &params)
{
return boxed_cast<Ret>(dispatch(t_funcs, params));
}
};
/**
* Specialization for void return types
*/
template<>
class Function_Caller_Ret<void>
{
public:
Function_Caller_Ret()
{
}
void call(const std::vector<std::pair<std::string, boost::shared_ptr<Proxy_Function> > > &t_funcs,
const std::vector<Boxed_Value> &params)
{
dispatch(t_funcs, params);
}
};
}
#define BOOST_PP_ITERATION_LIMITS ( 0, 9 )
#define BOOST_PP_FILENAME_1 <chaiscript/dispatchkit/function_call.hpp>
#include BOOST_PP_ITERATE()
namespace dispatchkit
{ {
/** /**
* Build a function caller that knows how to dispatch on a set of functions * Build a function caller that knows how to dispatch on a set of functions
@@ -77,10 +27,10 @@ namespace dispatchkit
*/ */
template<typename FunctionType> template<typename FunctionType>
boost::function<FunctionType> boost::function<FunctionType>
build_function_caller(const std::vector<std::pair<std::string, boost::shared_ptr<Proxy_Function> > > &funcs) functor(const std::vector<std::pair<std::string, Proxy_Function > > &funcs)
{ {
FunctionType *p; FunctionType *p=0;
return build_function_caller_helper(p, funcs); return detail::build_function_caller_helper(p, funcs);
} }
/** /**
@@ -88,7 +38,7 @@ namespace dispatchkit
* useful in the case that a function is being pass out from scripting back * useful in the case that a function is being pass out from scripting back
* into code * into code
* example: * example:
* void my_function(boost::shared_ptr<Proxy_Function> f) * void my_function(Proxy_Function f)
* { * {
* boost::function<void (int)> local_f = * boost::function<void (int)> local_f =
* build_function_caller(f); * build_function_caller(f);
@@ -98,11 +48,11 @@ namespace dispatchkit
*/ */
template<typename FunctionType> template<typename FunctionType>
boost::function<FunctionType> boost::function<FunctionType>
build_function_caller(boost::shared_ptr<Proxy_Function> func) functor(Proxy_Function func)
{ {
std::vector<std::pair<std::string, boost::shared_ptr<Proxy_Function> > > funcs; std::vector<std::pair<std::string, Proxy_Function > > funcs;
funcs.push_back(std::make_pair(std::string(), func)); funcs.push_back(std::make_pair(std::string(), func));
return build_function_caller<FunctionType>(funcs); return functor<FunctionType>(funcs);
} }
/** /**
@@ -111,58 +61,11 @@ namespace dispatchkit
*/ */
template<typename FunctionType> template<typename FunctionType>
boost::function<FunctionType> boost::function<FunctionType>
build_function_caller(const Boxed_Value &bv) functor(const Boxed_Value &bv)
{ {
return build_function_caller<FunctionType>(boxed_cast<boost::shared_ptr<Proxy_Function> >(bv)); return functor<FunctionType>(boxed_cast<Proxy_Function >(bv));
} }
/**
* Helper for calling script code as if it were native C++ code
* example:
* boost::function<int (int, int)> f = build_functor(chai, "func(x, y){x+y}");
* \return a boost::function representing the passed in script
* \param[in] e ScriptEngine to build the script execution from
* \param[in] script Script code to build a function from
*/
template<typename FunctionType, typename ScriptEngine>
boost::function<FunctionType> build_functor(ScriptEngine &e, const std::string &script)
{
return build_function_caller<FunctionType>(e.evaluate_string(script));
}
}
# endif
#else
# define n BOOST_PP_ITERATION()
namespace dispatchkit
{
/**
* used internally for unwrapping a function call's types
*/
template<typename Ret BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param) >
Ret function_caller(const std::vector<std::pair<std::string, boost::shared_ptr<Proxy_Function> > > &funcs
BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_BINARY_PARAMS(n, Param, p) )
{
std::vector<Boxed_Value> params;
BOOST_PP_REPEAT(n, addparam, ~)
return Function_Caller_Ret<Ret>().call(funcs, params);
}
/**
* used internally for unwrapping a function call's types
*/
template<typename Ret BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param) >
boost::function<Ret (BOOST_PP_ENUM_PARAMS(n, Param)) >
build_function_caller_helper(Ret (BOOST_PP_ENUM_PARAMS(n, Param)), const std::vector<std::pair<std::string, boost::shared_ptr<Proxy_Function> > > &funcs)
{
return boost::bind(&function_caller<Ret BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, Param)>, funcs
BOOST_PP_ENUM_TRAILING(n, curry, ~));
}
} }
#endif #endif

View File

@@ -0,0 +1,99 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2010, Jonathan Turner (jturner@minnow-lang.org)
// and Jason Turner (lefticus@gmail.com)
// http://www.chaiscript.com
#include <boost/preprocessor.hpp>
#define addparam(z,n,text) params.push_back(boost::is_reference<Param ## n>::value?Boxed_Value(boost::ref(BOOST_PP_CAT(p, n))):Boxed_Value(BOOST_PP_CAT(p, n) ));
#define curry(z,n,text) BOOST_PP_CAT(_, BOOST_PP_INC(n))
#ifndef BOOST_PP_IS_ITERATING
#ifndef __function_call_detail_hpp__
#define __function_call_detail_hpp__
#include <boost/shared_ptr.hpp>
#include <boost/bind.hpp>
#include <boost/function.hpp>
#include <string>
#include <vector>
#include "proxy_functions.hpp"
namespace chaiscript
{
namespace detail
{
/**
* Internal helper class for handling the return
* value of a build_function_caller
*/
template<typename Ret>
struct Function_Caller_Ret
{
static Ret call(const std::vector<std::pair<std::string, Proxy_Function > > &t_funcs,
const std::vector<Boxed_Value> &params)
{
return boxed_cast<Ret>(dispatch(t_funcs, params));
}
};
/**
* Specialization for void return types
*/
template<>
struct Function_Caller_Ret<void>
{
static void call(const std::vector<std::pair<std::string, Proxy_Function > > &t_funcs,
const std::vector<Boxed_Value> &params)
{
dispatch(t_funcs, params);
}
};
}
}
#define BOOST_PP_ITERATION_LIMITS ( 0, 9 )
#define BOOST_PP_FILENAME_1 <chaiscript/dispatchkit/function_call_detail.hpp>
#include BOOST_PP_ITERATE()
# endif
#else
# define n BOOST_PP_ITERATION()
namespace chaiscript
{
namespace detail
{
/**
* used internally for unwrapping a function call's types
*/
template<typename Ret BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param) >
Ret function_caller(const std::vector<std::pair<std::string, Proxy_Function > > &funcs
BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_BINARY_PARAMS(n, Param, p) )
{
std::vector<Boxed_Value> params;
BOOST_PP_REPEAT(n, addparam, ~)
return Function_Caller_Ret<Ret>::call(funcs, params);
}
/**
* used internally for unwrapping a function call's types
*/
template<typename Ret BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param) >
boost::function<Ret (BOOST_PP_ENUM_PARAMS(n, Param)) >
build_function_caller_helper(Ret (BOOST_PP_ENUM_PARAMS(n, Param)), const std::vector<std::pair<std::string, Proxy_Function> > &funcs)
{
return boost::bind(&function_caller<Ret BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, Param)>, funcs
BOOST_PP_ENUM_TRAILING(n, curry, ~));
}
}
}
#undef n
#endif

View File

@@ -0,0 +1,127 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2010, Jonathan Turner (jturner@minnow-lang.org)
// and Jason Turner (lefticus@gmail.com)
// http://www.chaiscript.com
#ifndef __handle_return_hpp__
#define __handle_return_hpp__
#include "boxed_value.hpp"
#include "type_info.hpp"
#include <string>
#include <boost/function.hpp>
#include <stdexcept>
#include <vector>
namespace chaiscript
{
/**
* Used internally for handling a return value from a Proxy_Function call
*/
template<typename Ret>
struct Handle_Return
{
static Boxed_Value handle(const Ret &r)
{
return Boxed_Value(r);
}
};
template<typename Ret>
struct Handle_Return<boost::shared_ptr<Ret> &>
{
static Boxed_Value handle(const boost::shared_ptr<Ret> &r)
{
return Boxed_Value(r);
}
};
template<typename Ret>
struct Handle_Return<const boost::shared_ptr<Ret> &>
{
static Boxed_Value handle(const boost::shared_ptr<Ret> &r)
{
return Boxed_Value(r);
}
};
template<typename Ret>
struct Handle_Return<const Ret &>
{
static Boxed_Value handle(const Ret &r)
{
return Boxed_Value(boost::cref(r));
}
};
/**
* Used internally for handling a return value from a Proxy_Function call
*/
template<typename Ret>
struct Handle_Return<Ret &>
{
static Boxed_Value handle(Ret &r)
{
return Boxed_Value(boost::ref(r));
}
static Boxed_Value handle(const Ret &r)
{
return Boxed_Value(boost::cref(r));
}
};
/**
* Used internally for handling a return value from a Proxy_Function call
*/
template<>
struct Handle_Return<Boxed_Value>
{
static Boxed_Value handle(const Boxed_Value &r)
{
return r;
}
};
/**
* Used internally for handling a return value from a Proxy_Function call
*/
template<>
struct Handle_Return<Boxed_Value &>
{
static Boxed_Value handle(const Boxed_Value &r)
{
return r;
}
};
/**
* Used internally for handling a return value from a Proxy_Function call
*/
template<>
struct Handle_Return<const Boxed_Value &>
{
static Boxed_Value handle(const Boxed_Value &r)
{
return r;
}
};
/**
* Used internally for handling a return value from a Proxy_Function call
*/
template<>
struct Handle_Return<void>
{
static Boxed_Value handle()
{
return Boxed_Value(Boxed_Value::Void_Type());
}
};
}
#endif

View File

@@ -0,0 +1,442 @@
#ifndef __CHAISCRIPT_OPERATORS_HPP__
#define __CHAISCRIPT_OPERATORS_HPP__
namespace chaiscript
{
namespace operators
{
template<typename Ret, typename L, typename R>
Ret assign(L l, R r)
{
return (l = r);
}
template<typename Ret, typename L, typename R>
Ret assign_bitwise_and(L l, R r)
{
return (l &= r);
}
template<typename Ret, typename L, typename R>
Ret assign_xor(L l, R r)
{
return (l ^= r);
}
template<typename Ret, typename L, typename R>
Ret assign_bitwise_or(L l, R r)
{
return (l |= r);
}
template<typename Ret, typename L, typename R>
Ret assign_difference(L l, R r)
{
return (l -= r);
}
template<typename Ret, typename L, typename R>
Ret assign_left_shift(L l, R r)
{
return (l <<= r);
}
template<typename Ret, typename L, typename R>
Ret assign_product(L l, R r)
{
return (l *= r);
}
template<typename Ret, typename L, typename R>
Ret assign_quotient(L l, R r)
{
return (l /= r);
}
template<typename Ret, typename L, typename R>
Ret assign_remainder(L l, R r)
{
return (l %= r);
}
template<typename Ret, typename L, typename R>
Ret assign_right_shift(L l, R r)
{
return (l >>= r);
}
template<typename Ret, typename L, typename R>
Ret assign_sum(L l, R r)
{
return (l += r);
}
template<typename Ret, typename L>
Ret prefix_decrement(L l)
{
return (--l);
}
template<typename Ret, typename L>
Ret prefix_increment(L l)
{
return (++l);
}
template<typename Ret, typename L, typename R>
Ret equal(L l, R r)
{
return (l == r);
}
template<typename Ret, typename L, typename R>
Ret greater_than(L l, R r)
{
return (l > r);
}
template<typename Ret, typename L, typename R>
Ret greater_than_equal(L l, R r)
{
return (l >= r);
}
template<typename Ret, typename L, typename R>
Ret less_than(L l, R r)
{
return (l < r);
}
template<typename Ret, typename L, typename R>
Ret less_than_equal(L l, R r)
{
return (l <= r);
}
template<typename Ret, typename L>
Ret logical_compliment(L l)
{
return (!l);
}
template<typename Ret, typename L, typename R>
Ret not_equal(L l, R r)
{
return (l != r);
}
template<typename Ret, typename L, typename R>
Ret addition(L l, R r)
{
return (l + r);
}
template<typename Ret, typename L>
Ret unary_plus(L l)
{
return (+l);
}
template<typename Ret, typename L, typename R>
Ret subtraction(L l, R r)
{
return (l - r);
}
template<typename Ret, typename L>
Ret unary_minus(L l)
{
return (-l);
}
template<typename Ret, typename L, typename R>
Ret bitwise_and(L l, R r)
{
return (l & r);
}
template<typename Ret, typename L>
Ret bitwise_compliment(L l)
{
return (~l);
}
template<typename Ret, typename L, typename R>
Ret bitwise_xor(L l, R r)
{
return (l ^ r);
}
template<typename Ret, typename L, typename R>
Ret bitwise_or(L l, R r)
{
return (l | r);
}
template<typename Ret, typename L, typename R>
Ret division(L l, R r)
{
return (l / r);
}
template<typename Ret, typename L, typename R>
Ret left_shift(L l, R r)
{
return l << r;
}
template<typename Ret, typename L, typename R>
Ret multiplication(L l, R r)
{
return l * r;
}
template<typename Ret, typename L, typename R>
Ret remainder(L l, R r)
{
return (l % r);
}
template<typename Ret, typename L, typename R>
Ret right_shift(L l, R r)
{
return (l >> r);
}
template<typename T>
ModulePtr assign(ModulePtr m = ModulePtr(new Module()))
{
m->add(fun(&assign<T &, T &, const T&>), "=");
return m;
}
template<typename T>
ModulePtr assign_bitwise_and(ModulePtr m = ModulePtr(new Module()))
{
m->add(fun(&assign_bitwise_and<T &, T &, const T&>), "&=");
return m;
}
template<typename T>
ModulePtr assign_xor(ModulePtr m = ModulePtr(new Module()))
{
m->add(fun(&assign_xor<T &, T &, const T&>), "^=");
return m;
}
template<typename T>
ModulePtr assign_bitwise_or(ModulePtr m = ModulePtr(new Module()))
{
m->add(fun(&assign_bitwise_or<T &, T &, const T&>), "|=");
return m;
}
template<typename T>
ModulePtr assign_difference(ModulePtr m = ModulePtr(new Module()))
{
m->add(fun(&assign_difference<T &, T &, const T&>), "-=");
return m;
}
template<typename T>
ModulePtr assign_left_shift(ModulePtr m = ModulePtr(new Module()))
{
m->add(fun(&assign_left_shift<T &, T &, const T&>), "<<=");
return m;
}
template<typename T>
ModulePtr assign_product(ModulePtr m = ModulePtr(new Module()))
{
m->add(fun(&assign_product<T &, T &, const T&>), "*=");
return m;
}
template<typename T>
ModulePtr assign_quotient(ModulePtr m = ModulePtr(new Module()))
{
m->add(fun(&assign_quotient<T &, T &, const T&>), "/=");
return m;
}
template<typename T>
ModulePtr assign_remainder(ModulePtr m = ModulePtr(new Module()))
{
m->add(fun(&assign_remainder<T &, T &, const T&>), "%=");
return m;
}
template<typename T>
ModulePtr assign_right_shift(ModulePtr m = ModulePtr(new Module()))
{
m->add(fun(&assign_right_shift<T &, T &, const T&>), ">>=");
return m;
}
template<typename T>
ModulePtr assign_sum(ModulePtr m = ModulePtr(new Module()))
{
m->add(fun(&assign_sum<T &, T &, const T&>), "+=");
return m;
}
template<typename T>
ModulePtr prefix_decrement(ModulePtr m = ModulePtr(new Module()))
{
m->add(fun(&prefix_decrement<T &, T &>), "--");
return m;
}
template<typename T>
ModulePtr prefix_increment(ModulePtr m = ModulePtr(new Module()))
{
m->add(fun(&prefix_increment<T &, T &>), "++");
return m;
}
template<typename T>
ModulePtr equal(ModulePtr m = ModulePtr(new Module()))
{
m->add(fun(&equal<bool, const T&, const T&>), "==");
return m;
}
template<typename T>
ModulePtr greater_than(ModulePtr m = ModulePtr(new Module()))
{
m->add(fun(&greater_than<bool, const T&, const T&>), ">");
return m;
}
template<typename T>
ModulePtr greater_than_equal(ModulePtr m = ModulePtr(new Module()))
{
m->add(fun(&greater_than_equal<bool, const T&, const T&>), ">=");
return m;
}
template<typename T>
ModulePtr less_than(ModulePtr m = ModulePtr(new Module()))
{
m->add(fun(&less_than<bool, const T&, const T&>), "<");
return m;
}
template<typename T>
ModulePtr less_than_equal(ModulePtr m = ModulePtr(new Module()))
{
m->add(fun(&less_than_equal<bool, const T&, const T&>), "<=");
return m;
}
template<typename T>
ModulePtr logical_compliment(ModulePtr m = ModulePtr(new Module()))
{
m->add(fun(&logical_compliment<bool, const T &>), "!");
return m;
}
template<typename T>
ModulePtr not_equal(ModulePtr m = ModulePtr(new Module()))
{
m->add(fun(&not_equal<bool, const T &, const T &>), "!=");
return m;
}
template<typename T>
ModulePtr addition(ModulePtr m = ModulePtr(new Module()))
{
m->add(fun(&addition<T, const T &, const T &>), "+");
return m;
}
template<typename T>
ModulePtr unary_plus(ModulePtr m = ModulePtr(new Module()))
{
m->add(fun(&unary_plus<T, const T &>), "+");
return m;
}
template<typename T>
ModulePtr subtraction(ModulePtr m = ModulePtr(new Module()))
{
m->add(fun(&subtraction<T, const T &, const T &>), "-");
return m;
}
template<typename T>
ModulePtr unary_minus(ModulePtr m = ModulePtr(new Module()))
{
m->add(fun(&unary_minus<T, const T &>), "-");
return m;
}
template<typename T>
ModulePtr bitwise_and(ModulePtr m = ModulePtr(new Module()))
{
m->add(fun(&bitwise_and<T, const T &, const T &>), "&");
return m;
}
template<typename T>
ModulePtr bitwise_compliment(ModulePtr m = ModulePtr(new Module()))
{
m->add(fun(&bitwise_compliment<T, const T &>), "~");
return m;
}
template<typename T>
ModulePtr bitwise_xor(ModulePtr m = ModulePtr(new Module()))
{
m->add(fun(&bitwise_xor<T, const T &, const T &>), "^");
return m;
}
template<typename T>
ModulePtr bitwise_or(ModulePtr m = ModulePtr(new Module()))
{
m->add(fun(&bitwise_or<T, const T &, const T &>), "|");
return m;
}
template<typename T>
ModulePtr division(ModulePtr m = ModulePtr(new Module()))
{
m->add(fun(&division<T, const T &, const T &>), "/");
return m;
}
template<typename T>
ModulePtr left_shift(ModulePtr m = ModulePtr(new Module()))
{
m->add(fun(&left_shift<T, const T &, const T &>), "<<");
return m;
}
template<typename T>
ModulePtr multiplication(ModulePtr m = ModulePtr(new Module()))
{
m->add(fun(&multiplication<T, const T &, const T &>), "*");
return m;
}
template<typename T>
ModulePtr remainder(ModulePtr m = ModulePtr(new Module()))
{
m->add(fun(&remainder<T, const T &, const T &>), "%");
return m;
}
template<typename T>
ModulePtr right_shift(ModulePtr m = ModulePtr(new Module()))
{
m->add(fun(&right_shift<T, const T &, const T &>), ">>");
return m;
}
}
}
#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, Jonathan Turner (jturner@minnow-lang.org) // Copyright 2009-2010, Jonathan Turner (jturner@minnow-lang.org)
// and Jason Turner (lefticus@gmail.com) // and Jason Turner (lefticus@gmail.com)
// http://www.chaiscript.com // http://www.chaiscript.com
@@ -19,34 +19,49 @@
#define BOOST_PP_FILENAME_1 <chaiscript/dispatchkit/proxy_constructors.hpp> #define BOOST_PP_FILENAME_1 <chaiscript/dispatchkit/proxy_constructors.hpp>
#include BOOST_PP_ITERATE() #include BOOST_PP_ITERATE()
# endif # endif
#else
# define n BOOST_PP_ITERATION()
namespace dispatchkit namespace chaiscript
{ {
/** template<typename T>
* A constructor function, used for creating a new object Proxy_Function constructor()
* of a given type with a given set of params
*/
template<typename Class BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param) >
boost::shared_ptr<Class> constructor( BOOST_PP_ENUM_BINARY_PARAMS(n, Param, p) )
{ {
return boost::shared_ptr<Class>(new Class( BOOST_PP_ENUM_PARAMS(n, p) )); T *f = 0;
} return (detail::build_constructor_(f));
/**
* Helper function for build a constructor function
* example:
* dispatchengine.register_function(build_constructor<MyClass, int, const std::string&>, "MyClass");
* \todo See if it is possible to make this not be a variadic function
*/
template<typename Class BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param) >
boost::function<boost::shared_ptr<Class> (BOOST_PP_ENUM_PARAMS(n, Param))> build_constructor()
{
typedef boost::shared_ptr<Class> (*func)(BOOST_PP_ENUM_PARAMS(n, Param));
return boost::function<boost::shared_ptr<Class> (BOOST_PP_ENUM_PARAMS(n, Param))>(func(&(constructor<Class BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, Param)>)));
} }
} }
#else
# define n BOOST_PP_ITERATION()
namespace chaiscript
{
namespace detail
{
/**
* A constructor function, used for creating a new object
* of a given type with a given set of params
*/
template<typename Class BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param) >
boost::shared_ptr<Class> constructor_( BOOST_PP_ENUM_BINARY_PARAMS(n, Param, p) )
{
return boost::shared_ptr<Class>(new Class( BOOST_PP_ENUM_PARAMS(n, p) ));
}
/**
* Helper function for build a constructor function
* example:
* dispatchengine.register_function(build_constructor<MyClass, int, const std::string&>, "MyClass");
* \todo See if it is possible to make this not be a variadic function
*/
template<typename Class BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param) >
Proxy_Function build_constructor_(Class (*)(BOOST_PP_ENUM_PARAMS(n, Param)))
{
typedef boost::shared_ptr<Class> (sig)(BOOST_PP_ENUM_PARAMS(n, Param));
return Proxy_Function(new Proxy_Function_Impl<sig>(boost::function<sig>(&(constructor_<Class BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, Param)>))));
}
}
}
#undef n
#endif #endif

View File

@@ -1,101 +1,32 @@
// 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, Jonathan Turner (jturner@minnow-lang.org) // Copyright 2009-2010, Jonathan Turner (jturner@minnow-lang.org)
// and Jason Turner (lefticus@gmail.com) // and Jason Turner (lefticus@gmail.com)
// http://www.chaiscript.com // http://www.chaiscript.com
#include <boost/preprocessor.hpp>
#define gettypeinfo(z,n,text) ti.push_back(Get_Type_Info<Param ## n>::get());
#define casthelper(z,n,text) ,dispatchkit::boxed_cast< Param ## n >(params[n])
#define comparetype(z,n,text) && ((Get_Type_Info<Param ## n>::get() == params[n].get_type_info()))
#define trycast(z,n,text) dispatchkit::boxed_cast<Param ## n>(params[n]);
#ifndef BOOST_PP_IS_ITERATING
#ifndef __proxy_functions_hpp__ #ifndef __proxy_functions_hpp__
#define __proxy_functions_hpp__ #define __proxy_functions_hpp__
#include "boxed_value.hpp" #include "boxed_value.hpp"
#include "type_info.hpp" #include "type_info.hpp"
#include <string> #include <string>
#include <boost/function.hpp> #include <boost/function.hpp>
#include <boost/bind.hpp> #include <boost/type_traits/add_reference.hpp>
#include <boost/lexical_cast.hpp>
#include <stdexcept> #include <stdexcept>
#include <vector> #include <vector>
#include "proxy_functions_detail.hpp"
namespace dispatchkit namespace chaiscript
{ {
/**
* Used internally for handling a return value from a Proxy_Function call
*/
template<typename Ret>
struct Handle_Return
{
Boxed_Value operator()(const boost::function<Ret ()> &f)
{
return Boxed_Value(f());
}
};
/**
* Used internally for handling a return value from a Proxy_Function call
*/
template<typename Ret>
struct Handle_Return<Ret &>
{
Boxed_Value operator()(const boost::function<Ret &()> &f)
{
return Boxed_Value(boost::ref(f()));
}
};
/**
* Used internally for handling a return value from a Proxy_Function call
*/
template<>
struct Handle_Return<Boxed_Value>
{
Boxed_Value operator()(const boost::function<Boxed_Value ()> &f)
{
return f();
}
};
/**
* Used internally for handling a return value from a Proxy_Function call
*/
template<>
struct Handle_Return<Boxed_Value &>
{
Boxed_Value operator()(const boost::function<Boxed_Value &()> &f)
{
return f();
}
};
/**
* Used internally for handling a return value from a Proxy_Function call
*/
template<>
struct Handle_Return<void>
{
Boxed_Value operator()(const boost::function<void ()> &f)
{
f();
return Boxed_Value(Boxed_Value::Void_Type());
}
};
/** /**
* Helper for building a list of parameters for calling a Proxy_Function * Helper for building a list of parameters for calling a Proxy_Function
* it does automatic conversion to Boxed_Value types via operator<< * it does automatic conversion to Boxed_Value types via operator<<
* *
* example usage: * example usage:
* Boxed_Value retval = dispatch(dispatchengine.get_function("+"), * Boxed_Value retval = dispatch(dispatchengine.get_function("+"),
* dispatchkit::Param_List_Builder() << 5 << 6); * chaiscript::Param_List_Builder() << 5 << 6);
*/ */
struct Param_List_Builder struct Param_List_Builder
{ {
@@ -120,30 +51,6 @@ namespace dispatchkit
std::vector<Boxed_Value> objects; std::vector<Boxed_Value> objects;
}; };
/**
* Exception thrown when there is a mismatch in number of
* parameters during Proxy_Function execution
*/
struct arity_error : std::range_error
{
arity_error(int t_got, int t_expected)
: std::range_error("Function dispatch arity mismatch"),
got(t_got), expected(t_expected)
{
}
virtual ~arity_error() throw() {}
int got;
int expected;
};
}
#define BOOST_PP_ITERATION_LIMITS ( 0, 10 )
#define BOOST_PP_FILENAME_1 <chaiscript/dispatchkit/proxy_functions.hpp>
#include BOOST_PP_ITERATE()
namespace dispatchkit
{
/** /**
* Pure virtual base class for all Proxy_Function implementations * Pure virtual base class for all Proxy_Function implementations
* Proxy_Functions are a type erasure of type safe C++ * Proxy_Functions are a type erasure of type safe C++
@@ -152,17 +59,90 @@ namespace dispatchkit
* Dispatch_Engine only knows how to work with Proxy_Function, no other * Dispatch_Engine only knows how to work with Proxy_Function, no other
* function classes. * function classes.
*/ */
class Proxy_Function class Proxy_Function_Base
{ {
public: public:
virtual ~Proxy_Function() {} virtual ~Proxy_Function_Base() {}
virtual Boxed_Value operator()(const std::vector<Boxed_Value> &params) = 0; virtual Boxed_Value operator()(const std::vector<Boxed_Value> &params) const = 0;
virtual std::vector<Type_Info> get_param_types() const = 0;
virtual bool operator==(const Proxy_Function &) const = 0; std::vector<Type_Info> get_param_types() const { return m_types; }
virtual bool types_match(const std::vector<Boxed_Value> &types) const = 0;
virtual bool operator==(const Proxy_Function_Base &) const = 0;
virtual bool call_match(const std::vector<Boxed_Value> &vals) const = 0;
//! Return true if the function is a possible match
//! to the passed in values
bool filter(const std::vector<Boxed_Value> &vals) const
{
int arity = get_arity();
if (arity < 0)
{
return true;
} else if (size_t(arity) == vals.size()) {
if (arity == 0)
{
return true;
} else {
const std::vector<Type_Info> &types = get_param_types();
if (types.size() < 2)
{
return true;
}
const Type_Info &ti = types[1];
if (ti.is_undef() || vals[0].get_type_info().is_undef()
|| ti.bare_equal(user_type<Boxed_Value>())
|| ti.bare_equal(user_type<Boxed_POD_Value>())
|| ti.bare_equal(vals[0].get_type_info()))
{
return true;
} else {
return false;
}
}
} else {
return false;
}
}
virtual int get_arity() const = 0;
virtual std::string annotation() const = 0; virtual std::string annotation() const = 0;
protected:
Proxy_Function_Base(const std::vector<Type_Info> &t_types)
: m_types(t_types)
{
}
bool compare_types(const std::vector<Type_Info> &tis, const std::vector<Boxed_Value> &bvs) const
{
if (tis.size() - 1 != bvs.size())
{
return false;
} else {
const int size = bvs.size();
for (int i = 0; i < size; ++i)
{
if (!(tis[i+1].bare_equal(bvs[i].get_type_info()) && tis[i+1].is_const() >= bvs[i].get_type_info().is_const() ))
{
return false;
}
}
}
return true;
}
std::vector<Type_Info> m_types;
}; };
typedef boost::shared_ptr<Proxy_Function_Base> Proxy_Function;
typedef boost::shared_ptr<const Proxy_Function_Base> Const_Proxy_Function;
/** /**
* Exception thrown if a function's guard fails to execute * Exception thrown if a function's guard fails to execute
*/ */
@@ -181,32 +161,33 @@ namespace dispatchkit
* A Proxy_Function implementation that is not type safe, the called function * A Proxy_Function implementation that is not type safe, the called function
* is expecting a vector<Boxed_Value> that it works with how it chooses. * is expecting a vector<Boxed_Value> that it works with how it chooses.
*/ */
class Dynamic_Proxy_Function : public Proxy_Function class Dynamic_Proxy_Function : public Proxy_Function_Base
{ {
public: public:
Dynamic_Proxy_Function( Dynamic_Proxy_Function(
const boost::function<Boxed_Value (const std::vector<Boxed_Value> &)> &t_f, const boost::function<Boxed_Value (const std::vector<Boxed_Value> &)> &t_f,
int t_arity=-1, int t_arity=-1,
const std::string &t_description = "", const std::string &t_description = "",
const boost::shared_ptr<Proxy_Function> &t_guard = boost::shared_ptr<Proxy_Function>()) const Proxy_Function &t_guard = Proxy_Function())
: m_f(t_f), m_arity(t_arity), m_description(t_description), m_guard(t_guard) : Proxy_Function_Base(build_param_type_list(t_arity)),
m_f(t_f), m_arity(t_arity), m_description(t_description), m_guard(t_guard)
{ {
} }
virtual bool operator==(const Proxy_Function &) const virtual bool operator==(const Proxy_Function_Base &) const
{ {
return false; return false;
} }
virtual bool types_match(const std::vector<Boxed_Value> &types) const virtual bool call_match(const std::vector<Boxed_Value> &vals) const
{ {
return (m_arity < 0 || types.size() == size_t(m_arity)) return (m_arity < 0 || vals.size() == size_t(m_arity))
&& test_guard(types); && test_guard(vals);
} }
virtual ~Dynamic_Proxy_Function() {} virtual ~Dynamic_Proxy_Function() {}
virtual Boxed_Value operator()(const std::vector<Boxed_Value> &params) virtual Boxed_Value operator()(const std::vector<Boxed_Value> &params) const
{ {
if (m_arity < 0 || params.size() == size_t(m_arity)) if (m_arity < 0 || params.size() == size_t(m_arity))
{ {
@@ -223,23 +204,9 @@ namespace dispatchkit
} }
} }
virtual std::vector<Type_Info> get_param_types() const virtual int get_arity() const
{ {
std::vector<Type_Info> types; return m_arity;
types.push_back(Get_Type_Info<Boxed_Value>::get());
if (m_arity >= 0)
{
for (int i = 0; i < m_arity; ++i)
{
types.push_back(Get_Type_Info<Boxed_Value>::get());
}
} else {
types.push_back(Get_Type_Info<std::vector<Boxed_Value> >::get());
}
return types;
} }
virtual std::string annotation() const virtual std::string annotation() const
@@ -264,10 +231,29 @@ namespace dispatchkit
} }
} }
static std::vector<Type_Info> build_param_type_list(int arity)
{
std::vector<Type_Info> types;
types.push_back(detail::Get_Type_Info<Boxed_Value>::get());
if (arity >= 0)
{
for (int i = 0; i < arity; ++i)
{
types.push_back(detail::Get_Type_Info<Boxed_Value>::get());
}
} else {
types.push_back(detail::Get_Type_Info<std::vector<Boxed_Value> >::get());
}
return types;
}
boost::function<Boxed_Value (const std::vector<Boxed_Value> &)> m_f; boost::function<Boxed_Value (const std::vector<Boxed_Value> &)> m_f;
int m_arity; int m_arity;
std::string m_description; std::string m_description;
boost::shared_ptr<Proxy_Function> m_guard; Proxy_Function m_guard;
}; };
/** /**
@@ -284,29 +270,29 @@ namespace dispatchkit
* at runtime, when call() is executed. * at runtime, when call() is executed.
* it is used for bind(function, param1, _, param2) style calls * it is used for bind(function, param1, _, param2) style calls
*/ */
class Bound_Function : public Proxy_Function class Bound_Function : public Proxy_Function_Base
{ {
public: public:
Bound_Function(const boost::shared_ptr<Proxy_Function> &t_f, Bound_Function(const Const_Proxy_Function &t_f,
const std::vector<Boxed_Value> &t_args) const std::vector<Boxed_Value> &t_args)
: m_f(t_f), m_args(t_args) : Proxy_Function_Base(std::vector<Type_Info>()),
m_f(t_f), m_args(t_args), m_arity(m_f->get_arity()<0?-1:(m_f->get_arity() - m_args.size()))
{ {
} }
virtual bool operator==(const Proxy_Function &) const virtual bool operator==(const Proxy_Function_Base &) const
{ {
return false; return false;
} }
virtual ~Bound_Function() {} virtual ~Bound_Function() {}
virtual bool types_match(const std::vector<Boxed_Value> &types) const virtual bool call_match(const std::vector<Boxed_Value> &vals) const
{ {
std::vector<Boxed_Value> params = build_param_list(types); return m_f->call_match(build_param_list(vals));
return m_f->types_match(params);
} }
virtual Boxed_Value operator()(const std::vector<Boxed_Value> &params) virtual Boxed_Value operator()(const std::vector<Boxed_Value> &params) const
{ {
return (*m_f)(build_param_list(params)); return (*m_f)(build_param_list(params));
} }
@@ -323,7 +309,7 @@ namespace dispatchkit
while (true) while (true)
{ {
while (barg != m_args.end() while (barg != m_args.end()
&& !(barg->get_type_info() == Get_Type_Info<Placeholder_Object>::get())) && !(barg->get_type_info() == detail::Get_Type_Info<Placeholder_Object>::get()))
{ {
args.push_back(*barg); args.push_back(*barg);
++barg; ++barg;
@@ -336,7 +322,7 @@ namespace dispatchkit
} }
if (barg != m_args.end() if (barg != m_args.end()
&& barg->get_type_info() == Get_Type_Info<Placeholder_Object>::get()) && barg->get_type_info() == detail::Get_Type_Info<Placeholder_Object>::get())
{ {
++barg; ++barg;
} }
@@ -349,9 +335,9 @@ namespace dispatchkit
return args; return args;
} }
virtual std::vector<Type_Info> get_param_types() const virtual int get_arity() const
{ {
return std::vector<Type_Info>(); return m_arity;
} }
virtual std::string annotation() const virtual std::string annotation() const
@@ -360,8 +346,9 @@ namespace dispatchkit
} }
private: private:
boost::shared_ptr<Proxy_Function> m_f; Const_Proxy_Function m_f;
std::vector<Boxed_Value> m_args; std::vector<Boxed_Value> m_args;
int m_arity;
}; };
/** /**
@@ -370,17 +357,18 @@ namespace dispatchkit
* type checking of Boxed_Value parameters, in a type safe manner * type checking of Boxed_Value parameters, in a type safe manner
*/ */
template<typename Func> template<typename Func>
class Proxy_Function_Impl : public Proxy_Function class Proxy_Function_Impl : public Proxy_Function_Base
{ {
public: public:
Proxy_Function_Impl(const Func &f) Proxy_Function_Impl(const boost::function<Func> &f)
: m_f(f) : Proxy_Function_Base(build_param_type_list(static_cast<Func *>(0))),
m_f(f), m_dummy_func(0)
{ {
} }
virtual ~Proxy_Function_Impl() {} virtual ~Proxy_Function_Impl() {}
virtual bool operator==(const Proxy_Function &t_func) const virtual bool operator==(const Proxy_Function_Base &t_func) const
{ {
try { try {
dynamic_cast<const Proxy_Function_Impl<Func> &>(t_func); dynamic_cast<const Proxy_Function_Impl<Func> &>(t_func);
@@ -390,19 +378,25 @@ namespace dispatchkit
} }
} }
virtual Boxed_Value operator()(const std::vector<Boxed_Value> &params) virtual Boxed_Value operator()(const std::vector<Boxed_Value> &params) const
{ {
return call_func(m_f, params); return Do_Call<typename boost::function<Func>::result_type>::go(m_f, params);
} }
virtual std::vector<Type_Info> get_param_types() const virtual int get_arity() const
{ {
return build_param_type_list(m_f); return m_types.size() - 1;
} }
virtual bool types_match(const std::vector<Boxed_Value> &types) const
virtual bool call_match(const std::vector<Boxed_Value> &vals) const
{ {
return compare_types(m_f, types); if (int(vals.size()) != get_arity())
{
return false;
}
return compare_types(m_types, vals) || compare_types_cast(m_dummy_func, vals);
} }
virtual std::string annotation() const virtual std::string annotation() const
@@ -411,7 +405,83 @@ namespace dispatchkit
} }
private: private:
Func m_f; boost::function<Func> m_f;
Func *m_dummy_func;
};
/**
* Attribute getter Proxy_Function implementation
*/
template<typename T, typename Class>
class Attribute_Access : public Proxy_Function_Base
{
public:
Attribute_Access(T Class::* t_attr)
: Proxy_Function_Base(param_types()),
m_attr(t_attr)
{
}
virtual ~Attribute_Access() {}
virtual bool operator==(const Proxy_Function_Base &t_func) const
{
try {
const Attribute_Access<T, Class> &aa
= dynamic_cast<const Attribute_Access<T, Class> &>(t_func);
return m_attr == aa.m_attr;
} catch (const std::bad_cast &) {
return false;
}
}
virtual Boxed_Value operator()(const std::vector<Boxed_Value> &params) const
{
if (params.size() == 1)
{
const Boxed_Value &bv = params[0];
if (bv.is_const())
{
const Class *o = boxed_cast<const Class *>(bv);
return Handle_Return<typename boost::add_reference<T>::type>::handle(o->*m_attr);
} else {
Class *o = boxed_cast<Class *>(bv);
return Handle_Return<typename boost::add_reference<T>::type>::handle(o->*m_attr);
}
} else {
throw arity_error(params.size(), 1);
}
}
virtual int get_arity() const
{
return 1;
}
virtual bool call_match(const std::vector<Boxed_Value> &vals) const
{
if (vals.size() != 1)
{
return false;
}
return vals[0].get_type_info().bare_equal(user_type<Class>());
}
virtual std::string annotation() const
{
return "";
}
private:
static std::vector<Type_Info> param_types()
{
std::vector<Type_Info> v;
v.push_back(user_type<T>());
v.push_back(user_type<Class>());
return v;
}
T Class::* m_attr;
}; };
/** /**
@@ -427,6 +497,11 @@ namespace dispatchkit
{ {
} }
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() {}
}; };
@@ -435,15 +510,17 @@ namespace dispatchkit
* each function against the set of parameters, in order, until a matching * each function against the set of parameters, in order, until a matching
* 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
*/ */
Boxed_Value dispatch(const std::vector<std::pair<std::string, boost::shared_ptr<Proxy_Function> > > &funcs, template<typename InItr>
Boxed_Value dispatch(InItr begin, InItr end,
const std::vector<Boxed_Value> &plist) const std::vector<Boxed_Value> &plist)
{ {
for (std::vector<std::pair<std::string, boost::shared_ptr<Proxy_Function> > >::const_iterator itr = funcs.begin(); while (begin != end)
itr != funcs.end();
++itr)
{ {
try { try {
return (*itr->second)(plist); if (begin->second->filter(plist))
{
return (*begin->second)(plist);
}
} catch (const bad_boxed_cast &) { } catch (const bad_boxed_cast &) {
//parameter failed to cast, try again //parameter failed to cast, try again
} catch (const arity_error &) { } catch (const arity_error &) {
@@ -452,75 +529,24 @@ namespace dispatchkit
//guard failed to allow the function to execute, //guard failed to allow the function to execute,
//try again //try again
} }
++begin;
} }
throw dispatch_error();
throw dispatch_error(plist.empty()?false:plist[0].is_const());
}
/**
* Take a vector of functions and a vector of parameters. Attempt to execute
* each function against the set of parameters, in order, until a matching
* function is found or throw dispatch_error if no matching function is found
*/
template<typename Funcs>
Boxed_Value dispatch(const Funcs &funcs,
const std::vector<Boxed_Value> &plist)
{
return dispatch(funcs.begin(), funcs.end(), plist);
} }
} }
# endif
#else
# define n BOOST_PP_ITERATION()
namespace dispatchkit
{
/**
* Used by Proxy_Function_Impl to return a list of all param types
* it contains.
*/
template<typename Ret BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param) >
std::vector<Type_Info> build_param_type_list(const boost::function<Ret (BOOST_PP_ENUM_PARAMS(n, Param))> &)
{
std::vector<Type_Info> ti;
ti.push_back(Get_Type_Info<Ret>::get());
BOOST_PP_REPEAT(n, gettypeinfo, ~)
return ti;
}
/**
* Used by Proxy_Function_Impl to perform typesafe execution of a function.
* The function attempts to unbox each paramter to the expected type.
* if any unboxing fails the execution of the function fails and
* the bad_boxed_cast is passed up to the caller.
*/
template<typename Ret BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param)>
Boxed_Value call_func(const boost::function<Ret (BOOST_PP_ENUM_PARAMS(n, Param))> &f,
const std::vector<Boxed_Value> &params)
{
if (params.size() != n)
{
throw arity_error(params.size(), n);
} else {
return Handle_Return<Ret>()(boost::bind(f BOOST_PP_REPEAT(n, casthelper, ~)));
}
}
/**
* Used by Proxy_Function_Impl to determine if it is equivalent to another
* Proxy_Function_Impl object. This function is primarly used to prevent
* registration of two functions with the exact same signatures
*/
template<typename Ret BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param)>
bool compare_types(const boost::function<Ret (BOOST_PP_ENUM_PARAMS(n, Param))> &,
const std::vector<Boxed_Value> &params)
{
if (params.size() != n)
{
return false;
} else {
bool val = true BOOST_PP_REPEAT(n, comparetype, ~);
if (val) return true;
try {
BOOST_PP_REPEAT(n, trycast, ~);
} catch (const bad_boxed_cast &) {
return false;
}
return true;
}
}
}
#endif #endif

View File

@@ -0,0 +1,135 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2010, Jonathan Turner (jturner@minnow-lang.org)
// and Jason Turner (lefticus@gmail.com)
// http://www.chaiscript.com
#include <boost/preprocessor.hpp>
#define gettypeinfo(z,n,text) ti.push_back(detail::Get_Type_Info<Param ## n>::get());
#define casthelper(z,n,text) BOOST_PP_COMMA_IF(n) chaiscript::boxed_cast< Param ## n >(params[n])
#define trycast(z,n,text) chaiscript::boxed_cast<Param ## n>(params[n]);
#ifndef BOOST_PP_IS_ITERATING
#ifndef __proxy_functions_detail_hpp__
#define __proxy_functions_detail_hpp__
#include "boxed_value.hpp"
#include "type_info.hpp"
#include "handle_return.hpp"
#include <string>
#include <boost/function.hpp>
#include <boost/bind.hpp>
#include <boost/lexical_cast.hpp>
#include <stdexcept>
#include <vector>
namespace chaiscript
{
/**
* Exception thrown when there is a mismatch in number of
* parameters during Proxy_Function execution
*/
struct arity_error : std::range_error
{
arity_error(int t_got, int t_expected)
: std::range_error("Function dispatch arity mismatch"),
got(t_got), expected(t_expected)
{
}
virtual ~arity_error() throw() {}
int got;
int expected;
};
template<typename Ret>
struct Do_Call
{
template<typename Fun>
static Boxed_Value go(const boost::function<Fun> &fun, const std::vector<Boxed_Value> &params)
{
return Handle_Return<Ret>::handle(call_func(fun, params));
}
};
template<>
struct Do_Call<void>
{
template<typename Fun>
static Boxed_Value go(const boost::function<Fun> &fun, const std::vector<Boxed_Value> &params)
{
call_func(fun, params);
return Handle_Return<void>::handle();
};
};
}
#define BOOST_PP_ITERATION_LIMITS ( 0, 10 )
#define BOOST_PP_FILENAME_1 <chaiscript/dispatchkit/proxy_functions_detail.hpp>
#include BOOST_PP_ITERATE()
# endif
#else
# define n BOOST_PP_ITERATION()
namespace chaiscript
{
/**
* Used by Proxy_Function_Impl to return a list of all param types
* it contains.
*/
template<typename Ret BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param) >
std::vector<Type_Info> build_param_type_list(Ret (*)(BOOST_PP_ENUM_PARAMS(n, Param)))
{
std::vector<Type_Info> ti;
ti.push_back(detail::Get_Type_Info<Ret>::get());
BOOST_PP_REPEAT(n, gettypeinfo, ~)
return ti;
}
/**
* Used by Proxy_Function_Impl to perform typesafe execution of a function.
* The function attempts to unbox each paramter to the expected type.
* if any unboxing fails the execution of the function fails and
* the bad_boxed_cast is passed up to the caller.
*/
template<typename Ret BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param)>
Ret call_func(const boost::function<Ret (BOOST_PP_ENUM_PARAMS(n, Param))> &f,
const std::vector<Boxed_Value> &params)
{
if (params.size() != n)
{
throw arity_error(params.size(), n);
} else {
return f(BOOST_PP_REPEAT(n, casthelper, ~));
}
}
/**
* Used by Proxy_Function_Impl to determine if it is equivalent to another
* Proxy_Function_Impl object. This function is primarly used to prevent
* registration of two functions with the exact same signatures
*/
template<typename Ret BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param)>
bool compare_types_cast(Ret (*)(BOOST_PP_ENUM_PARAMS(n, Param)),
const std::vector<Boxed_Value> & BOOST_PP_IF(n, params, ))
{
try {
BOOST_PP_REPEAT(n, trycast, ~);
} catch (const bad_boxed_cast &) {
return false;
}
return true;
}
}
#undef n
#endif

View File

@@ -1,79 +1,94 @@
// 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, Jonathan Turner (jturner@minnow-lang.org) // Copyright 2009-2010, Jonathan Turner (jturner@minnow-lang.org)
// and Jason Turner (lefticus@gmail.com) // and Jason Turner (lefticus@gmail.com)
// http://www.chaiscript.com // http://www.chaiscript.com
#include <boost/preprocessor.hpp>
#ifndef BOOST_PP_IS_ITERATING
#ifndef __register_function_hpp__ #ifndef __register_function_hpp__
#define __register_function_hpp__ #define __register_function_hpp__
#include "dispatchkit.hpp" #include "dispatchkit.hpp"
#include "bind_first.hpp"
#include <boost/function.hpp> #include <boost/function.hpp>
#include <boost/bind.hpp> #include <boost/bind.hpp>
#include <boost/function_types/components.hpp>
#include <boost/function_types/function_type.hpp>
#include <boost/function_types/is_member_object_pointer.hpp>
#include <boost/function_types/is_member_function_pointer.hpp>
namespace dispatchkit namespace chaiscript
{ {
/** namespace detail
* Helper function for register_member function {
*/ template<bool Object, bool MemFn>
template<typename T, typename Class> struct Fun_Helper
T &get_member(T Class::* m, Class *obj) {
template<typename T>
static Proxy_Function go(T t)
{
return Proxy_Function(
new Proxy_Function_Impl<
typename boost::function_types::function_type<boost::function_types::components<T> >::type> (
boost::function<
typename boost::function_types::function_type<boost::function_types::components<T> >::type
>(t)));
}
};
template<>
struct Fun_Helper<false, true>
{
template<typename T>
static Proxy_Function go(T t)
{
return Proxy_Function(
new Proxy_Function_Impl<
typename boost::function_types::function_type<boost::function_types::components<T> >::type> (
boost::function<
typename boost::function_types::function_type<boost::function_types::components<T> >::type
>(boost::mem_fn(t))));
}
};
template<>
struct Fun_Helper<true, false>
{
template<typename T, typename Class>
static Proxy_Function go(T Class::* m)
{
return Proxy_Function(new Attribute_Access<T, Class>(m));
}
};
}
template<typename T>
Proxy_Function fun(const boost::function<T> &f)
{ {
return obj->*m; return Proxy_Function(new Proxy_Function_Impl<T>(f));
} }
/** template<typename T>
* Automatically create a get_member helper function for an object Proxy_Function fun(T t)
* to allow for runtime dispatched access to public data members
* for example, the case of std::pair<>::first and std::pair<>::second
*/
template<typename T, typename Class>
void register_member(Dispatch_Engine &s, T Class::* m, const std::string &name)
{ {
s.register_function(boost::function<T (Class *)>(boost::bind(&get_member<T, Class>, m, _1)), name); return detail::Fun_Helper<boost::function_types::is_member_object_pointer<T>::value, boost::function_types::is_member_function_pointer<T>::value>::go(t);
} }
template<typename T, typename Q>
Proxy_Function fun(T t, const Q &q)
{
return fun(bind_first(t, q));
}
template<typename T, typename Q, typename R>
Proxy_Function fun(T t, const Q &q, const R &r)
{
return fun(bind_first(bind_first(t, q), r));
}
} }
#define BOOST_PP_ITERATION_LIMITS ( 0, 10 )
#define BOOST_PP_FILENAME_1 <chaiscript/dispatchkit/register_function.hpp>
#include BOOST_PP_ITERATE()
# endif
#else
# define n BOOST_PP_ITERATION()
namespace dispatchkit
{
/**
* Register a global function of n parameters with name
*/
template<typename Ret BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param)>
void register_function(Dispatch_Engine &s, Ret (*f)(BOOST_PP_ENUM_PARAMS(n, Param)), const std::string &name)
{
s.register_function(boost::function<Ret (BOOST_PP_ENUM_PARAMS(n, Param))>(f), name);
}
/**
* Register a class method of n parameters with name
*/
template<typename Ret, typename Class BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param)>
void register_function(Dispatch_Engine &s, Ret (Class::*f)(BOOST_PP_ENUM_PARAMS(n, Param)), const std::string &name)
{
s.register_function(boost::function<Ret (Class* BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, Param))>(f), name);
}
/**
* Register a const class method of n parameters with name
*/
template<typename Ret, typename Class BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param)>
void register_function(Dispatch_Engine &s, Ret (Class::*f)(BOOST_PP_ENUM_PARAMS(n, Param))const, const std::string &name)
{
s.register_function(boost::function<Ret (const Class* BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, Param))>(f), name);
}
}
#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, Jonathan Turner (jturner@minnow-lang.org) // Copyright 2009-2010, Jonathan Turner (jturner@minnow-lang.org)
// and Jason Turner (lefticus@gmail.com) // and Jason Turner (lefticus@gmail.com)
// http://www.chaiscript.com // http://www.chaiscript.com
@@ -16,105 +16,176 @@
#include <boost/type_traits/remove_pointer.hpp> #include <boost/type_traits/remove_pointer.hpp>
#include <boost/ref.hpp> #include <boost/ref.hpp>
namespace dispatchkit namespace chaiscript
{ {
/** /**
* compile time deduced information about a type * compile time deduced information about a type
*/ */
struct Type_Info class Type_Info
{ {
Type_Info(bool t_is_const, bool t_is_reference, bool t_is_pointer, bool t_is_void, public:
const std::type_info *t_ti, const std::type_info *t_bareti) Type_Info(bool t_is_const, bool t_is_reference, bool t_is_pointer, bool t_is_void,
: m_is_const(t_is_const), m_is_reference(t_is_reference), m_is_pointer(t_is_pointer), const std::type_info *t_ti, const std::type_info *t_bareti)
: m_is_const(t_is_const), m_is_reference(t_is_reference), m_is_pointer(t_is_pointer),
m_is_void(t_is_void), m_is_void(t_is_void),
m_type_info(t_ti), m_bare_type_info(t_bareti), m_type_info(t_ti), m_bare_type_info(t_bareti),
m_is_unknown(false) m_is_undef(false)
{ {
} }
Type_Info() Type_Info()
: m_is_const(false), m_is_reference(false), m_is_pointer(false), : m_is_const(false), m_is_reference(false), m_is_pointer(false),
m_is_void(false), m_type_info(0), m_bare_type_info(0), m_is_void(false), m_type_info(0), m_bare_type_info(0),
m_is_unknown(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_is_const(ti.m_is_const), 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_type_info(ti.m_type_info), 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_unknown(ti.m_is_unknown) m_is_undef(ti.m_is_undef)
{ {
} }
Type_Info &operator=(const Type_Info &ti)
{
m_is_const = ti.m_is_const;
m_is_reference = ti.m_is_reference;
m_is_pointer = ti.m_is_pointer;
m_is_void = ti.m_is_void;
m_type_info = ti.m_type_info;
m_bare_type_info = ti.m_bare_type_info;
m_is_unknown = ti.m_is_unknown;
return *this;
}
bool operator<(const Type_Info &ti) const
{
return m_type_info < ti.m_type_info;
}
bool operator==(const Type_Info &ti) const Type_Info &operator=(const Type_Info &ti)
{ {
return ti.m_type_info == m_type_info; m_is_const = ti.m_is_const;
} m_is_reference = ti.m_is_reference;
m_is_pointer = ti.m_is_pointer;
m_is_void = ti.m_is_void;
m_type_info = ti.m_type_info;
m_bare_type_info = ti.m_bare_type_info;
m_is_undef = ti.m_is_undef;
return *this;
}
bool m_is_const; bool operator<(const Type_Info &ti) const
bool m_is_reference; {
bool m_is_pointer; return m_type_info < ti.m_type_info;
bool m_is_void; }
const std::type_info *m_type_info;
const std::type_info *m_bare_type_info; bool operator==(const Type_Info &ti) const
bool m_is_unknown; {
return ti.m_type_info == m_type_info
|| (ti.m_type_info && m_type_info && *ti.m_type_info == *m_type_info);
}
bool operator==(const std::type_info &ti) const
{
return m_type_info != 0 && (*m_type_info) == ti;
}
bool bare_equal(const Type_Info &ti) const
{
return ti.m_bare_type_info == m_bare_type_info
|| (ti.m_bare_type_info && m_bare_type_info && *ti.m_bare_type_info == *m_bare_type_info);
}
bool is_const() const { return m_is_const; }
bool is_reference() const { return m_is_reference; }
bool is_void() const { return m_is_void; }
bool is_undef() const { return m_is_undef || m_bare_type_info == 0; }
bool is_pointer() const { return m_is_pointer; }
std::string name() const
{
if (m_type_info)
{
return m_type_info->name();
} else {
return "";
}
}
std::string bare_name() const
{
if (m_bare_type_info)
{
return m_bare_type_info->name();
} else {
return "";
}
}
private:
bool m_is_const;
bool m_is_reference;
bool m_is_pointer;
bool m_is_void;
const std::type_info *m_type_info;
const std::type_info *m_bare_type_info;
bool m_is_undef;
}; };
/** namespace detail
* Helper used to create a Type_Info object {
*/ /**
template<typename T> * Helper used to create a Type_Info object
struct Get_Type_Info */
{ template<typename T>
static Type_Info get() struct Get_Type_Info
{ {
return Type_Info(boost::is_const<T>::value, boost::is_reference<T>::value, boost::is_pointer<T>::value, static Type_Info get()
boost::is_void<T>::value, {
&typeid(T), return Type_Info(boost::is_const<T>::value, boost::is_reference<T>::value, boost::is_pointer<T>::value,
&typeid(typename boost::remove_const<typename boost::remove_pointer<typename boost::remove_reference<T>::type>::type>::type)); boost::is_void<T>::value,
} &typeid(T),
}; &typeid(typename boost::remove_const<typename boost::remove_pointer<typename boost::remove_reference<T>::type>::type>::type));
}
};
template<typename T>
struct Get_Type_Info<boost::shared_ptr<T> >
{
static Type_Info get()
{
return Type_Info(boost::is_const<T>::value, boost::is_reference<T>::value, boost::is_pointer<T>::value,
boost::is_void<T>::value,
&typeid(boost::shared_ptr<T> ),
&typeid(typename boost::remove_const<typename boost::remove_pointer<typename boost::remove_reference<T>::type>::type>::type));
}
};
template<typename T>
struct Get_Type_Info<const boost::shared_ptr<T> &>
{
static Type_Info get()
{
return Type_Info(boost::is_const<T>::value, boost::is_reference<T>::value, boost::is_pointer<T>::value,
boost::is_void<T>::value,
&typeid(const boost::shared_ptr<T> &),
&typeid(typename boost::remove_const<typename boost::remove_pointer<typename boost::remove_reference<T>::type>::type>::type));
}
};
template<typename T>
struct Get_Type_Info<boost::reference_wrapper<T> >
{
static Type_Info get()
{
return Type_Info(boost::is_const<T>::value, boost::is_reference<T>::value, boost::is_pointer<T>::value,
boost::is_void<T>::value,
&typeid(boost::reference_wrapper<T> ),
&typeid(typename boost::remove_const<typename boost::remove_pointer<typename boost::remove_reference<T>::type>::type>::type));
}
};
}
template<typename T>
Type_Info user_type(T)
{
return detail::Get_Type_Info<T>::get();
}
template<typename T> template<typename T>
struct Get_Type_Info<boost::shared_ptr<T> > Type_Info user_type()
{ {
static Type_Info get() return detail::Get_Type_Info<T>::get();
{ }
return Type_Info(boost::is_const<T>::value, boost::is_reference<T>::value, boost::is_pointer<T>::value,
boost::is_void<T>::value,
&typeid(boost::shared_ptr<T> ),
&typeid(typename boost::remove_const<typename boost::remove_pointer<typename boost::remove_reference<T>::type>::type>::type));
}
};
template<typename T>
struct Get_Type_Info<boost::reference_wrapper<T> >
{
static Type_Info get()
{
return Type_Info(boost::is_const<T>::value, boost::is_reference<T>::value, boost::is_pointer<T>::value,
boost::is_void<T>::value,
&typeid(boost::reference_wrapper<T> ),
&typeid(typename boost::remove_const<typename boost::remove_pointer<typename boost::remove_reference<T>::type>::type>::type));
}
};
} }
#endif #endif

View File

@@ -0,0 +1,149 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2010, Jonathan Turner (jturner@minnow-lang.org)
// and Jason Turner (lefticus@gmail.com)
// http://www.chaiscript.com
#ifndef _CHAISCRIPT_COMMON_HPP
#define _CHAISCRIPT_COMMON_HPP
#ifdef BOOST_HAS_DECLSPEC
#define CHAISCRIPT_MODULE_EXPORT extern "C" __declspec(dllexport)
#else
#define CHAISCRIPT_MODULE_EXPORT extern "C"
#endif
namespace chaiscript
{
typedef ModulePtr (*Create_Module_Func)();
/**
* Types of AST nodes available to the parser and eval
*/
class Token_Type { public: enum Type { Error, Int, Float, Id, Char, Str, Eol, Fun_Call, Inplace_Fun_Call, Arg_List, Variable, Equation, Var_Decl,
Comparison, Additive, Multiplicative, Array_Call, Dot_Access, Quoted_String, Single_Quoted_String,
Lambda, Block, Def, While, If, For, Inline_Array, Inline_Map, Return, File, Prefix, Break, Map_Pair, Value_Range,
Inline_Range, Annotation, Try, Catch, Finally, Method, Attr_Decl, Shift, Equality, Bitwise_And, Bitwise_Xor, Bitwise_Or,
Logical_And, Logical_Or}; };
namespace
{
/**
* Helper lookup to get the name of each node type
*/
const char *token_type_to_string(int tokentype) {
const char *token_types[] = { "Internal Parser Error", "Int", "Float", "Id", "Char", "Str", "Eol", "Fun_Call", "Inplace_Fun_Call", "Arg_List", "Variable", "Equation", "Var_Decl",
"Comparison", "Additive", "Multiplicative", "Array_Call", "Dot_Access", "Quoted_String", "Single_Quoted_String",
"Lambda", "Block", "Def", "While", "If", "For", "Inline_Array", "Inline_Map", "Return", "File", "Prefix", "Break", "Map_Pair", "Value_Range",
"Inline_Range", "Annotation", "Try", "Catch", "Finally", "Method", "Attr_Decl", "Shift", "Equality", "Bitwise_And", "Bitwise_Xor", "Bitwise_Or",
"Logical_And", "Logical_Or"};
return token_types[tokentype];
}
}
/**
* Convenience type for file positions
*/
struct File_Position {
int line;
int column;
File_Position(int file_line, int file_column)
: line(file_line), column(file_column) { }
File_Position() : line(0), column(0) { }
};
typedef boost::shared_ptr<struct Token> TokenPtr;
/**
* The struct that doubles as both a parser token and an AST node
*/
struct Token {
std::string text;
int identifier;
const char *filename;
File_Position start, end;
bool is_cached;
Boxed_Value cached_value;
std::vector<TokenPtr> children;
TokenPtr annotation;
Token(const std::string &token_text, int id, const char *fname) :
text(token_text), identifier(id), filename(fname), is_cached(false) { }
Token(const std::string &token_text, int id, const char *fname, int start_line, int start_col, int end_line, int end_col) :
text(token_text), identifier(id), filename(fname), is_cached(false) {
start.line = start_line;
start.column = start_col;
end.line = end_line;
end.column = end_col;
}
};
/**
* Errors generated during parsing or evaluation
*/
struct Eval_Error : public std::runtime_error {
std::string reason;
File_Position start_position;
File_Position end_position;
const char *filename;
Eval_Error(const std::string &why, const File_Position &where, const char *fname) :
std::runtime_error("Error: \"" + why + "\" " +
(std::string(fname) != "__EVAL__" ? ("in '" + std::string(fname) + "' ") : "during evaluation ") +
+ "at (" + boost::lexical_cast<std::string>(where.line) + ", " +
boost::lexical_cast<std::string>(where.column) + ")"),
reason(why), start_position(where), end_position(where), filename(fname)
{ }
Eval_Error(const std::string &why, const TokenPtr &where)
: std::runtime_error("Error: \"" + why + "\" " +
(std::string(where->filename) != "__EVAL__" ? ("in '" + std::string(where->filename) + "' ") : "during evaluation ") +
"at (" + boost::lexical_cast<std::string>(where->start.line) + ", " +
boost::lexical_cast<std::string>(where->start.column) + ")"),
reason(why), start_position(where->start), end_position(where->end), filename(where->filename) {
}
virtual ~Eval_Error() throw() {}
};
/**
* Errors generated when loading a file
*/
struct File_Not_Found_Error : public std::runtime_error {
File_Not_Found_Error(const std::string &filename)
: std::runtime_error("File Not Found: " + filename)
{ }
virtual ~File_Not_Found_Error() throw() {}
};
/**
* Special type for returned values
*/
struct Return_Value {
Boxed_Value retval;
TokenPtr location;
Return_Value(const Boxed_Value &return_value, const TokenPtr where) : retval(return_value), location(where) { }
};
/**
* Special type indicating a call to 'break'
*/
struct Break_Loop {
TokenPtr location;
Break_Loop(const TokenPtr where) : location(where) { }
};
}
#endif /* _CHAISCRIPT_COMMON_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, Jonathan Turner (jturner@minnow-lang.org) // Copyright 2009-2010, Jonathan Turner (jturner@minnow-lang.org)
// and Jason Turner (lefticus@gmail.com) // and Jason Turner (lefticus@gmail.com)
// http://www.chaiscript.com // http://www.chaiscript.com
@@ -10,22 +10,502 @@
#include <exception> #include <exception>
#include <fstream> #include <fstream>
#include <chaiscript/language/chaiscript_common.hpp>
#include "chaiscript_prelude.hpp" #ifdef _POSIX_VERSION
#include "chaiscript_parser.hpp" #include <dlfcn.h>
#else
#ifdef WIN32
#include <Windows.h>
#endif
#endif
#include <chaiscript/language/chaiscript_prelude.hpp>
#include <chaiscript/language/chaiscript_parser.hpp>
namespace chaiscript namespace chaiscript
{ {
struct load_module_error : std::runtime_error
{
load_module_error(const std::string &reason) throw()
: std::runtime_error(reason)
{
}
virtual ~load_module_error() throw()
{
}
};
#ifdef _POSIX_VERSION
struct Loadable_Module
{
struct DLModule
{
DLModule(const std::string &t_filename)
: m_data(dlopen(t_filename.c_str(), RTLD_NOW))
{
if (!m_data)
{
throw load_module_error(dlerror());
}
}
DLModule(const DLModule &); // Explicitly unimplemented copy constructor
DLModule &operator=(const DLModule &); // Explicitly unimplemented assignment operator
~DLModule()
{
dlclose(m_data);
}
void *m_data;
};
template<typename T>
struct DLSym
{
DLSym(DLModule &t_mod, const std::string &t_symbol)
: m_symbol(reinterpret_cast<T>(dlsym(t_mod.m_data, t_symbol.c_str())))
{
if (!m_symbol)
{
throw load_module_error(dlerror());
}
}
T m_symbol;
};
Loadable_Module(const std::string &t_module_name, const std::string &t_filename)
: m_dlmodule(t_filename), m_func(m_dlmodule, "create_chaiscript_module_" + t_module_name),
m_moduleptr(m_func.m_symbol())
{
}
DLModule m_dlmodule;
DLSym<Create_Module_Func> m_func;
ModulePtr m_moduleptr;
};
#else
#ifdef WIN32
struct Loadable_Module
{
template<typename T>
static std::wstring towstring(const T &str)
{
return std::wstring(str.begin(), str.end());
}
template<typename T>
static std::string tostring(const T &str)
{
return std::string(str.begin(), str.end());
}
#ifdef _UNICODE
template<typename T>
static std::wstring toproperstring(const T &str)
{
return towstring(str);
}
#else
template<typename T>
static std::string toproperstring(const T &str)
{
return tostring(str);
}
#endif
static std::string GetErrorMessage(DWORD err)
{
#ifdef _UNICODE
typedef LPWSTR StringType;
std::wstring retval = L"Unknown Error";
#else
typedef LPSTR StringType;
std::string retval = "Unknown Error";
#endif
StringType lpMsgBuf = 0;
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
err,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(StringType)&lpMsgBuf,
0, NULL );
if (lpMsgBuf)
{
retval = lpMsgBuf;
}
LocalFree(lpMsgBuf);
return tostring(retval);
}
struct DLModule
{
DLModule(const std::string &t_filename)
: m_data(LoadLibrary(toproperstring(t_filename).c_str()))
{
if (!m_data)
{
throw load_module_error(GetErrorMessage(GetLastError()));
}
}
~DLModule()
{
FreeLibrary(m_data);
}
HMODULE m_data;
};
template<typename T>
struct DLSym
{
DLSym(DLModule &t_mod, const std::string &t_symbol)
: m_symbol(reinterpret_cast<T>(GetProcAddress(t_mod.m_data, t_symbol.c_str())))
{
if (!m_symbol)
{
throw load_module_error(GetErrorMessage(GetLastError()));
}
}
T m_symbol;
};
Loadable_Module(const std::string &t_module_name, const std::string &t_filename)
: m_dlmodule(t_filename), m_func(m_dlmodule, "create_chaiscript_module_" + t_module_name),
m_moduleptr(m_func.m_symbol())
{
}
DLModule m_dlmodule;
DLSym<Create_Module_Func> m_func;
ModulePtr m_moduleptr;
};
#else
struct Loadable_Module
{
Loadable_Module(const std::string &, const std::string &)
{
throw load_module_error("Loadable module support not available for your platform");
}
ModulePtr get()
{
throw load_module_error("Loadable module support not available for your platform");
}
};
#endif
#endif
typedef boost::shared_ptr<Loadable_Module> Loadable_Module_Ptr;
template <typename Eval_Engine> template <typename Eval_Engine>
class ChaiScript_System { class ChaiScript_System {
#ifndef CHAISCRIPT_NO_THREADS
mutable boost::shared_mutex mutex;
mutable boost::recursive_mutex use_mutex;
#endif
std::set<std::string> loaded_files;
std::map<std::string, Loadable_Module_Ptr> loaded_modules;
std::set<std::string> active_loaded_modules;
std::vector<std::string> modulepaths;
std::vector<std::string> usepaths;
Eval_Engine engine; Eval_Engine engine;
ChaiScript_Parser parser;
/**
* Evaluates the given string in by parsing it and running the results through the evaluator
*/
Boxed_Value do_eval(const std::string &input, const std::string &filename = "__EVAL__", bool internal = false) {
ChaiScript_Parser parser;
if (!internal)
{
engine.sync_cache();
}
//debug_print(tokens);
Boxed_Value value;
// Keep a cache of all loaded filenames and use the char * from this cache to pass
// to the parser. This is so that the parser does not have the overhead of passing
// around and copying strings
//
if (filename != "__EVAL__")
{
#ifndef CHAISCRIPT_NO_THREADS
boost::unique_lock<boost::shared_mutex> l(mutex);
#endif
loaded_files.insert(filename);
try {
if (parser.parse(input, loaded_files.find(filename)->c_str())) {
#ifndef CHAISCRIPT_NO_THREADS
l.unlock();
#endif
//parser.show_match_stack();
value = eval_token<Eval_Engine>(engine, parser.ast());
}
}
catch (const Return_Value &rv) {
value = rv.retval;
}
} else {
try {
#ifndef CHAISCRIPT_NO_THREADS
boost::shared_lock<boost::shared_mutex> l(mutex);
#endif
const char *fname = loaded_files.find("__EVAL__")->c_str();
#ifndef CHAISCRIPT_NO_THREADS
l.unlock();
#endif
if (parser.parse(input, fname)) {
//parser.show_match_stack();
value = eval_token<Eval_Engine>(engine, parser.ast());
}
}
catch (const Return_Value &rv) {
value = rv.retval;
}
}
if (!internal)
{
engine.sync_cache();
}
return value;
}
/**
* Evaluates the given boxed string, used during eval() inside of a script
*/
const Boxed_Value internal_eval(const std::string &e) {
return do_eval(e, "__EVAL__", true);
}
void use(const std::string &filename)
{
for (size_t i = 0; i < usepaths.size(); ++i)
{
try {
const std::string appendedpath = usepaths[i] + filename;
#ifndef CHAISCRIPT_NO_THREADS
boost::lock_guard<boost::recursive_mutex> l(use_mutex);
boost::shared_lock<boost::shared_mutex> l2(mutex);
#endif
if (loaded_files.count(appendedpath) == 0)
{
#ifndef CHAISCRIPT_NO_THREADS
l2.unlock();
#endif
eval_file(appendedpath);
} else {
engine.sync_cache();
}
} catch (const File_Not_Found_Error &) {
if (i == usepaths.size() - 1)
{
throw File_Not_Found_Error(filename);
}
// failed to load, try the next path
}
}
}
public: public:
ChaiScript_System() { ChaiScript_System(const std::vector<std::string> &t_modulepaths = std::vector<std::string>(),
const std::vector<std::string> &t_usepaths = std::vector<std::string>())
: modulepaths(t_modulepaths), usepaths(t_usepaths) {
if (modulepaths.empty())
{
modulepaths.push_back("");
}
if (usepaths.empty())
{
usepaths.push_back("");
}
loaded_files.insert("__EVAL__"); // Make sure the default name is already registered
build_eval_system(); build_eval_system();
} }
/**
* Adds a shared object, that can be used by all threads, to the system
*/
ChaiScript_System &add_global_const(const Boxed_Value &bv, const std::string &name)
{
engine.add_global_const(bv, name);
return *this;
}
struct State
{
std::set<std::string> loaded_files;
typename Eval_Engine::State engine_state;
std::set<std::string> active_loaded_modules;
};
/**
* Returns a state object that represents the current
* set of loaded files, the set of global variables and
* the set of initialized functions
*/
State get_state()
{
#ifndef CHAISCRIPT_NO_THREADS
boost::lock_guard<boost::recursive_mutex> l(use_mutex);
boost::shared_lock<boost::shared_mutex> l2(mutex);
#endif
State s;
s.loaded_files = loaded_files;
s.engine_state = engine.get_state();
s.active_loaded_modules = active_loaded_modules;
return s;
}
/**
* Restores the state from a saved State object.
*/
void set_state(const State &t_state)
{
#ifndef CHAISCRIPT_NO_THREADS
boost::lock_guard<boost::recursive_mutex> l(use_mutex);
boost::shared_lock<boost::shared_mutex> l2(mutex);
#endif
loaded_files = t_state.loaded_files;
active_loaded_modules = t_state.active_loaded_modules;
engine.set_state(t_state.engine_state);
}
/**
* Adds an object to the system: type, function, object
*/
template<typename T>
ChaiScript_System &add(const T &t, const std::string &name)
{
engine.add(t, name);
return *this;
}
/**
* Adds a module object to the system
*/
ChaiScript_System &add(const ModulePtr &p)
{
p->apply(*this, this->get_eval_engine());
return *this;
}
/**
* Load a dynamic library containing a chaiscript module
*/
void load_module(const std::string &t_module_name)
{
std::vector<std::string> prefixes;
prefixes.push_back("lib");
prefixes.push_back("");
std::vector<std::string> postfixes;
postfixes.push_back(".dll");
postfixes.push_back(".so");
postfixes.push_back("");
for (size_t i = 0; i < modulepaths.size(); ++i)
{
for (size_t j = 0; j < prefixes.size(); ++j)
{
for (size_t k = 0; k < postfixes.size(); ++k)
{
try {
std::string name = modulepaths[i] + prefixes[j] + t_module_name + postfixes[k];
load_module(t_module_name, name);
return;
} catch (const load_module_error &) {
// Try next set
}
}
}
}
throw load_module_error("Unable to find module: " + t_module_name);
}
/**
* Load a dynamic library and provide the file name to load it from
*/
void load_module(const std::string &t_module_name, const std::string &t_filename)
{
#ifndef CHAISCRIPT_NO_THREADS
boost::lock_guard<boost::recursive_mutex> l(use_mutex);
#endif
if (loaded_modules.count(t_module_name) == 0)
{
Loadable_Module_Ptr lm(new Loadable_Module(t_module_name, t_filename));
loaded_modules[t_module_name] = lm;
active_loaded_modules.insert(t_module_name);
add(lm->m_moduleptr);
} else if (active_loaded_modules.count(t_module_name) == 0) {
active_loaded_modules.insert(t_module_name);
add(loaded_modules[t_module_name]->m_moduleptr);
} else {
engine.sync_cache();
}
}
/**
* Helper for calling script code as if it were native C++ code
* example:
* boost::function<int (int, int)> f = build_functor(chai, "func(x, y){x+y}");
* \return a boost::function representing the passed in script
* \param[in] script Script code to build a function from
*/
template<typename FunctionType>
boost::function<FunctionType> functor(const std::string &script)
{
return chaiscript::functor<FunctionType>(eval(script));
}
/**
* Evaluate a string via eval method
*/
Boxed_Value operator()(const std::string &script)
{
return do_eval(script);
}
/** /**
* Returns the current evaluation engine * Returns the current evaluation engine
*/ */
@@ -43,25 +523,14 @@ namespace chaiscript
} }
} }
/**
* Evaluates the given boxed string, used during eval() inside of a script
*/
const dispatchkit::Boxed_Value eval(const std::vector<dispatchkit::Boxed_Value> &vals) {
std::string val;
val = dispatchkit::boxed_cast<std::string &>(vals[0]);
return evaluate_string(val);
}
/** /**
* Helper function for loading a file * Helper function for loading a file
*/ */
std::string load_file(const char *filename) { std::string load_file(const std::string &filename) {
std::ifstream infile (filename, std::ios::in | std::ios::ate); std::ifstream infile (filename.c_str(), std::ios::in | std::ios::ate);
if (!infile.is_open()) { if (!infile.is_open()) {
std::string fname = filename; throw File_Not_Found_Error(filename);
throw std::runtime_error("Can not open: " + fname);
} }
std::streampos size = infile.tellg(); std::streampos size = infile.tellg();
@@ -79,48 +548,82 @@ namespace chaiscript
* Builds all the requirements for ChaiScript, including its evaluator and a run of its prelude. * Builds all the requirements for ChaiScript, including its evaluator and a run of its prelude.
*/ */
void build_eval_system() { void build_eval_system() {
dispatchkit::Bootstrap::bootstrap(engine); using namespace bootstrap;
dispatchkit::bootstrap_vector<std::vector<dispatchkit::Boxed_Value> >(engine, "Vector"); engine.add_reserved_word("def");
dispatchkit::bootstrap_string<std::string>(engine, "string"); engine.add_reserved_word("fun");
dispatchkit::bootstrap_map<std::map<std::string, dispatchkit::Boxed_Value> >(engine, "Map"); engine.add_reserved_word("while");
dispatchkit::bootstrap_pair<std::pair<dispatchkit::Boxed_Value, dispatchkit::Boxed_Value > >(engine, "Pair"); engine.add_reserved_word("for");
engine.add_reserved_word("if");
engine.add_reserved_word("else");
engine.add_reserved_word("&&");
engine.add_reserved_word("||");
engine.add_reserved_word(",");
engine.add_reserved_word(":=");
engine.add_reserved_word("var");
engine.add_reserved_word("return");
engine.add_reserved_word("break");
engine.add_reserved_word("true");
engine.add_reserved_word("false");
engine.add_reserved_word("_");
engine.register_function(boost::shared_ptr<dispatchkit::Proxy_Function>( add(Bootstrap::bootstrap());
new dispatchkit::Dynamic_Proxy_Function(boost::bind(&ChaiScript_System<Eval_Engine>::eval, boost::ref(*this), _1), 1)), "eval");
evaluate_string(chaiscript_prelude); engine.add(fun(&Eval_Engine::dump_system, boost::ref(engine)), "dump_system");
engine.add(fun(&Eval_Engine::dump_object, boost::ref(engine)), "dump_object");
engine.add(fun(&Eval_Engine::is_type, boost::ref(engine)), "is_type");
engine.add(fun(&Eval_Engine::type_name, boost::ref(engine)), "type_name");
engine.add(fun(&Eval_Engine::function_exists, boost::ref(engine)), "function_exists");
engine.add(fun(&Eval_Engine::get_type_name, boost::ref(engine)), "name");
typedef void (ChaiScript_System<Eval_Engine>::*load_mod_1)(const std::string&);
typedef void (ChaiScript_System<Eval_Engine>::*load_mod_2)(const std::string&, const std::string&);
engine.add(fun(static_cast<load_mod_1>(&ChaiScript_System<Eval_Engine>::load_module), this), "load_module");
engine.add(fun(static_cast<load_mod_2>(&ChaiScript_System<Eval_Engine>::load_module), this), "load_module");
add(vector_type<std::vector<Boxed_Value> >("Vector"));
add(string_type<std::string>("string"));
add(map_type<std::map<std::string, Boxed_Value> >("Map"));
add(pair_type<std::pair<Boxed_Value, Boxed_Value > >("Pair"));
engine.add(fun(&ChaiScript_System<Eval_Engine>::use, this), "use");
engine.add(fun(&ChaiScript_System<Eval_Engine>::internal_eval, this), "eval");
do_eval(chaiscript_prelude, "standard prelude");
} }
/** template<typename T>
* Evaluates the given string in by parsing it and running the results through the evaluator T eval(const std::string &input)
*/ {
dispatchkit::Boxed_Value evaluate_string(const std::string &input, const char *filename = "__EVAL__") { return boxed_cast<T>(do_eval(input));
//debug_print(tokens); }
dispatchkit::Boxed_Value value;
parser.clear_match_stack();
try { Boxed_Value eval(const std::string &input)
if (parser.parse(input, filename)) { {
//parser.show_match_stack(); return do_eval(input);
value = eval_token<Eval_Engine>(engine, parser.ast());
}
}
catch (const Return_Value &rv) {
value = rv.retval;
}
return value;
} }
/** /**
* Loads the file specified by filename, evaluates it, and returns the result * Loads the file specified by filename, evaluates it, and returns the result
*/ */
dispatchkit::Boxed_Value evaluate_file(const char *filename) { Boxed_Value eval_file(const std::string &filename) {
return evaluate_string(load_file(filename), filename); return do_eval(load_file(filename), filename);
}
/**
* Loads the file specified by filename, evaluates it, and returns the as the specified type
*/
template<typename T>
T eval_file(const std::string &filename) {
return boxed_cast<T>(do_eval(load_file(filename), filename));
} }
}; };
typedef ChaiScript_System<dispatchkit::Dispatch_Engine> ChaiScript_Engine; typedef ChaiScript_System<Dispatch_Engine> ChaiScript;
} }
#endif /* CHAISCRIPT_ENGINE_HPP_ */ #endif /* CHAISCRIPT_ENGINE_HPP_ */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

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, Jonathan Turner (jturner@minnow-lang.org) // Copyright 2009-2010, Jonathan Turner (jturner@minnow-lang.org)
// and Jason Turner (lefticus@gmail.com) // and Jason Turner (lefticus@gmail.com)
// http://www.chaiscript.com // http://www.chaiscript.com
@@ -9,257 +9,321 @@
//Note, the expression "[x,y]" in "collate" is parsed as two separate expressions //Note, the expression "[x,y]" in "collate" is parsed as two separate expressions
//by C++, so CODE_STRING, takes two expressions and adds in the missing comma //by C++, so CODE_STRING, takes two expressions and adds in the missing comma
#define CODE_STRING(x, y) #x ", " #y #define CODE_STRING(x, y) #x ", " #y
#define chaiscript_prelude CODE_STRING(\ #define chaiscript_prelude CODE_STRING(\
def lt(l, r) { if (call_exists(`<`, l, r)) { l < r } else { type_name(l) < type_name(r) } } \n\
def gt(l, r) { if (call_exists(`>`, l, r)) { l > r } else { type_name(l) > type_name(r) } } \n\
def eq(l, r) { if (call_exists(`==`, l, r)) { l == r } else { false } } \n\
def new(x) { eval(type_name(x))(); } \n\
def clone(x) : function_exists(type_name(x)) && call_exists(eval(type_name(x)), x) { eval(type_name(x))(x); } \n\
# to_string for Pair()\n\ # to_string for Pair()\n\
def to_string(x) : call_exists(first, x) && call_exists(second, x) { \ def to_string(x) : call_exists(first, x) && call_exists(second, x) { \n\
"<" + x.first.to_string() + ", " + x.second.to_string() + ">"; \ "<" + x.first.to_string() + ", " + x.second.to_string() + ">"; \n\
}\ }\n\
# to_string for containers\n\ # to_string for containers\n\
def to_string(x) : call_exists(range, x) && !x.is_type("string"){ \ def to_string(x) : call_exists(range, x) && !x.is_type("string"){ \n\
"[" + x.join(", ") + "]"; \ "[" + x.join(", ") + "]"; \n\
}\ }\n\
# Basic to_string function\n\ # Basic to_string function\n\
def to_string(x) { \ def to_string(x) { \n\
return internal_to_string(x); \ internal_to_string(x); \n\
}\ }\n\
# Prints to console with no carriage return\n\ # Prints to console with no carriage return\n\
def puts(x) { \ def puts(x) { \n\
print_string(x.to_string()); \ print_string(x.to_string()); \n\
} \ } \n\
# Prints to console with carriage return\n\ # Prints to console with carriage return\n\
def print(x) { \ def print(x) { \n\
println_string(x.to_string()); \ println_string(x.to_string()); \n\
} \ } \n\
# Returns the maximum value of two numbers\n\ # Returns the maximum value of two numbers\n\
def max(a, b) { if (a>b) { a } else { b } } \ def max(a, b) { if (a>b) { a } else { b } } \n\
# Returns the minimum value of two numbers\n\ # Returns the minimum value of two numbers\n\
def min(a, b) { if (a<b) { a } else { b } } \ def min(a, b) { if (a<b) { a } else { b } } \n\
# Returns true if the value is odd\n\ # Returns true if the value is odd\n\
def odd(x) { if (x % 2 == 1) { true } else { false } } \ def odd(x) { if (x % 2 == 1) { true } else { false } } \n\
# Returns true if the value is even\n\ # Returns true if the value is even\n\
def even(x) { if (x % 2 == 0) { true } else { false } } \ def even(x) { if (x % 2 == 0) { true } else { false } } \n\
# Pushes the second value onto the container first value while making a clone of the value\n\ # Pushes the second value onto the container first value while making a clone of the value\n\
def push_back(container, x) { container.push_back_ref(clone(x)) } \n\ def push_back(container, x) : call_exists(push_back_ref, container, x) { container.push_back_ref(clone(x)) } \n\
# Pushes the second value onto the front of the container first value while making a clone of the value\n\
def push_front(container, x) : call_exists(push_front_ref, container, x) { container.push_front_ref(clone(x)) } \n\
# Inserts the third value at the position of the second value into the container of the first\n\ # Inserts the third value at the position of the second value into the container of the first\n\
# while making a clone. \n\ # while making a clone. \n\
def insert_at(container, pos, x) { container.insert_ref_at(pos, clone(x)); } \n\ def insert_at(container, pos, x) { container.insert_ref_at(pos, clone(x)); } \n\
# Returns the reverse of the given container\n\
def reverse(container) {\n\
var retval = new(container); \n\
var r = range(container); \n\
while (!r.empty()) { \n\
retval.push_back(r.back()); \n\
r.pop_back(); \n\
} \n\
retval; \n\
} \n\
# Return a range from a range \n\
def range(r) : call_exists(empty, r) && call_exists(pop_front, r) && call_exists(pop_back, r) && call_exists(back, r) && call_exists(front, r) { return clone(r); }\n\
# The retro attribute that contains the underlying range \n\
attr retro::m_range; \n\
# Creates a retro from a retro by returning the original range\n\
def retro(r) : call_exists(get_type_name, r) && get_type_name(r) == "retro" { clone(r.m_range) }\n\
# Creates a retro range from a range\n\
def retro::retro(r) : call_exists(empty, r) && call_exists(pop_front, r) && call_exists(pop_back, r) && call_exists(back, r) && call_exists(front, r) { this.m_range = r; }\n\
# Returns the first value of a retro\n\
def retro::front() { back(this.m_range) }\n\
# Returns the last value of a retro\n\
def retro::back() { front(this.m_range) }\n\
# Moves the back iterator of a retro towards the front by one \n\
def retro::pop_back() { pop_front(this.m_range) }\n\
# Moves the front iterator of a retro towards the back by one \n\
def retro::pop_front() { pop_back(this.m_range) } \n\
# returns true if the retro is out of elements \n\
def retro::empty() { empty(this.m_range); } \n\
# Performs the second value function over the container first value\n\ # Performs the second value function over the container first value\n\
def for_each(container, func) : call_exists(range, container) { \ def for_each(container, func) : call_exists(range, container) { \n\
var range = range(container); \ var t_range = range(container); \n\
while (!range.empty()) { \ while (!t_range.empty()) { \n\
func(range.front()); \ func(t_range.front()); \n\
range.pop_front(); \ t_range.pop_front(); \n\
} \ } \n\
} \ } \n\
def back_inserter(container) { \ def back_inserter(container) { \n\
return bind(push_back, container, _); \ bind(push_back, container, _); \n\
}\ }\n\
\ \n\
def map(container, func, inserter) : call_exists(range, container) { \ def contains(container, item, compare_func) : call_exists(range, container) { \n\
var range = range(container); \ var t_range = range(container); \n\
while (!range.empty()) { \ while (!t_range.empty()) { \n\
inserter(func(range.front())); \ if ( compare_func(t_range.front(), item) ) { return true; } \n\
range.pop_front(); \ t_range.pop_front(); \n\
} \ } \n\
} \ return false; \n\
# Performs the second value function over the container first value. Creates a new Vector with the results\n\ } \n\
def map(container, func) { \ def contains(container, item) { return contains(container, item, eq) } \n\
var retval = Vector();\ def map(container, func, inserter) : call_exists(range, container) { \n\
map(container, func, back_inserter(retval));\ var range = range(container); \n\
return retval;\ while (!range.empty()) { \n\
}\ inserter(func(range.front())); \n\
range.pop_front(); \n\
} \n\
} \n\
# Performs the second value function over the container first value. Creates a new container with the results\n\
def map(container, func) { \n\
var retval = new(container); \n\
map(container, func, back_inserter(retval));\n\
retval;\n\
}\n\
# Performs the second value function over the container first value. Starts with initial and continues with each element.\n\ # Performs the second value function over the container first value. Starts with initial and continues with each element.\n\
def foldl(container, func, initial) : call_exists(range, container){ \ def foldl(container, func, initial) : call_exists(range, container){ \n\
var retval = initial; \ var retval = initial; \n\
var range = range(container); \ var range = range(container); \n\
while (!range.empty()) { \ while (!range.empty()) { \n\
retval = (func(range.front(), retval)); \ retval = (func(range.front(), retval)); \n\
range.pop_front(); \ range.pop_front(); \n\
} \ } \n\
retval; \ retval; \n\
} \ } \n\
# Returns the sum of the elements of the given value\n\ # Returns the sum of the elements of the given value\n\
def sum(container) { foldl(container, `+`, 0.0) } \ def sum(container) { foldl(container, `+`, 0.0) } \n\
# Returns the product of the elements of the given value\n\ # Returns the product of the elements of the given value\n\
def product(container) { foldl(container, `*`, 1.0) } \ def product(container) { foldl(container, `*`, 1.0) } \n\
# Returns a new Vector with the elements of the first value concatenated with the elements of the second value\n\ # Returns a new container with the elements of the first value concatenated with the elements of the second value\n\
def concat(x, y) : call_exists(clone, x) { \ def concat(x, y) : call_exists(clone, x) { \n\
var retval = x; \ var retval = x; \n\
var len = y.size(); \ var len = y.size(); \n\
var i = 0; \ var i = 0; \n\
while (i < len) { \ while (i < len) { \n\
retval.push_back(y[i]); \ retval.push_back(y[i]); \n\
++i; \ ++i; \n\
} \ } \n\
retval; \ retval; \n\
} \ } \n\
def take(container, num, inserter) : call_exists(range, container) { \ def take(container, num, inserter) : call_exists(range, container) { \n\
var r = range(container); \ var r = range(container); \n\
var i = num; \ var i = num; \n\
while ((i > 0) && (!r.empty())) { \ while ((i > 0) && (!r.empty())) { \n\
inserter(r.front()); \ inserter(r.front()); \n\
r.pop_front(); \ r.pop_front(); \n\
--i; \ --i; \n\
} \ } \n\
} \ } \n\
# Returns a new Vector with the given number of elements taken from the container\n\ # Returns a new container with the given number of elements taken from the container\n\
def take(container, num) {\ def take(container, num) {\n\
var retval = Vector(); \ var retval = new(container); \n\
take(container, num, back_inserter(retval)); \ take(container, num, back_inserter(retval)); \n\
return retval; \ retval; \n\
}\ }\n\
def take_while(container, f, inserter) : call_exists(range, container) { \ def take_while(container, f, inserter) : call_exists(range, container) { \n\
var r = range(container); \ var r = range(container); \n\
while ((!r.empty()) && f(r.front())) { \ while ((!r.empty()) && f(r.front())) { \n\
inserter(r.front()); \ inserter(r.front()); \n\
r.pop_front(); \ r.pop_front(); \n\
} \ } \n\
} \ } \n\
# Returns a new Vector with the given elements match the second value function\n\ # Returns a new container with the given elements match the second value function\n\
def take_while(container, f) {\ def take_while(container, f) {\n\
var retval = Vector(); \ var retval = new(container); \n\
take_while(container, f, back_inserter(retval)); \ take_while(container, f, back_inserter(retval)); \n\
return retval;\ retval;\n\
}\ }\n\
def drop(container, num, inserter) : call_exists(range, container) { \ def drop(container, num, inserter) : call_exists(range, container) { \n\
var r = range(container); \ var r = range(container); \n\
var i = num; \ var i = num; \n\
while ((i > 0) && (!r.empty())) { \ while ((i > 0) && (!r.empty())) { \n\
r.pop_front(); \ r.pop_front(); \n\
--i; \ --i; \n\
} \ } \n\
while (!r.empty()) { \ while (!r.empty()) { \n\
inserter(r.front()); \ inserter(r.front()); \n\
r.pop_front(); \ r.pop_front(); \n\
} \ } \n\
} \ } \n\
# Returns a new Vector with the given number of elements dropped from the given container \n\ # Returns a new container with the given number of elements dropped from the given container \n\
def drop(container, num) {\ def drop(container, num) {\n\
var retval = Vector(); \ var retval = new(container); \n\
drop(container, num, back_inserter(retval)); \ drop(container, num, back_inserter(retval)); \n\
return retval; \ retval; \n\
}\ }\n\
def drop_while(container, f, inserter) : call_exists(range, container) { \ def drop_while(container, f, inserter) : call_exists(range, container) { \n\
var r = range(container); \ var r = range(container); \n\
while ((!r.empty())&& f(r.front())) { \ while ((!r.empty())&& f(r.front())) { \n\
r.pop_front(); \ r.pop_front(); \n\
} \ } \n\
while (!r.empty()) { \ while (!r.empty()) { \n\
inserter(r.front()); \ inserter(r.front()); \n\
r.pop_front(); \ r.pop_front(); \n\
} \ } \n\
} \ } \n\
# Returns a new Vector with the given elements dropped that match the second value function\n\ # Returns a new container with the given elements dropped that match the second value function\n\
def drop_while(container, f) {\ def drop_while(container, f) {\n\
var retval = Vector(); \ var retval = new(container); \n\
drop_while(container, f, back_inserter(retval)); \ drop_while(container, f, back_inserter(retval)); \n\
return retval; \ retval; \n\
}\ }\n\
# Applies the second value function to the container. Starts with the first two elements. Expects at least 2 elements.\n\ # Applies the second value function to the container. Starts with the first two elements. Expects at least 2 elements.\n\
def reduce(container, func) : container.size() >= 2 && call_exists(range, container) { \ def reduce(container, func) : container.size() >= 2 && call_exists(range, container) { \n\
var r = range(container); \ var r = range(container); \n\
var retval = r.front(); \ var retval = r.front(); \n\
r.pop_front(); \ r.pop_front(); \n\
retval = func(retval, r.front()); \ retval = func(retval, r.front()); \n\
r.pop_front(); \ r.pop_front(); \n\
while (!r.empty()) { \ while (!r.empty()) { \n\
retval = func(retval, r.front()); \ retval = func(retval, r.front()); \n\
r.pop_front(); \ r.pop_front(); \n\
} \ } \n\
retval; \ retval; \n\
} \ } \n\
# Returns a string of the elements in container delimited by the second value string\n\ # Returns a string of the elements in container delimited by the second value string\n\
def join(container, delim) { \ def join(container, delim) { \n\
var retval = ""; \ var retval = ""; \n\
var range = range(container); \ var range = range(container); \n\
if (!range.empty()) { \ if (!range.empty()) { \n\
retval += to_string(range.front()); \ retval += to_string(range.front()); \n\
range.pop_front(); \ range.pop_front(); \n\
while (!range.empty()) { \ while (!range.empty()) { \n\
retval += delim; \ retval += delim; \n\
retval += to_string(range.front()); \ retval += to_string(range.front()); \n\
range.pop_front(); \ range.pop_front(); \n\
} \ } \n\
} \ } \n\
retval; \ retval; \n\
} \ } \n\
def filter(container, f, inserter) : call_exists(range, container) { \ def filter(container, f, inserter) : call_exists(range, container) { \n\
var r = range(container); \ var r = range(container); \n\
while (!r.empty()) { \ while (!r.empty()) { \n\
if (f(r.front())) { \ if (f(r.front())) { \n\
inserter(r.front()); \ inserter(r.front()); \n\
} \ } \n\
r.pop_front(); \ r.pop_front(); \n\
} \ } \n\
} \ } \n\
# Returns a new Vector which match the second value function\n\ # Returns a new Vector which match the second value function\n\
def filter(container, f) { \ def filter(container, f) { \n\
var retval = Vector(); \ var retval = new(container); \n\
filter(container, f, back_inserter(retval));\ filter(container, f, back_inserter(retval));\n\
return retval;\ retval;\n\
}\ }\n\
def generate_range(x, y, inserter) { \ def generate_range(x, y, inserter) { \n\
var i = x; \ var i = x; \n\
while (i <= y) { \ while (i <= y) { \n\
inserter(i); \ inserter(i); \n\
++i; \ ++i; \n\
} \ } \n\
} \ } \n\
# Returns a new Vector which represents the range from the first value to the second value\n\ # Returns a new Vector which represents the range from the first value to the second value\n\
def generate_range(x, y) { \ def generate_range(x, y) { \n\
var retval = Vector(); \ var retval = Vector(); \n\
generate_range(x,y,back_inserter(retval)); \ generate_range(x,y,back_inserter(retval)); \n\
return retval; \ retval; \n\
}\ }\n\
# Returns a new Vector with the first value to the second value as its elements\n\ # Returns a new Vector with the first value to the second value as its elements\n\
def collate(x, y) { \ def collate(x, y) { \n\
[x, y]; \ [x, y]; \n\
} \ } \n\
def zip_with(f, x, y, inserter) : call_exists(range, x) && call_exists(range, y) { \ def zip_with(f, x, y, inserter) : call_exists(range, x) && call_exists(range, y) { \n\
var r_x = range(x); \ var r_x = range(x); \n\
var r_y = range(y); \ var r_y = range(y); \n\
while (!r_x.empty() && !r_y.empty()) { \ while (!r_x.empty() && !r_y.empty()) { \n\
inserter(f(r_x.front(), r_y.front())); \ inserter(f(r_x.front(), r_y.front())); \n\
r_x.pop_front(); \ r_x.pop_front(); \n\
r_y.pop_front(); \ r_y.pop_front(); \n\
} \ } \n\
} \ } \n\
# Returns a new Vector which joins matching elements of the second and third value with the first value function\n\ # Returns a new Vector which joins matching elements of the second and third value with the first value function\n\
def zip_with(f, x, y) { \ def zip_with(f, x, y) { \n\
var retval = Vector(); \ var retval = Vector(); \n\
zip_with(f,x,y,back_inserter(retval)); \ zip_with(f,x,y,back_inserter(retval)); \n\
return retval;\ retval;\n\
}\ }\n\
# Returns a new Vector which joins matching elements of the first and second\n\ # Returns a new Vector which joins matching elements of the first and second\n\
def zip(x, y) { \ def zip(x, y) { \n\
zip_with(collate, x, y); \ zip_with(collate, x, y); \n\
}\ }\n\
# Returns the position of the second value string in the first value string\n\ # Returns the position of the second value string in the first value string\n\
def find(str, substr) { \ def string::find(substr) : is_type(substr, "string") { \n\
return int(find(str, substr, size_t(0))); \ int(find(this, substr, 0)); \n\
} \ } \n\
# Returns the position of last match of the second value string in the first value string\n\ # Returns the position of last match of the second value string in the first value string\n\
def rfind(str, substr) { \ def string::rfind(substr) : is_type(substr, "string") { \n\
return int(rfind(str, substr, size_t(-1))); \ int(rfind(this, substr, -1)); \n\
} \ } \n\
# Returns the position of the first match of elements in the second value string in the first value string\n\ # Returns the position of the first match of elements in the second value string in the first value string\n\
def find_first_of(str, list) { \ def string::find_first_of(list) : is_type(list, "string") { \n\
return int(find_first_of(str, list, size_t(0))); \ int(find_first_of(this, list, 0)); \n\
} \ } \n\
# Returns the position of the last match of elements in the second value string in the first value string\n\ # Returns the position of the last match of elements in the second value string in the first value string\n\
def find_last_of(str, list) { \ def string::find_last_of(list) : is_type(list, "string") { \n\
return int(find_last_of(str, list, size_t(-1))); \ int(find_last_of(this, list, -1)); \n\
} \ } \n\
# Returns the position of the first non-matching element in the second value string in the first value string\n\ # Returns the position of the first non-matching element in the second value string in the first value string\n\
def find_first_not_of(str, list) { \ def string::find_first_not_of(list) : is_type(list, "string") { \n\
return int(find_first_not_of(str, list, size_t(0))); \ int(find_first_not_of(this, list, 0)); \n\
} \ } \n\
# Returns the position of the last non-matching element in the second value string in the first value string\n\ # Returns the position of the last non-matching element in the second value string in the first value string\n\
def find_last_not_of(str, list) { \ def string::find_last_not_of(list) : is_type(list, "string") { \n\
return int(find_last_not_of(str, list, size_t(-1))); \ int(find_last_not_of(this, list, -1)); \n\
} \ } \n\
def string::ltrim() { \n\
drop_while(this, fun(x) { x == ' ' || x == '\t' }); \n\
} \n\
def string::rtrim() { \n\
reverse(drop_while(reverse(this), fun(x) { x == ' ' || x == '\t' })); \n\
} \n\
def string::trim() { \n\
ltrim(rtrim(this)); \n\
} \n\
def find(container, value, compare_func) : call_exists(range, container) && is_type(compare_func, "function") { \n\
var range = range(container); \n\
while (!range.empty()) { \n\
if (compare_func(range.front(), value)) { \n\
return range; \n\
} else { \n\
range.pop_front(); \n\
} \n\
} \n\
return range; \n\
} \n\
def find(container, value) { return find(container, value, eq) } \
) )
#endif /* CHAISCRIPT_PRELUDE_HPP_ */ #endif /* CHAISCRIPT_PRELUDE_HPP_ */

View File

@@ -1,4 +1,4 @@
Copyright 2009 Jason and Jonathan Turner. All Rights Reserved. Copyright 2009-2010 Jason Turner and Jonathan Turner. All Rights Reserved.
Redistribution and use in source and binary forms, with or without 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:

View File

@@ -1,11 +0,0 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioPropertySheet
ProjectType="Visual C++"
Version="8.00"
Name="Boost"
>
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories="&quot;C:\Programming\Boost\include\boost-1_38&quot;"
/>
</VisualStudioPropertySheet>

View File

@@ -1,20 +0,0 @@

Microsoft Visual Studio Solution File, Format Version 10.00
# Visual C++ Express 2008
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "chaiscript", "chaiscript.vcproj", "{46FD9DC7-2DA9-4C17-ADE4-E3A18C46E87B}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Release|Win32 = Release|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{46FD9DC7-2DA9-4C17-ADE4-E3A18C46E87B}.Debug|Win32.ActiveCfg = Debug|Win32
{46FD9DC7-2DA9-4C17-ADE4-E3A18C46E87B}.Debug|Win32.Build.0 = Debug|Win32
{46FD9DC7-2DA9-4C17-ADE4-E3A18C46E87B}.Release|Win32.ActiveCfg = Release|Win32
{46FD9DC7-2DA9-4C17-ADE4-E3A18C46E87B}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

View File

@@ -1,258 +0,0 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="9.00"
Name="chaiscript"
ProjectGUID="{46FD9DC7-2DA9-4C17-ADE4-E3A18C46E87B}"
RootNamespace="chaiscript"
Keyword="Win32Proj"
TargetFrameworkVersion="196613"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
InheritedPropertySheets=".\Boost.vsprops"
UseOfMFC="2"
CharacterSet="0"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
UseUnicodeResponseFiles="false"
Optimization="0"
AdditionalIncludeDirectories="&quot;$(ProjectDir)\..\..\include&quot;"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
DisableLanguageExtensions="true"
TreatWChar_tAsBuiltInType="false"
UsePrecompiledHeader="0"
WarningLevel="4"
DebugInformationFormat="4"
CompileAs="2"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
LinkIncremental="2"
GenerateDebugInformation="true"
SubSystem="1"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
InheritedPropertySheets=".\Boost.vsprops"
CharacterSet="0"
WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="3"
EnableIntrinsicFunctions="true"
AdditionalIncludeDirectories="&quot;$(ProjectDir)\..\..\dispatchkit&quot;;&quot;$(ProjectDir)\..\..\chaiscript&quot;"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
RuntimeLibrary="2"
EnableFunctionLevelLinking="true"
UsePrecompiledHeader="0"
WarningLevel="4"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
LinkIncremental="1"
GenerateDebugInformation="true"
SubSystem="1"
OptimizeReferences="2"
EnableCOMDATFolding="2"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
>
<File
RelativePath="..\..\src\main.cpp"
>
</File>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
>
<File
RelativePath="..\..\include\chaiscript\dispatchkit\bootstrap.hpp"
>
</File>
<File
RelativePath="..\..\include\chaiscript\dispatchkit\bootstrap_stl.hpp"
>
</File>
<File
RelativePath="..\..\include\chaiscript\dispatchkit\boxed_value.hpp"
>
</File>
<File
RelativePath="..\..\include\chaiscript\chaiscript.hpp"
>
</File>
<File
RelativePath="..\..\include\chaiscript\language\chaiscript_engine.hpp"
>
</File>
<File
RelativePath="..\..\include\chaiscript\language\chaiscript_eval.hpp"
>
</File>
<File
RelativePath="..\..\include\chaiscript\language\chaiscript_parser.hpp"
>
</File>
<File
RelativePath="..\..\include\chaiscript\language\chaiscript_prelude.hpp"
>
</File>
<File
RelativePath="..\..\include\chaiscript\dispatchkit\dispatchkit.hpp"
>
</File>
<File
RelativePath="..\..\include\chaiscript\dispatchkit\function_call.hpp"
>
</File>
<File
RelativePath="..\..\include\chaiscript\dispatchkit\proxy_constructors.hpp"
>
</File>
<File
RelativePath="..\..\include\chaiscript\dispatchkit\proxy_functions.hpp"
>
</File>
<File
RelativePath="..\..\include\chaiscript\dispatchkit\register_function.hpp"
>
</File>
<File
RelativePath="..\..\include\chaiscript\dispatchkit\type_info.hpp"
>
</File>
</Filter>
<Filter
Name="Resource Files"
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
>
</Filter>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

View File

@@ -1,6 +1,6 @@
ChaiScript v1.0 ChaiScript v2.3.3
http://www.chaiscript.com http://www.chaiscript.com
(c) 2009 Jason Turner and Jonathan Turner (c) 2009-2010 Jason Turner and Jonathan Turner
Release under the BSD license, see "license.txt" for details. Release under the BSD license, see "license.txt" for details.
[Introduction] [Introduction]

View File

@@ -1,25 +0,0 @@
#!/bin/bash
successes=0
failures=0
echo -n "Running unit tests"
for file in unittests/*.chai
do
tstname=${file%.*}
tst="$tstname.txt"
./chaiscript_eval $file > /tmp/tstout.txt
diff $tst /tmp/tstout.txt
if [ "$?" -eq "0" ]
then
echo -n "."
successes=$((successes+1))
else
echo "[from failed test $file]"
failures=$((failures+1))
fi
done
echo ""
total=$((successes+failures))
echo "$successes out of $total succeeded"

View File

@@ -1,3 +1,2 @@
var i = 1 var i = 1
var j = eval("5 + 4") var j = eval("5 + 4")
print(j)

View File

@@ -2,11 +2,11 @@ for (var i = 0; i < 10; ++i) {
print(i) print(i)
} }
for (i = 10; i >= 0; i -= 2) { for (var i = 10; i >= 0; i -= 2) {
print(i) print(i)
} }
i = 0 var i = 0
for (; i < 5; ++i) { for (; i < 5; ++i) {
print(i) print(i)

View File

@@ -2,7 +2,7 @@ var i = 0
if (i == 0) { if (i == 0) {
print("i is 0") print("i is 0")
} }
elseif (i == 1) { else if (i == 1) {
print("i is 1") print("i is 1")
} }
else { else {

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, Jonathan Turner (jturner@minnow-lang.org) // Copyright 2009-2010, Jonathan Turner (jturner@minnow-lang.org)
// and Jason Turner (lefticus@gmail.com) // and Jason Turner (lefticus@gmail.com)
// http://www.chaiscript.com // http://www.chaiscript.com
@@ -22,14 +22,30 @@ void log(const std::string &module, const std::string &msg)
std::cout << "[" << boost::posix_time::microsec_clock::local_time() << "] <" << module << "> " << msg << std::endl; std::cout << "[" << boost::posix_time::microsec_clock::local_time() << "] <" << module << "> " << msg << std::endl;
} }
void bound_log(const std::string &msg)
{
log(msg);
}
void hello_world(const chaiscript::Boxed_Value &o)
{
std::cout << "Hello World" << std::endl;
}
void hello_constructor(const chaiscript::Boxed_Value &o)
{
std::cout << "Hello Constructor" << std::endl;
}
struct System struct System
{ {
std::map<std::string, boost::function<std::string (const std::string &) > > m_callbacks; std::map<std::string, boost::function<std::string (const std::string &) > > m_callbacks;
void add_callback(const std::string &t_name, void add_callback(const std::string &t_name,
boost::shared_ptr<dispatchkit::Proxy_Function> t_func) const chaiscript::Proxy_Function &t_func)
{ {
m_callbacks[t_name] = dispatchkit::build_function_caller<std::string (const std::string &)>(t_func); m_callbacks[t_name] = chaiscript::functor<std::string (const std::string &)>(t_func);
} }
@@ -45,48 +61,115 @@ struct System
} }
}; };
void take_shared_ptr(const boost::shared_ptr<const std::string> &p)
{
std::cout << *p << std::endl;
}
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
using namespace chaiscript;
ChaiScript chai;
chaiscript::ChaiScript_Engine chai;
//Create a new system object and share it with the chaiscript engine //Create a new system object and share it with the chaiscript engine
System system; System system;
chai.get_eval_engine().add_object("system", boost::ref(system)); chai.add(var(&system), "system");
//Add a bound callback method
chai.add(fun(&System::add_callback, system), "add_callback_bound");
//Register the two methods of the System structure. //Register the two methods of the System structure.
dispatchkit::register_function(chai.get_eval_engine(), &System::add_callback, "add_callback"); chai.add(fun(&System::add_callback), "add_callback");
dispatchkit::register_function(chai.get_eval_engine(), &System::do_callbacks, "do_callbacks"); chai.add(fun(&System::do_callbacks), "do_callbacks");
chai.add(fun(&take_shared_ptr), "take_shared_ptr");
// Let's use chaiscript to add a new lambda callback to our system. // Let's use chaiscript to add a new lambda callback to our system.
// The function "{ 'Callback1' + x }" is created in chaiscript and passed into our C++ application // The function "{ 'Callback1' + x }" is created in chaiscript and passed into our C++ application
// in the "add_callback" function of struct System the chaiscript function is converted into a // in the "add_callback" function of struct System the chaiscript function is converted into a
// boost::function, so it can be handled and called easily and type-safely // boost::function, so it can be handled and called easily and type-safely
chai.evaluate_string("system.add_callback('#1', fun(x) { 'Callback1 ' + x });"); chai.eval("system.add_callback(\"#1\", fun(x) { \"Callback1 \" + x });");
// Because we are sharing the "system" object with the chaiscript engine we have equal // Because we are sharing the "system" object with the chaiscript engine we have equal
// access to it both from within chaiscript and from C++ code // access to it both from within chaiscript and from C++ code
system.do_callbacks("TestString"); system.do_callbacks("TestString");
chai.evaluate_string("system.do_callbacks(\"TestString\");"); chai.eval("system.do_callbacks(\"TestString\");");
// The log function is overloaded, therefore we have to give the C++ compiler a hint as to which // The log function is overloaded, therefore we have to give the C++ compiler a hint as to which
// version we want to register. One way to do this is to create a typedef of the function pointer // version we want to register. One way to do this is to create a typedef of the function pointer
// then cast your function to that typedef. // then cast your function to that typedef.
typedef void (*PlainLog)(const std::string &); typedef void (*PlainLog)(const std::string &);
typedef void (*ModuleLog)(const std::string &, const std::string &); typedef void (*ModuleLog)(const std::string &, const std::string &);
dispatchkit::register_function(chai.get_eval_engine(), PlainLog(&log), "log"); chai.add(fun(PlainLog(&log)), "log");
dispatchkit::register_function(chai.get_eval_engine(), ModuleLog(&log), "log"); chai.add(fun(ModuleLog(&log)), "log");
chai.evaluate_string("log('Test Message')"); chai.eval("log(\"Test Message\")");
chai.evaluate_string("log('Test Module', 'Test Message');");
// A shortcut to using eval is just to use the chai operator()
chai("log(\"Test Module\", \"Test Message\");");
//Finally, it is possible to register any boost::function as a system function, in this //Finally, it is possible to register any boost::function as a system function, in this
//way, we can, for instance add a bound member function to the system //way, we can, for instance add a bound member function to the system
chai.get_eval_engine().register_function(boost::function<void ()>(boost::bind(&System::do_callbacks, boost::ref(system), "Bound Test")), "do_callbacks"); chai.add(fun(&System::do_callbacks, boost::ref(system), std::string("Bound Test")), "do_callbacks");
//Call bound version of do_callbacks //Call bound version of do_callbacks
chai.evaluate_string("do_callbacks()"); chai("do_callbacks()");
boost::function<void ()> caller = chai.functor<void ()>("fun() { system.do_callbacks(\"From Functor\"); }");
caller();
//If we would like a type-safe return value from all call, we can use
//the templated version of eval:
int i = chai.eval<int>("5+5");
std::cout << "5+5: " << i << std::endl;
//Add a new variable
chai("var scripti = 15");
//We can even get a handle to the variables in the system
int &scripti = chai.eval<int &>("scripti");
std::cout << "scripti: " << scripti << std::endl;
scripti *= 2;
std::cout << "scripti (updated): " << scripti << std::endl;
chai("print(\"Scripti from chai: \" + to_string(scripti))");
//To do: Add examples of handling Boxed_Values directly when needed
//Creating a functor on the stack and using it immediatly
int x = chai.functor<int (int, int)>("fun (x, y) { return x + y; }")(5, 6);
log("Functor test output", boost::lexical_cast<std::string>(x));
chai.add(var(boost::shared_ptr<int>()), "nullvar");
chai("print(\"This should be true.\"); print(nullvar.is_var_null())");
// test the global const action
chai.add_global_const(const_var(1), "constvar");
chai("def getvar() { return constvar; }");
chai("print( getvar() )");
//Ability to create our own container types when needed. std::vector and std::map are
//mostly supported currently
chai.add(bootstrap::vector_type<std::vector<int> >("IntVector"));
// Test ability to register a function that excepts a shared_ptr version of a type
chai("take_shared_ptr(\"Hello World as a shared_ptr\");");
chai.add(fun(&bound_log, std::string("Msg")), "BoundFun");
//Dynamic objects test
chai.add(chaiscript::Proxy_Function(new Dynamic_Object_Function("TestType", fun(&hello_world))), "hello_world");
chai.add(chaiscript::Proxy_Function(new Dynamic_Object_Constructor("TestType", fun(&hello_constructor))), "TestType");
chai.add(fun(boost::function<Boxed_Value (Dynamic_Object &)>(boost::bind(&Dynamic_Object_Attribute::func, "TestType", "attr", _1))), "attr");
chai.eval("var x = TestType()");
// chai.eval("x.attr = \"hi\"");
// chai.eval("print(x.attr)");
chai.eval("x.hello_world()");
} }

View File

@@ -1,30 +1,94 @@
// 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, Jonathan Turner (jturner@minnow-lang.org) // Copyright 2009-2010, Jonathan Turner (jturner@minnow-lang.org)
// and Jason Turner (lefticus@gmail.com) // and Jason Turner (lefticus@gmail.com)
// http://www.chaiscript.com // http://www.chaiscript.com
#include <iostream> #include <iostream>
#include <list>
#define _CRT_SECURE_NO_WARNINGS
#ifdef READLINE_AVAILABLE
#include <readline/readline.h>
#include <readline/history.h>
#endif
#include <chaiscript/chaiscript.hpp> #include <chaiscript/chaiscript.hpp>
void print_help() { void print_help() {
std::cout << "ChaiScript evaluator. To evaluate and expression, type it and press <enter>." << std::endl; std::cout << "ChaiScript evaluator. To evaluate an expression, type it and press <enter>." << std::endl;
std::cout << "Additionally, you can inspect the runtime system using:" << std::endl; std::cout << "Additionally, you can inspect the runtime system using:" << std::endl;
std::cout << " dump_system() - outputs all functions registered to the system" << std::endl; std::cout << " dump_system() - outputs all functions registered to the system" << std::endl;
std::cout << " dump_object(x) - dumps information about the given symbol" << std::endl; std::cout << " dump_object(x) - dumps information about the given symbol" << std::endl;
} }
bool throws_exception(const chaiscript::Proxy_Function &f)
{
try {
chaiscript::functor<void ()>(f)();
} catch (...) {
return true;
}
return false;
}
std::string get_next_command() {
#ifdef READLINE_AVAILABLE
char *input_raw;
input_raw = readline("eval> ");
add_history(input_raw);
return std::string(input_raw);
#else
std::string retval;
std::cout << "eval> ";
std::getline(std::cin, retval);
return retval;
#endif
}
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
std::string input; std::string input;
chaiscript::ChaiScript_Engine chai;
std::vector<std::string> usepaths;
std::vector<std::string> modulepaths;
const char *usepath = getenv("CHAI_USE_PATH");
const char *modulepath = getenv("CHAI_MODULE_PATH");
usepaths.push_back("");
if (usepath)
{
usepaths.push_back(usepath);
}
modulepaths.push_back("");
if (modulepath)
{
modulepaths.push_back(modulepath);
}
chaiscript::ChaiScript chai(modulepaths,usepaths);
chai.add(chaiscript::fun(&exit), "exit");
chai.add(chaiscript::fun(&throws_exception), "throws_exception");
if (argc < 2) { if (argc < 2) {
std::cout << "eval> "; #ifdef READLINE_AVAILABLE
std::getline(std::cin, input); using_history();
#endif
input = get_next_command();
while (input != "quit") { while (input != "quit") {
dispatchkit::Boxed_Value val; chaiscript::Boxed_Value val;
if (input == "help") { if (input == "help") {
print_help(); print_help();
@@ -32,59 +96,38 @@ int main(int argc, char *argv[]) {
else { else {
try { try {
//First, we evaluate it //First, we evaluate it
val = chai.evaluate_string(input); val = chai.eval(input);
//Then, we try to print the result of the evaluation to the user //Then, we try to print the result of the evaluation to the user
if (val.get_type_info().m_bare_type_info && *(val.get_type_info().m_bare_type_info) != typeid(void)) { if (!val.get_type_info().bare_equal(chaiscript::user_type<void>())) {
try { try {
dispatchkit::dispatch(chai.get_eval_engine().get_function("print"), dispatchkit::Param_List_Builder() << val); chaiscript::dispatch(chai.get_eval_engine().get_function("print"), chaiscript::Param_List_Builder() << val);
} }
catch (...) { catch (...) {
//If we can't, do nothing //If we can't, do nothing
} }
} }
} }
catch (chaiscript::Parse_Error &pe) {
std::cout << pe.reason << " in " << pe.filename << " at " << pe.position.line << ", " << pe.position.column << std::endl;
}
catch (chaiscript::Eval_Error &ee) {
std::cout << ee.reason << std::endl;
}
catch (std::exception &e) { catch (std::exception &e) {
std::cout << e.what() << std::endl; std::cout << e.what() << std::endl;
} }
} }
std::cout << "eval> "; input = get_next_command();
std::getline(std::cin, input);
} }
} }
else { else {
for (int i = 1; i < argc; ++i) { for (int i = 1; i < argc; ++i) {
std::string filename(argv[i]);
try { try {
dispatchkit::Boxed_Value val = chai.evaluate_file(argv[i]); chaiscript::Boxed_Value val = chai.eval_file(argv[i]);
}
catch (chaiscript::Parse_Error &pe) {
if (filename != std::string("__EVAL__")) {
std::cout << pe.reason << " in " << pe.filename << " at " << pe.position.line << ", " << pe.position.column << std::endl;
}
else {
std::cout << pe.reason << std::endl;
}
}
catch (chaiscript::Eval_Error &ee) {
if (filename != std::string("__EVAL__")) {
std::cout << ee.reason << " in '" << ee.location->filename << "' at " << ee.location->start.line << ", " << ee.location->start.column << std::endl;
}
else {
std::cout << ee.reason << std::endl;
}
} }
catch (std::exception &e) { catch (std::exception &e) {
std::cout << e.what() << std::endl; std::cout << e.what() << std::endl;
return EXIT_FAILURE;
} }
} }
} }
return EXIT_SUCCESS;
} }

83
src/memory_leak_test.cpp Normal file
View File

@@ -0,0 +1,83 @@
#include <iostream>
#include "chaiscript/chaiscript.hpp"
using namespace chaiscript;
std::string get_next_command() {
#ifdef READLINE_AVAILABLE
char *input_raw;
input_raw = readline("eval> ");
add_history(input_raw);
return std::string(input_raw);
#else
std::string retval;
std::cout << "eval> ";
std::getline(std::cin, retval);
return retval;
#endif
}
void fuction(void)
{
// do nothing
}
class test
{
ChaiScript chai;
ChaiScript::State backupState;
public:
test()
{
backupState = chai.get_state();
}
~test(){}
void ResetState()
{
chai.set_state(backupState);
chai.add(fun(&fuction),"Whatever()");
}
void RunFile(std::string sFile)
{
chaiscript::Boxed_Value val;
try {
chaiscript::Boxed_Value val = chai.eval_file(sFile);
}
catch (std::exception &e) {
std::cout << e.what() << std::endl;
}
}
};
int main(int argc, char *argv[]) {
test myChai;
std::string command = "";
//
// this loop increases memoryusage, if RunFile is not called (just hittin enter)
// as soon RunFile gets called, memory will be freed.
//
// scenario1 - RunFile gets called every Loop: memoryusage does not change
// scenario2 - RunFile gets never called (just hitting enter): memoryusage increases every loop
// scenario3 - RunFile gets in changing intervals: memoryusage goes up and down, but never as
// low as in case 1 scenario3 :
while(command != "quit")
{
for(int i = 1; i < 200; i++)
myChai.ResetState();
if(command == "runfile")
myChai.RunFile("Test.chai");
command = get_next_command();
}
}

38
src/multithreaded.cpp Normal file
View File

@@ -0,0 +1,38 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2010, Jonathan Turner (jturner@minnow-lang.org)
// and Jason Turner (lefticus@gmail.com)
// 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);");
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();
}
}

9
src/stl_extra.cpp Normal file
View File

@@ -0,0 +1,9 @@
#include <chaiscript/chaiscript.hpp>
#include <string>
CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_stl_extra()
{
return chaiscript::bootstrap::list_type<std::list<chaiscript::Boxed_Value> >("List");
}

16
src/test_module.cpp Normal file
View File

@@ -0,0 +1,16 @@
#include <chaiscript/chaiscript.hpp>
#include <string>
std::string hello_world()
{
return "Hello World";
}
CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_test_module()
{
chaiscript::ModulePtr m(new chaiscript::Module());
m->add(chaiscript::fun(hello_world), "hello_world");
return m;
}

10
src/work.chai Normal file
View File

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

View File

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

View File

@@ -1 +0,0 @@
60

View File

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

View File

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

View File

@@ -1 +0,0 @@
false

View File

@@ -4,4 +4,4 @@ while (i < 10) {
break break
} }
} }
print(i) assert_equal(5, i);

View File

@@ -1 +0,0 @@
5

View File

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

View File

@@ -1 +0,0 @@
b

View File

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

View File

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

View File

@@ -1 +0,0 @@
[1, 2]

View File

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

View File

@@ -1 +0,0 @@
false

View File

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

View File

@@ -1 +0,0 @@
true

View File

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

View File

@@ -1 +0,0 @@
[1, 2, 3, 4]

View File

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

View File

@@ -1 +0,0 @@
3.5bob

View File

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

View File

@@ -1 +0,0 @@
3bob

View File

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

View File

@@ -1 +0,0 @@
6.7999999999999998

View File

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

View File

@@ -1 +0,0 @@
8

View File

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

View File

@@ -1 +0,0 @@
[3, 4]

View File

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

View File

@@ -1 +0,0 @@
[2, 3]

View File

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

View File

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

View File

@@ -1 +0,0 @@
7

View File

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

View File

@@ -1 +0,0 @@
true

9
unittests/exception.chai Normal file
View File

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

View File

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

View File

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

View File

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

View File

@@ -1 +0,0 @@
[1, 3]

7
unittests/float.chai Normal file
View File

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

View File

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

View File

@@ -1 +0,0 @@
10

View File

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

View File

@@ -1,5 +0,0 @@
0
1
2
3
4

View File

@@ -1,3 +0,0 @@
1
2
3

View File

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

View File

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

View File

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

View File

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

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