Compare commits

..

175 Commits

Author SHA1 Message Date
Jason Turner
7478d57264 Merge remote-tracking branch 'origin/master' into develop 2014-12-21 13:15:12 -07:00
Jason Turner
bab3701c2f Update release notes 2014-12-21 13:14:47 -07:00
Jason Turner
e225654289 Tick version up to 5.5.1 2014-12-21 13:12:56 -07:00
Jason Turner
019ea57cb6 Merge pull request #151 from ChaiScript/performance_test
Performance test
2014-12-17 09:46:28 -07:00
Jason Turner
60fe242fb6 Skip packaging of MSVC 14 builds 2014-12-12 06:52:47 -07:00
Jason Turner
6c10f18e4c Merge pull request #149 from gitter-badger/gitter-badge
Add a Gitter chat badge to readme.md
2014-12-11 08:50:51 -07:00
The Gitter Badger
d5a221a468 Added Gitter badge 2014-12-11 15:47:26 +00:00
Jason Turner
6ec3afc687 Only package 4.8 gcc on linux 2014-12-02 14:33:56 -07:00
Jason Turner
049cd12127 Add "skip_packaging" to macos debug build 2014-12-02 11:23:29 -07:00
Jason Turner
8b34066dd5 Put to use new skip_packaging and build_tag features 2014-12-01 21:22:45 -07:00
Jason Turner
9fb74762ad Remove extraneous std::cout messages 2014-11-23 20:14:12 -07:00
Jason Turner
7b7e7176f5 Merge remote-tracking branch 'origin/develop' into performance_test 2014-11-17 14:17:28 -07:00
Jason Turner
81146d6b0f Clean up compiler warnings 2014-11-17 14:17:07 -07:00
Jason Turner
423e872720 Work around bug in gcc 4.6 for initializer_list
Hopefully also fixes MSVC 2012
2014-11-17 07:02:52 -07:00
Jason Turner
1e8c0ab93e Reduce redundant parsing / error code 2014-11-16 21:22:55 -07:00
Jason Turner
c90fe16858 Clean up Prefix() implementation
Reducing redundant code
2014-11-16 21:02:28 -07:00
Jason Turner
161652b5d9 Reworking of binary operators
- Eliminates re-parsing of operator strings
- Reduces much redundant code

Results

1. smaller binaries
2. less runtime memory usage
4. faster runtime
2014-11-16 20:28:44 -07:00
Jason Turner
cc5bf45b3b Merge branch 'develop' into performance_test 2014-11-14 21:37:07 -07:00
Jason Turner
28124e4b33 Fix stack memory management
From 747M to 6.2M for profiling tests.
2014-11-14 20:28:53 -07:00
Jason Turner
db207b345b Merge branch 'add_object_lifetime_test' into develop 2014-11-14 14:57:27 -07:00
Jason Turner
684d724103 Add object lifetime test that failed in v5.4.0 2014-11-14 14:54:57 -07:00
Jason Turner
283152a880 Speed up print functions 2014-11-14 09:45:49 -07:00
Jason Turner
dc3ef087e2 Merge branch 'performance_evaluations' into performance_test 2014-11-14 08:00:08 -07:00
Jason Turner
032ba63b8a Add fun_call_performance samples 2014-11-14 07:41:43 -07:00
Jason Turner
cf49b1b30c Make def more efficient, fix to_string(string) 2014-11-13 12:28:52 -07:00
Jason Turner
63a083b47b Remove uses of std::endl, which imply a flush 2014-11-13 10:13:51 -07:00
Jason Turner
4a3315cfd1 Merge pull request #144 from ChaiScript/develop
Merge release 5.5.0 to master
2014-11-10 12:48:25 -07:00
Jason Turner
8a30581eaf Update release notes for version 5.5.0 2014-11-10 12:45:49 -07:00
Jason Turner
a51281a5be Merge branch 'develop' of http://github.com/ChaiScript/ChaiScript into develop 2014-11-06 15:13:51 -07:00
Jason Turner
e0919f7228 Merge branch 'develop' of https://github.com/ChaiScript/ChaiScript into develop 2014-11-06 15:13:30 -07:00
Jason Turner
fa5966bd04 Enable optimizations options for LTO and profile 2014-11-06 15:12:53 -07:00
Jason Turner
f4f2391801 Add support for clang/gcc MemorySanitizer 2014-11-04 15:22:09 -07:00
Jason Turner
5daf837037 Increment version number to 5.5.0 2014-11-04 09:47:32 -07:00
Jason Turner
99396ba05c Add \r skipping code from @jespada 2014-11-03 21:37:25 -07:00
Jason Turner
f5304ac75c Merge branch 'develop' of http://github.com/ChaiScript/ChaiScript into develop 2014-11-03 18:36:10 -07:00
Jason Turner
3f460fdd20 Fix 64bit msvc warning 2014-11-03 18:34:33 -07:00
Jason Turner
4f972bcf67 Refine lifetime of parameters to functions
Fixes crash caused when making function calls in a global context, and
probably fixes other things.
2014-11-03 09:13:30 -07:00
Jason Turner
5d5e881971 Fix arity of functions
A value was being accessed after it was moved.
2014-11-03 08:24:02 -07:00
Jason Turner
5515d058bb Fix some warnings for clang / 64bit windows 2014-11-03 07:33:53 -07:00
Jason Turner
79c5f71975 Fix compilation on gcc 4.6 2014-11-02 21:47:42 -07:00
Jason Turner
c876a89030 Fix crash during user_defined_conversions_2
Temporaries created during user conversion operations were being dropped
before the result of the conversion was able to be used. This fixes that
by temporarily storing the result of the conversion inside the
current Function_Push_Pop context.
2014-11-02 21:37:01 -07:00
Jason Turner
20c0e6016e Add type_conversion helper and failing unit test 2014-11-02 14:08:57 -07:00
Jason Turner
dd12785b72 Reduce virtual calls for get_arity
Saves compiled code size and some minor runtime differences
2014-11-01 18:40:42 -06:00
Jason Turner
87cee688a8 Fix broken type conversion call implementation
- We need to properly order the function so that the one with the least
   number if type differences is the one that is tried first.
2014-11-01 15:52:02 -06:00
Jason Turner
e2cf8a48be Correct check for which types might have conversions 2014-10-29 07:07:12 -06:00
Jason Turner
7c766f87a4 Add thread specific cache of type info
Reduces the number of locks necessary to check of a user defined type
conversion should be scanned for / applied.
2014-10-28 22:12:03 -06:00
Jason Turner
e85be6eb3d Add C++ test for user defined conversion 2014-10-28 20:23:19 -06:00
Jason Turner
7b42d5307a Add ability to register a user defined type conversion
Currently this adds a fair bit of overhead. It will need to be evaluated
further before it's merged.
2014-10-28 14:52:24 -06:00
Jason Turner
43d6f0cf16 Rename dynamic_cast into type_conversion
Prep work for getting user defined type conversions implemented
2014-10-28 12:43:30 -06:00
Jason Turner
86e26966c1 More code cleanups 2014-10-28 10:53:29 -06:00
Jason Turner
9e8b833d11 Code cleanups 2014-10-18 16:18:56 -06:00
Jason Turner
48c97bce9c Add faux-inheritance example 2014-10-12 22:13:40 -07:00
Jason Turner
021e2a7949 Fix returning of boolean values from functors 2014-10-12 22:12:54 -07:00
Jason Turner
78cd980067 Work around broken Apple clang implementation
This line of code does not cause an error on clang-3.4 or clang-3.5
on Linux. Apple's clang is somewhere between the two, no way to know
where.

For an unknown reason, specifying default move operations in 'Data'
causes the compiler to think that Boxed_Value is an incomplete type.

This is highly illogical since Data is only used via a shared_ptr, so
the size / type of Boxed_Value should be fully known (and is known on
every other compiler/platform combination).
2014-10-01 15:49:11 -06:00
Jason Turner
58d9e69479 Work around missing move operations in MSVC12 2014-10-05 21:53:44 -06:00
Jason Turner
935e9de19e GCC 4.6 fixes to cleanups 2014-10-05 14:58:27 -06:00
Jason Turner
f547b4bb10 Enable moving of data into Boxed_Values when possible 2014-10-05 12:11:46 -06:00
Jason Turner
87e40237d3 Enable moving of Any objects 2014-10-05 11:47:50 -06:00
Jason Turner
5619f2602d Eliminate extra dynamic allocation in the Stack 2014-10-05 08:58:29 -06:00
Jason Turner
5986531bba dispatchkit modernization 2014-10-04 22:59:52 -06:00
Jason Turner
8ecc11c275 First pass of modernization of chaiscript_eval.hpp done 2014-10-04 18:31:08 -06:00
Jason Turner
81dc4949d2 1/4 through modernization of chaiscript_eval.hpp 2014-10-04 15:34:32 -06:00
Jason Turner
9a7d03df05 Modernization of chaiscript_parser 2014-10-04 09:37:33 -06:00
Jason Turner
4f5a6da280 Move constructor and noexcept correctness 2014-09-21 14:19:41 -06:00
Jason Turner
e4b9be6e09 Merge remote-tracking branch 'origin/develop' into code_cleanups
Conflicts:
	.decent_ci-Linux.yaml
2014-09-20 14:27:37 -06:00
Jason Turner
0a7e7b3a0d Merge pull request #137 from ChaiScript/enable_decent_ci
Enable decent ci
2014-09-20 14:24:24 -06:00
Jason Turner
e1b80abac4 Update documenation to-dos regarding gcc 4.6 2014-09-20 14:20:37 -06:00
Jason Turner
b6e8605aee Attempt again to satisfy gcc 4.6 2014-09-20 14:17:41 -06:00
Jason Turner
0e381e333e Attempt to satisfy G++4.6 and decltype usage 2014-09-20 08:31:18 -06:00
Jason Turner
8c31255012 Windows and GCC 4.6 error cleanups 2014-09-20 07:21:30 -06:00
Jason Turner
01cf906e18 Clean up 32bit windows warnings 2014-09-19 21:58:28 -06:00
Jason Turner
e55700b86b Remove static in bind_first - VS12 warns on it 2014-09-19 21:52:18 -06:00
Jason Turner
81184cbbd7 Rollback template alias, not supported in gcc 4.6 2014-09-19 21:46:52 -06:00
Jason Turner
c00c38bc22 Fix spelling of "USE_LIBCXX" flag 2014-09-19 10:34:51 -06:00
Jason Turner
ae1897e2ea Update to force CI rebuild 2014-09-19 10:25:04 -06:00
Jason Turner
93c1cfde99 Try out some alias templates for cleanup 2014-09-18 20:48:34 -06:00
Jason Turner
2321f1d709 Enable clang linux builds 2014-09-18 20:07:15 -06:00
Jason Turner
cfd4a73a89 Add VS 2014 CI Support 2014-09-16 13:30:47 -06:00
Jason Turner
04782b6a33 Add gcc-4.6 to test configuration 2014-09-16 08:02:12 -06:00
Jason Turner
5861c45fc1 C++11 related cleanup and improvments 2014-09-15 21:16:44 -06:00
Jason Turner
d62a452a9d Correct -I path for cppcheck run 2014-09-15 07:12:19 -06:00
Jason Turner
3ccb155358 Fix up usage of cppcheck, enable samples build 2014-09-14 21:57:07 -06:00
Jason Turner
6c2ccf3869 Various cleanups prefering lambda to bind 2014-09-14 21:53:11 -06:00
Jason Turner
f02a9fa885 Merge remote-tracking branch 'origin/enable_decent_ci' into code_cleanups 2014-09-14 20:10:52 -06:00
Jason Turner
0036ebfe5d Update .decent_ci-Windows.yaml 2014-09-14 12:44:20 -06:00
Jason Turner
7b28f9ef57 Fix results location 2014-09-13 23:11:17 -06:00
Jason Turner
bd8a78eccc Initial decent_ci files 2014-09-13 21:53:12 -06:00
Jason Turner
9436533ddb Merge commit '243f400' into develop
Conflicts:
	include/chaiscript/dispatchkit/bind_first.hpp
2014-09-12 15:18:38 -06:00
Jason Turner
243f4001d1 Code cleanups 2014-09-12 15:16:24 -06:00
Jason Turner
3bd2a9c00d Clean up bind_first implementation 2014-09-10 07:40:16 -06:00
Jason Turner
fde90ad980 Throw exception if user attempts to use null Boxed_Value 2014-09-09 13:43:05 -06:00
Jason Turner
308eb34d05 Correct test_module changes 2014-09-08 21:15:02 -06:00
Jason Turner
4a70ffe599 Add failing unit test for accessing member of null object 2014-09-08 18:23:53 -06:00
Jason Turner
52179d8333 Merge branch 'develop' of https://github.com/ChaiScript/ChaiScript into develop 2014-09-08 11:11:35 -06:00
Jason Turner
eed90b521d Spelling corrections and comment fixes 2014-09-08 11:10:53 -06:00
Jason Turner
166f3501c3 Ignore missing system include files 2014-09-05 08:41:58 -06:00
Jason Turner
29b1fca76c Use g++-4.8 for cppcheck building 2014-09-05 08:09:22 -06:00
Jason Turner
8d36b66c89 Fix call to cppcheck 2014-09-05 07:45:36 -06:00
Jason Turner
f78fb77128 Merge pull request #135 from ChaiScript/develop
Develop
2014-08-31 20:03:18 -06:00
Jason Turner
bb08cc3699 Add documenation for "class" keyword 2014-08-31 19:54:43 -06:00
Jason Turner
6692607507 Update version number to 5.4.0, update releasenotes 2014-08-31 19:45:07 -06:00
Jason Turner
6bea42c1c0 Speed up to_string performance by relying on C++ versions
Addresses #134, fixing issues introduced by #132
2014-08-31 16:03:42 -06:00
Jason Turner
251790f144 Fix some MSVC warnings 2014-08-31 12:04:02 -06:00
Jason Turner
4ee9ba9c96 Make up some of the performance losses #132 2014-08-30 14:49:31 -06:00
Jason Turner
a71903f185 Add strong reference to range objects #132 2014-08-30 13:36:36 -06:00
Jason Turner
3fe80d70c6 Roll back name of range class, it's half baked from the range fix 2014-08-27 12:24:46 -06:00
Jason Turner
9c05779fac Add failing range test
Crash occurs if the user attempts to use a range and the source
of the range has gone out of scope. #132
2014-08-27 12:15:47 -06:00
Jason Turner
a6e3fd5b42 Make reflection API part of stdlib
removes the reflection module completely. Reflection and the
ability to catch eval errors is too useful.
2014-08-27 12:05:03 -06:00
Jason Turner
6a3f19d575 Add copy constructor for Type_Info 2014-08-26 09:28:51 -06:00
Jason Turner
9b7e4d2e78 Let a subscript out of range be catchable from chaiscript 2014-08-26 08:51:02 -06:00
Jason Turner
f546e46582 Update to cppcheck 1.66 2014-08-22 21:29:14 -06:00
Jason Turner
fa1f4b795b Add class keyword for easier user defined types.
Issue #118
2014-08-22 21:11:49 -06:00
Jason Turner
cb1c7730cf Add the ability to look up user defined typenames
Closes #124
2014-08-17 09:05:29 -06:00
Jason Turner
3a775097dd Reduce size of Any template wrapper. 2014-08-17 06:52:11 -06:00
Jason Turner
5692dfc58a Move to unique_ptr for Any implemenation
Speed and size improvements
2014-08-15 20:38:35 -06:00
Jason Turner
c5f6c549ec Reduce compiled size with template reductions 2014-08-15 20:14:15 -06:00
Jason Turner
14a280713f Update version to 5.3.2 2014-06-11 15:15:51 -06:00
Jason Turner
e7b6ee6cf9 Update release notes for 5.3.1 2014-06-11 15:11:21 -06:00
Jason Turner
32a9aa9c3c Merge branch 'develop' of https://github.com/ChaiScript/ChaiScript into develop 2014-05-29 20:44:35 -06:00
Jason Turner
f57a14e3de Allow user to add globals from within script. 2014-05-29 20:44:05 -06:00
Jason Turner
4018c873dc Spelling fixes, phase 1. 2014-05-29 20:16:47 -06:00
Jason Turner
b4ea27d28a Add unsupported build support for Haiku 2014-05-27 06:51:38 +00:00
Jason Turner
e5d723621f Merge branch 'develop' of https://github.com/ChaiScript/ChaiScript into develop 2014-05-23 09:57:29 -06:00
Jason Turner
46e7d0ab99 Clean up tab vs space issues
discovered by @axelstudios
2014-05-23 09:56:55 -06:00
Jason Turner
d5378f50af Fix cygwin builds #121
Cygwin claims to be POSIX but only implementes part of
the dl_open interface.

For this usage, we revert to win32 interface when building on
Cygwin.
2014-05-13 14:55:27 -06:00
Jason Turner
be9632d0ad Balance signed/unsigned issues between msvc and gcc 2014-05-11 12:30:21 -06:00
Jason Turner
61cd633084 Merge branch 'develop' of https://github.com/ChaiScript/ChaiScript into develop
Conflicts:
	include/chaiscript/language/chaiscript_common.hpp
	include/chaiscript/language/chaiscript_parser.hpp
2014-05-11 12:02:33 -06:00
Jason Turner
c35b35e4f8 Fix issues discovered while evaluating pvs-studio 2014-05-11 11:53:03 -06:00
Jason Turner
bcb7172037 Enable MSVC warning for thread safety with statics
Clean up a couple of additional issues found while playing with /Wall in MSVC.
2014-05-11 10:52:07 -06:00
Jason Turner
3c552db548 Upgrade cppcheck and disable inconclusive checks 2014-05-10 20:14:40 -06:00
Jason Turner
37982cbdaa Fix issues found by cppcheck 1.65 2014-05-10 20:12:49 -06:00
Jason Turner
28a016b51d Fix potential memory issue discovered by clang's analyzer 2014-05-10 19:20:03 -06:00
Jason Turner
c0bf6ee99d Apply corrections from the "include what you use" tool
Generally cleanups of the includes. Making sure each file
can properly stand on its own and forward declares when possible.
2014-05-10 18:41:11 -06:00
Jason Turner
f29af4618a Make override a #define for gcc 4.6 support 2014-05-10 09:04:41 -06:00
Jason Turner
ee17a184c2 Merge branch 'develop' of https://github.com/ChaiScript/ChaiScript into develop 2014-05-10 08:39:59 -06:00
Jason Turner
6eab8ddfe1 Apply changes applied from clang-modernize
Needed 1-2 cleanups by hand. 99% was automatic.

* The version that ships with ubuntu 14.04 seems to not work.
  I had to build from scratch

* Use cmake to generate the build commands that clang-modernize wants

```sh
cmake -DCMAKE_EXPORT_COMPILE_COMMANDS:bool=true ../ChaiScript/
```

* Use the clang-modernize tool. Note that you have to be pretty explicit
  about the include paths if you want it to also update your include
  files

```sh
../llvm-build/bin/clang-modernize ../ChaiScript/src/*.cpp -for-compilers=gcc-4.8 -include /home/jason/ChaiScript/include,/hjason/ChaiScript/include/chaiscript,/home/jason/ChaiScript/include/chaiscript/dispatchkit,/home/jason/ChaiScript/include/chaiscript/language -p compile_commands.json
```

* In my case, it left some unused `typedef`s behind, which I cleaned up.
2014-05-10 08:25:38 -06:00
Jason Turner
a7e8c6fe1f Merge pull request #120 from axelstudios/develop
Formatted CMakeLists.txt
2014-05-09 20:04:31 -06:00
Jason Turner
5f2796868b Fix threading warning discovered with MSVC -Wall
MSVC in -Wall mode creates approximately 6,500 warnings. 5,000+ of which are
from the std library. The one gem was the potential for threading issues with
the initilization of a function scoped static.

This fixes that.
2014-05-09 17:46:06 -06:00
Jason Turner
c2d08457ad Fix thread-unsafe builds 2014-05-09 15:55:29 -06:00
Alex Swindler
d3084ed136 Formatted CMakeLists.txt 2014-05-07 15:02:21 -06:00
Jason Turner
62b8977abe Correct linking of modules for coverage testing 2014-05-04 21:52:27 -06:00
Jason Turner
b87c37032b Add version numbers that can be queried at runtime 2014-05-04 10:14:42 -06:00
Jason Turner
7932cb18f3 Clean up linker flags and add sanitizer options
Sanitizers are features now built into gcc and clang to check for
runtime problems such as data races, memory errors or undefined
behavior.
2014-05-04 07:55:36 -06:00
Jason Turner
706b5aaa45 Merge remote-tracking branch 'origin/release-4.x' into develop
Conflicts:
	releasenotes.md
2014-05-04 07:16:27 -06:00
Jason Turner
41bf96c42e Update release notes for release 4.3.1 2014-05-03 17:44:54 -06:00
Jason Turner
67b5d989cb Merge remote-tracking branch 'origin/release-4.x' into develop 2014-04-22 19:52:01 -06:00
Jason Turner
fcc9bd9bbb Start porting of documentatation to markdown style 2014-04-13 19:16:51 -06:00
Jason Turner
825c28521e Update doxyfile to latest template 2014-04-13 19:16:23 -06:00
Jason Turner
5da1475082 Port is_prime.chai to run on pre-cpp11 versions 2014-04-13 19:15:39 -06:00
Jason Turner
c9a244019e Enhance the inheritance unit tests #117 2014-04-13 08:05:46 -06:00
Jason Turner
2bd1910c70 ~30% performance improvement with threading enabled 2014-04-05 22:49:50 -06:00
Jason Turner
4ace508339 Update travis token 2014-04-02 14:13:19 -06:00
Jason Turner
926e962fc0 Merge remote-tracking branch 'origin/release-4.x'
Conflicts:
	.travis.yml
	CMakeLists.txt
	include/chaiscript/dispatchkit/bootstrap.hpp
	include/chaiscript/dispatchkit/boxed_cast.hpp
	include/chaiscript/dispatchkit/dynamic_cast_conversion.hpp
	include/chaiscript/dispatchkit/function_call_detail.hpp
	include/chaiscript/dispatchkit/proxy_functions.hpp
	include/chaiscript/language/chaiscript_common.hpp
2014-03-29 07:30:14 -06:00
Jason Turner
caf4495cff Add unit tests for inheritance with multiple layers 2014-03-29 06:16:21 -06:00
Jason Turner
6b0e0dc7ae Removed erroneously kept debug output 2014-03-28 07:04:51 -06:00
Jason Turner
65b0846e41 Address some of the issues found by cppcheck 2014-03-26 16:59:41 -06:00
Jason Turner
296769ee24 Version number bump, cppcheck fix 2014-03-26 15:20:06 -06:00
Jason Turner
d9bdad714f Fix syntax problem with .travis.yml 2014-03-26 14:45:01 -06:00
Jason Turner
12de955a47 Post cppcheck results to pull request 2014-03-26 13:56:02 -06:00
Jason Turner
a652a7e564 Only post comment if this is a pull request 2014-03-26 13:37:51 -06:00
Jason Turner
611692646f Add travis support for testing with cppcheck 2014-03-26 13:32:25 -06:00
Jason Turner
96acf5e833 Update travis in 4.x branch for coveralls support 2014-03-26 11:37:37 -06:00
Jason Turner
656b438002 First cast up chain, if that fails, cast down 2014-03-26 10:52:56 -06:00
Jason Turner
56b036052f Add test for automatic casting down in inheritance 2014-03-26 09:14:06 -06:00
Jason Turner
7fade8e841 Allow for automatic conversion of arithmetic types
for returns from chaiscript function wrappers
2014-03-26 08:11:37 -06:00
Jason Turner
db8be03cee Add tests for returning of arithmetic types with conversions 2014-03-26 07:26:23 -06:00
Jason Turner
372cf73548 Correct typo in travis logic 2014-03-25 08:24:25 -06:00
Jason Turner
0213039ee7 Install gcc-4.8 in travis matrix and test both 4.6 & 4.8 2014-03-25 08:12:07 -06:00
Jason Turner
e8fcb3f68b Revert back to cpp and use ubuntu for builds with travis 2014-03-24 21:29:11 -06:00
Jason Turner
8d8df1f5bd Attempt objective-c for building on macos travis 2014-03-24 21:17:40 -06:00
Jason Turner
f40f9d8441 Fix call to gcov for older gcov ver / travis 2014-03-24 19:41:41 -06:00
Jason Turner
8879a89490 Utilize 2 cores on travis during build 2014-03-24 18:55:01 -06:00
Jason Turner
e4a3b3f620 Update coveralls execution to merge all data and ignore cpp 2014-03-24 18:51:25 -06:00
Jason Turner
d6c8b36eeb Update readme.md 2014-03-24 14:23:44 -06:00
Jason Turner
de86e79df2 Merge pull request #106 from ChaiScript/ChaiScript_5_0_CPP_11
Chai script 5 0 cpp 11
2014-03-24 14:16:38 -06:00
95 changed files with 6481 additions and 5208 deletions

25
.decent_ci-Linux.yaml Normal file
View File

@@ -0,0 +1,25 @@
compilers:
- name: "clang"
version: "3.5"
skip_packaging: true
cmake_extra_flags: -DUSE_LIBCXX:BOOL=OFF -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON
- name: "clang"
build_tag: AddressSanitizer
version: "3.5"
skip_packaging: true
cmake_extra_flags: -DUSE_LIBCXX:BOOL=OFF -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DENABLE_ADDRESS_SANITIZER:BOOL=ON
- name: "clang"
build_tag: ThreadSanitizer
version: "3.5"
skip_packaging: true
cmake_extra_flags: -DUSE_LIBCXX:BOOL=OFF -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DENABLE_THREAD_SANITIZER:BOOL=ON
- name: "gcc"
version: "4.8"
cmake_extra_flags: -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DBUILD_TESTING:BOOL=ON
- name: "gcc"
version: "4.6"
skip_packaging: true
cmake_extra_flags: -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON
- name: cppcheck
compiler_extra_flags: --enable=all -I include --inline-suppr

8
.decent_ci-MacOS.yaml Normal file
View File

@@ -0,0 +1,8 @@
compilers:
- name: clang
cmake_extra_flags: -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DCOMMIT_SHA=$COMMIT_SHA
- name: clang
build_type: Debug
cmake_extra_flags: -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DCOMMIT_SHA=$COMMIT_SHA
skip_packaging: true

22
.decent_ci-Windows.yaml Normal file
View File

@@ -0,0 +1,22 @@
compilers:
- name: Visual Studio
version: 14
cmake_extra_flags: -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DCOMMIT_SHA=%COMMIT_SHA%
compiler_extra_flags: /ANALYZE
skip_packaging: true
- name: Visual Studio
version: 14
architecture: Win64
cmake_extra_flags: -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DCOMMIT_SHA=%COMMIT_SHA%
compiler_extra_flags: /ANALYZE
skip_packaging: true
- name: Visual Studio
version: 12
cmake_extra_flags: -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DCOMMIT_SHA=%COMMIT_SHA%
compiler_extra_flags: /ANALYZE
- name: Visual Studio
version: 12
architecture: Win64
cmake_extra_flags: -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DCOMMIT_SHA=%COMMIT_SHA%
compiler_extra_flags: /ANALYZE

4
.decent_ci.yaml Normal file
View File

@@ -0,0 +1,4 @@
results_repository : ChaiScript/ChaiScript-BuildResults
results_path : _posts
results_base_url : https://chaiscript.github.io/ChaiScript-BuildResults
aging_pull_requests_notification: true

View File

@@ -1,17 +1,31 @@
language: cpp language: cpp
compiler: compiler:
- gcc - gcc
env:
- GCC_VER=4.6
- GCC_VER=4.8
before_install: before_install:
- sudo pip install cpp-coveralls --use-mirrors - sudo pip install cpp-coveralls
- sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y
- sudo apt-get update
- sudo apt-get install -qq g++-4.8
- if [ "$GCC_VER" = "4.8" ]; then export CXX="g++-4.8" CC="gcc-4.8" GCOV="gcov-4.8"; else export CXX="g++-4.6" CC="gcc-4.6" GCOV="gcov-4.6"; fi
script: script:
- cmake -D ENABLE_COVERAGE:BOOL=TRUE -D CMAKE_BUILD_TYPE:STRING=Debug -D USE_LIBCXX:BOOL=FALSE . - cmake -D ENABLE_COVERAGE:BOOL=TRUE -D CMAKE_BUILD_TYPE:STRING=Debug .
- make - make -j2
- make test - make test
- coveralls -x hpp - mkdir gcov
- find CMakeFiles/ -name "*.gc*" -exec mv {} gcov/ \;
- $GCOV -d -o gcov gcov/*.gcda
- coveralls -n -E ".*\.cpp"
after_script:
- contrib/codeanalysis/runcppcheck.sh
notifications: notifications:
recipients:
- jason@emptycrate.com
email: email:
recipients:
- jason@emptycrate.com
on_success: always on_success: always
on_failure: always on_failure: always
env:
global:
secure: eiaR6pXiiEpyB8+LLQ1NvZdl0Yylru1BLy9lMoHl+IpUNGGQGywmW/2WAn77rFfmR1OPA2qWQLfgPwgK0HxUA9HHlot9tre5QhiN2Lw8NOT8tCZ6tTm2+QntDBjBGJyal/knRvQkn/6qs6GxlXRerz4ArnnuPL1vESt3zwB0YtU=

View File

@@ -3,20 +3,72 @@ cmake_minimum_required(VERSION 2.8)
project(chaiscript) project(chaiscript)
# MINGW does not yet support C++11's concurrency features # MINGW does not yet support C++11's concurrency features
if (MINGW) if(MINGW)
option(MULTITHREAD_SUPPORT_ENABLED "Multithreaded Support Enabled" FALSE) option(MULTITHREAD_SUPPORT_ENABLED "Multithreaded Support Enabled" FALSE)
else() else()
option(MULTITHREAD_SUPPORT_ENABLED "Multithreaded Support Enabled" TRUE) option(MULTITHREAD_SUPPORT_ENABLED "Multithreaded Support Enabled" TRUE)
endif() endif()
if (CMAKE_COMPILER_IS_GNUCC)
option(BUILD_MODULES "Build Extra Modules (stl)" TRUE)
option(BUILD_SAMPLES "Build Samples Folder" FALSE)
if(CMAKE_COMPILER_IS_GNUCC)
option(ENABLE_COVERAGE "Enable Coverage Reporting in GCC" FALSE) option(ENABLE_COVERAGE "Enable Coverage Reporting in GCC" FALSE)
if(ENABLE_COVERAGE)
add_definitions(--coverage -O0)
set(LINKER_FLAGS "${LINKER_FLAGS} --coverage")
endif()
endif() endif()
if(CMAKE_COMPILER_IS_GNUCC OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
option(ENABLE_THREAD_SANITIZER "Enable thread sanitizer testing in gcc/clang" FALSE)
if(ENABLE_THREAD_SANITIZER)
add_definitions(-fsanitize=thread -g)
set(LINKER_FLAGS "${LINKER_FLAGS} -fsanitize=thread")
endif()
option(ENABLE_ADDRESS_SANITIZER "Enable address sanitizer testing in gcc/clang" FALSE)
if(ENABLE_ADDRESS_SANITIZER)
add_definitions(-fsanitize=address -g)
set(LINKER_FLAGS "${LINKER_FLAGS} -fsanitize=address")
endif()
option(ENABLE_MEMORY_SANITIZER "Enable memory sanitizer testing in gcc/clang" FALSE)
if(ENABLE_MEMORY_SANITIZER)
add_definitions(-fsanitize=memory -g)
set(LINKER_FLAGS "${LINKER_FLAGS} -fsanitize=memory")
endif()
option(ENABLE_UNDEFINED_SANITIZER "Enable undefined behavior sanitizer testing in gcc/clang" FALSE)
if(ENABLE_UNDEFINED_SANITIZER)
add_definitions(-fsanitize=undefined -g)
set(LINKER_FLAGS "${LINKER_FLAGS} -fsanitize=undefined")
endif()
option(ENABLE_LTO "Enable Link Time Optimization" FALSE)
if (ENABLE_LTO)
add_definitions(-flto)
set(LINKER_FLAGS "${LINKER_FLAGS} -flto")
endif()
option(PROFILE_GENERATE "Generate profile data" FALSE)
if (PROFILE_GENERATE)
add_definitions(-fprofile-generate)
set(LINKER_FLAGS "${LINKER_FLAGS} -fprofile-generate")
endif()
option(PROFILE_USE "Use profile data" FALSE)
if (PROFILE_USE)
add_definitions(-fprofile-use)
set(LINKER_FLAGS "${LINKER_FLAGS} -fprofile-use")
endif()
option(BUILD_MODULES "Build Extra Modules (stl, reflection)" TRUE) endif()
option(BUILD_SAMPLES "Build Samples Folder" FALSE)
list(APPEND CPACK_SOURCE_IGNORE_FILES "${CMAKE_CURRENT_BINARY_DIR}") list(APPEND CPACK_SOURCE_IGNORE_FILES "${CMAKE_CURRENT_BINARY_DIR}")
list(APPEND CPACK_SOURCE_IGNORE_FILES "\\\\.svn") list(APPEND CPACK_SOURCE_IGNORE_FILES "\\\\.svn")
@@ -29,8 +81,8 @@ set(CPACK_RESOURCE_FILE_README "${CMAKE_CURRENT_SOURCE_DIR}/readme.md")
set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/description.txt") set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/description.txt")
set(CPACK_PACKAGE_VERSION_MAJOR 5) set(CPACK_PACKAGE_VERSION_MAJOR 5)
set(CPACK_PACKAGE_VERSION_MINOR 3) set(CPACK_PACKAGE_VERSION_MINOR 5)
set(CPACK_PACKAGE_VERSION_PATCH 0) set(CPACK_PACKAGE_VERSION_PATCH 1)
set(CPACK_PACKAGE_EXECUTABLES "chai;ChaiScript Eval") set(CPACK_PACKAGE_EXECUTABLES "chai;ChaiScript Eval")
set(CPACK_PACKAGE_VENDOR "ChaiScript.com") set(CPACK_PACKAGE_VENDOR "ChaiScript.com")
@@ -66,40 +118,30 @@ enable_testing()
message(STATUS "Detecting readline support") message(STATUS "Detecting readline support")
if (READLINE_LIBRARY) if(READLINE_LIBRARY)
message(STATUS "Found: ${READLINE_LIBRARY}") message(STATUS "Found: ${READLINE_LIBRARY}")
set (READLINE_LIB readline) set(READLINE_LIB readline)
add_definitions(/DREADLINE_AVAILABLE) add_definitions(/DREADLINE_AVAILABLE)
else(READLINE_LIBRARY) else()
message(STATUS "Not Found") message(STATUS "Not Found")
set (READLINE_LIB ) set(READLINE_LIB)
set (READLINE_FLAG ) set(READLINE_FLAG)
endif(READLINE_LIBRARY) endif()
SET(EXTRA_LINKER_FLAGS "") if(CMAKE_COMPILER_IS_GNUCC)
if (CMAKE_COMPILER_IS_GNUCC)
execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpversion OUTPUT_VARIABLE GCC_VERSION) execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpversion OUTPUT_VARIABLE GCC_VERSION)
if (GCC_VERSION VERSION_LESS 4.8) if(GCC_VERSION VERSION_LESS 4.8)
SET(CPP11_FLAG "-std=c++0x") set(CPP11_FLAG "-std=c++0x")
else() else()
SET(CPP11_FLAG "-std=c++11") set(CPP11_FLAG "-std=c++11")
endif() endif()
if (ENABLE_COVERAGE)
add_definitions(-fprofile-arcs -ftest-coverage)
SET(EXTRA_LINKER_FLAGS ${EXTRA_LINKER_FLAGS} "-fprofile-arcs -ftest-coverage")
# SET(CMAKE_EXE_LINKER_FLAGS_DEBUG "-fprofile-arcs -ftest-coverage")
endif()
else() else()
SET(CPP11_FLAG "-std=c++11") set(CPP11_FLAG "-std=c++11")
endif() endif()
if(MSVC) if(MSVC)
add_definitions(/W4) add_definitions(/W4 /w44640)
add_definitions(/bigobj) add_definitions(/bigobj)
# Note on MSVC compiler flags. # Note on MSVC compiler flags.
# The code base selective disables warnings as necessary when the compiler is complaining too much # The code base selective disables warnings as necessary when the compiler is complaining too much
@@ -108,94 +150,98 @@ if(MSVC)
# The error did not come up until the move to C++11, but the compiler doesn't give enough information # The error did not come up until the move to C++11, but the compiler doesn't give enough information
# to determine where the error is coming from, and the internet provides no real information for # to determine where the error is coming from, and the internet provides no real information for
# how to workaround or fix the error. So I'm disabling it globally. # how to workaround or fix the error. So I'm disabling it globally.
ADD_DEFINITIONS(/wd4503) add_definitions(/wd4503)
else() else()
add_definitions(-Wall -Wextra -Wshadow -Wnon-virtual-dtor -pedantic ${CPP11_FLAG}) add_definitions(-Wall -Wextra -Wshadow -Wnon-virtual-dtor -pedantic ${CPP11_FLAG})
if (APPLE) if(APPLE)
add_definitions(-Wno-sign-compare) add_definitions(-Wno-sign-compare)
endif() endif()
endif() endif()
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
option(USE_LIBCXX "Use clang's libcxx" TRUE) option(USE_LIBCXX "Use clang's libcxx" TRUE)
if (USE_LIBCXX) if(USE_LIBCXX)
add_definitions(-stdlib=libc++) add_definitions(-stdlib=libc++)
set (EXTRA_LINKER_FLAGS ${EXTRA_LINKER_FLAGS} ${CPP11_FLAG} -stdlib=libc++) set(LINKER_FLAGS "${LINKER_FLAGS} ${CPP11_FLAG} -stdlib=libc++")
else () else()
set (EXTRA_LINKER_FLAGS ${EXTRA_LINKER_FLAGS} ${CPP11_FLAG}) set(LINKER_FLAGS "${LINKER_FLAGS} ${CPP11_FLAG}")
endif() endif()
elseif(CMAKE_COMPILER_IS_GNUCC) elseif(CMAKE_COMPILER_IS_GNUCC)
set (EXTRA_LINKER_FLAGS ${EXTRA_LINKER_FLAGS} ${CPP11_FLAG}) set(LINKER_FLAGS "${LINKER_FLAGS} ${CPP11_FLAG}")
endif() endif()
# limitations in MinGW require us to make an optimized build # limitations in MinGW require us to make an optimized build
# for the sake of object sizes or something # for the sake of object sizes or something
if (MINGW) if(MINGW OR CYGWIN)
add_definitions(-O3) add_definitions(-O3)
endif() endif()
include_directories(include) include_directories(include)
set (Chai_INCLUDES include/chaiscript/chaiscript.hpp include/chaiscript/chaiscript_threading.hpp include/chaiscript/dispatchkit/bad_boxed_cast.hpp include/chaiscript/dispatchkit/bind_first.hpp include/chaiscript/dispatchkit/bootstrap.hpp include/chaiscript/dispatchkit/bootstrap_stl.hpp include/chaiscript/dispatchkit/boxed_cast.hpp include/chaiscript/dispatchkit/boxed_cast_helper.hpp include/chaiscript/dispatchkit/boxed_number.hpp include/chaiscript/dispatchkit/boxed_value.hpp include/chaiscript/dispatchkit/dispatchkit.hpp include/chaiscript/dispatchkit/dynamic_cast_conversion.hpp include/chaiscript/dispatchkit/dynamic_object.hpp include/chaiscript/dispatchkit/exception_specification.hpp include/chaiscript/dispatchkit/function_call.hpp include/chaiscript/dispatchkit/function_call_detail.hpp include/chaiscript/dispatchkit/handle_return.hpp include/chaiscript/dispatchkit/operators.hpp include/chaiscript/dispatchkit/proxy_constructors.hpp include/chaiscript/dispatchkit/proxy_functions.hpp include/chaiscript/dispatchkit/proxy_functions_detail.hpp include/chaiscript/dispatchkit/register_function.hpp include/chaiscript/dispatchkit/type_info.hpp include/chaiscript/language/chaiscript_algebraic.hpp include/chaiscript/language/chaiscript_common.hpp include/chaiscript/language/chaiscript_engine.hpp include/chaiscript/language/chaiscript_eval.hpp include/chaiscript/language/chaiscript_parser.hpp include/chaiscript/language/chaiscript_prelude.chai include/chaiscript/language/chaiscript_prelude_docs.hpp include/chaiscript/utility/utility.hpp) set(Chai_INCLUDES include/chaiscript/chaiscript.hpp include/chaiscript/chaiscript_threading.hpp include/chaiscript/dispatchkit/bad_boxed_cast.hpp include/chaiscript/dispatchkit/bind_first.hpp include/chaiscript/dispatchkit/bootstrap.hpp include/chaiscript/dispatchkit/bootstrap_stl.hpp include/chaiscript/dispatchkit/boxed_cast.hpp include/chaiscript/dispatchkit/boxed_cast_helper.hpp include/chaiscript/dispatchkit/boxed_number.hpp include/chaiscript/dispatchkit/boxed_value.hpp include/chaiscript/dispatchkit/dispatchkit.hpp include/chaiscript/dispatchkit/type_conversions.hpp include/chaiscript/dispatchkit/dynamic_object.hpp include/chaiscript/dispatchkit/exception_specification.hpp include/chaiscript/dispatchkit/function_call.hpp include/chaiscript/dispatchkit/function_call_detail.hpp include/chaiscript/dispatchkit/handle_return.hpp include/chaiscript/dispatchkit/operators.hpp include/chaiscript/dispatchkit/proxy_constructors.hpp include/chaiscript/dispatchkit/proxy_functions.hpp include/chaiscript/dispatchkit/proxy_functions_detail.hpp include/chaiscript/dispatchkit/register_function.hpp include/chaiscript/dispatchkit/type_info.hpp include/chaiscript/language/chaiscript_algebraic.hpp include/chaiscript/language/chaiscript_common.hpp include/chaiscript/language/chaiscript_engine.hpp include/chaiscript/language/chaiscript_eval.hpp include/chaiscript/language/chaiscript_parser.hpp include/chaiscript/language/chaiscript_prelude.chai include/chaiscript/language/chaiscript_prelude_docs.hpp include/chaiscript/utility/utility.hpp)
set_source_files_properties(${Chai_INCLUDES} PROPERTIES HEADER_FILE_ONLY TRUE) set_source_files_properties(${Chai_INCLUDES} PROPERTIES HEADER_FILE_ONLY TRUE)
if (MULTITHREAD_SUPPORT_ENABLED) if(NOT MULTITHREAD_SUPPORT_ENABLED)
else()
add_definitions(-DCHAISCRIPT_NO_THREADS) add_definitions(-DCHAISCRIPT_NO_THREADS)
endif() endif()
if (CMAKE_HOST_UNIX) if(CMAKE_HOST_UNIX)
if (NOT ${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD") if(NOT ${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD" AND NOT ${CMAKE_SYSTEM_NAME} MATCHES "Haiku")
list(APPEND LIBS "dl") list(APPEND LIBS "dl")
endif(NOT ${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD") endif()
if (MULTITHREAD_SUPPORT_ENABLED) if(MULTITHREAD_SUPPORT_ENABLED)
if (CMAKE_COMPILER_IS_GNUCC) if(CMAKE_COMPILER_IS_GNUCC)
execute_process(COMMAND ${CMAKE_C_COMPILER} --version OUTPUT_VARIABLE GCC_FULL_VERSION) execute_process(COMMAND ${CMAKE_C_COMPILER} --version OUTPUT_VARIABLE GCC_FULL_VERSION)
if (GCC_FULL_VERSION MATCHES "4.8.1.*ubuntu") if(GCC_FULL_VERSION MATCHES "4.8.1.*ubuntu")
set (EXTRA_LINKER_FLAGS ${EXTRA_LINKER_FLAGS} -Wl,--no-as-needed -pthread ) set(LINKER_FLAGS "${LINKER_FLAGS} -Wl,--no-as-needed -pthread")
else() else()
set (EXTRA_LINKER_FLAGS ${EXTRA_LINKER_FLAGS} -pthread ) set(LINKER_FLAGS "${LINKER_FLAGS} -pthread")
endif() endif()
else() else()
set (EXTRA_LINKER_FLAGS ${EXTRA_LINKER_FLAGS} -pthread ) set(LINKER_FLAGS "${LINKER_FLAGS} -pthread")
endif() endif()
add_definitions(-pthread) add_definitions(-pthread)
endif() endif()
endif(CMAKE_HOST_UNIX) endif()
list(APPEND LIBS ${READLINE_LIB}) list(APPEND LIBS ${READLINE_LIB})
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${LINKER_FLAGS}")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${LINKER_FLAGS}")
set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${LINKER_FLAGS}")
add_library(chaiscript_stdlib MODULE src/chaiscript_stdlib.cpp) add_library(chaiscript_stdlib-${CHAI_VERSION} MODULE src/chaiscript_stdlib.cpp)
target_link_libraries(chaiscript_stdlib ${LIBS} ${EXTRA_LINKER_FLAGS} ${CMAKE_THREAD_LIBS_INIT}) target_link_libraries(chaiscript_stdlib-${CHAI_VERSION} ${LIBS} ${CMAKE_THREAD_LIBS_INIT})
add_executable(chai src/main.cpp ${Chai_INCLUDES}) add_executable(chai src/main.cpp ${Chai_INCLUDES})
target_link_libraries(chai ${LIBS} ${EXTRA_LINKER_FLAGS}) target_link_libraries(chai ${LIBS})
add_dependencies(chai chaiscript_stdlib) add_dependencies(chai chaiscript_stdlib-${CHAI_VERSION})
if (BUILD_SAMPLES) if(BUILD_SAMPLES)
add_executable(example samples/example.cpp) add_executable(example samples/example.cpp)
target_link_libraries(example ${LIBS} ${EXTRA_LINKER_FLAGS}) target_link_libraries(example ${LIBS})
add_executable(memory_leak_test samples/memory_leak_test.cpp) add_executable(memory_leak_test samples/memory_leak_test.cpp)
target_link_libraries(memory_leak_test ${LIBS} ${EXTRA_LINKER_FLAGS}) target_link_libraries(memory_leak_test ${LIBS})
add_executable(inheritance samples/inheritance.cpp)
target_link_libraries(inheritance ${LIBS})
add_executable(fun_call_performance samples/fun_call_performance.cpp)
target_link_libraries(fun_call_performance ${LIBS})
endif() endif()
if (BUILD_MODULES) if(BUILD_MODULES)
add_library(stl_extra MODULE src/stl_extra.cpp) add_library(stl_extra MODULE src/stl_extra.cpp)
target_link_libraries(stl_extra ${LIBS} ${EXTRA_LINKER_FLAGS}) target_link_libraries(stl_extra ${LIBS})
add_library(reflection MODULE src/reflection.cpp) set(MODULES stl_extra)
target_link_libraries(reflection ${LIBS} ${EXTRA_LINKER_FLAGS})
set(MODULES stl_extra reflection)
endif() endif()
file(GLOB UNIT_TESTS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/unittests/ ${CMAKE_CURRENT_SOURCE_DIR}/unittests/*.chai ${CMAKE_CURRENT_SOURCE_DIR}/unittests/3.x/*.chai) file(GLOB UNIT_TESTS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/unittests/ ${CMAKE_CURRENT_SOURCE_DIR}/unittests/*.chai ${CMAKE_CURRENT_SOURCE_DIR}/unittests/3.x/*.chai)
@@ -205,134 +251,153 @@ list(SORT UNIT_TESTS)
if(BUILD_TESTING) if(BUILD_TESTING)
option(UNIT_TEST_LIGHT "Unit tests light (expect module loading failures)" FALSE) option(UNIT_TEST_LIGHT "Unit tests light (expect module loading failures)" FALSE)
foreach(filename ${UNIT_TESTS}) add_test(version_check chai -c "if(\"\\\${ version() };\\\${version_major()};\\\${version_minor()};\\\${version_patch()}\" != \"${CHAI_VERSION};${CPACK_PACKAGE_VERSION_MAJOR};${CPACK_PACKAGE_VERSION_MINOR};${CPACK_PACKAGE_VERSION_PATCH}\") { exit(-1) }")
message(STATUS "Adding test ${filename}") set_property(TEST version_check
add_test(${filename} chai ${CMAKE_CURRENT_SOURCE_DIR}/unittests/unit_test.inc ${CMAKE_CURRENT_SOURCE_DIR}/unittests/${filename}) PROPERTY ENVIRONMENT
endforeach(filename)
set_property(TEST ${UNIT_TESTS}
PROPERTY ENVIRONMENT
"CHAI_USE_PATH=${CMAKE_CURRENT_SOURCE_DIR}/unittests/" "CHAI_USE_PATH=${CMAKE_CURRENT_SOURCE_DIR}/unittests/"
"CHAI_MODULE_PATH=${CMAKE_CURRENT_BINARY_DIR}/" "CHAI_MODULE_PATH=${CMAKE_CURRENT_BINARY_DIR}/"
) )
if (NOT UNIT_TEST_LIGHT)
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()
set_property(TEST ${UNIT_TESTS}
PROPERTY ENVIRONMENT
"CHAI_USE_PATH=${CMAKE_CURRENT_SOURCE_DIR}/unittests/"
"CHAI_MODULE_PATH=${CMAKE_CURRENT_BINARY_DIR}/"
)
if(NOT UNIT_TEST_LIGHT)
# commented out because uniform initializer syntax is not working properly in MSVC 2013 # commented out because uniform initializer syntax is not working properly in MSVC 2013
add_executable(utility_test unittests/utility_test.cpp) add_executable(utility_test unittests/utility_test.cpp)
target_link_libraries(utility_test ${LIBS} ${EXTRA_LINKER_FLAGS}) target_link_libraries(utility_test ${LIBS})
add_test(NAME Utility_Test COMMAND utility_test) add_test(NAME Utility_Test COMMAND utility_test)
add_executable(dynamic_object_test unittests/dynamic_object_test.cpp) add_executable(dynamic_object_test unittests/dynamic_object_test.cpp)
target_link_libraries(dynamic_object_test ${LIBS} ${EXTRA_LINKER_FLAGS}) target_link_libraries(dynamic_object_test ${LIBS})
add_test(NAME Dynamic_Object_Test COMMAND dynamic_object_test) add_test(NAME Dynamic_Object_Test COMMAND dynamic_object_test)
add_executable(functor_creation_test unittests/functor_creation_test.cpp) add_executable(functor_creation_test unittests/functor_creation_test.cpp)
target_link_libraries(functor_creation_test ${LIBS} ${EXTRA_LINKER_FLAGS}) target_link_libraries(functor_creation_test ${LIBS})
add_test(NAME Functor_Creation_Test COMMAND functor_creation_test) add_test(NAME Functor_Creation_Test COMMAND functor_creation_test)
add_executable(functor_cast_test unittests/functor_cast_test.cpp) add_executable(functor_cast_test unittests/functor_cast_test.cpp)
target_link_libraries(functor_cast_test ${LIBS} ${EXTRA_LINKER_FLAGS}) target_link_libraries(functor_cast_test ${LIBS})
add_test(NAME Functor_Cast_Test COMMAND functor_cast_test) add_test(NAME Functor_Cast_Test COMMAND functor_cast_test)
add_executable(boxed_cast_test unittests/boxed_cast_test.cpp) add_executable(boxed_cast_test unittests/boxed_cast_test.cpp)
target_link_libraries(boxed_cast_test ${LIBS} ${EXTRA_LINKER_FLAGS}) target_link_libraries(boxed_cast_test ${LIBS})
add_test(NAME Boxed_Cast_Test COMMAND boxed_cast_test) add_test(NAME Boxed_Cast_Test COMMAND boxed_cast_test)
add_executable(object_lifetime_test unittests/object_lifetime_test.cpp) add_executable(object_lifetime_test unittests/object_lifetime_test.cpp)
target_link_libraries(object_lifetime_test ${LIBS} ${EXTRA_LINKER_FLAGS}) target_link_libraries(object_lifetime_test ${LIBS})
add_test(NAME Object_Lifetime_Test COMMAND object_lifetime_test) add_test(NAME Object_Lifetime_Test COMMAND object_lifetime_test)
add_executable(object_lifetime_test2 unittests/object_lifetime_test2.cpp)
target_link_libraries(object_lifetime_test2 ${LIBS})
add_test(NAME Object_Lifetime_Test2 COMMAND object_lifetime_test2)
add_executable(function_ordering_test unittests/function_ordering_test.cpp) add_executable(function_ordering_test unittests/function_ordering_test.cpp)
target_link_libraries(function_ordering_test ${LIBS} ${EXTRA_LINKER_FLAGS}) target_link_libraries(function_ordering_test ${LIBS})
add_test(NAME Function_Ordering_Test COMMAND function_ordering_test) add_test(NAME Function_Ordering_Test COMMAND function_ordering_test)
add_executable(type_info_test unittests/type_info_test.cpp) add_executable(type_info_test unittests/type_info_test.cpp)
target_link_libraries(type_info_test ${LIBS} ${EXTRA_LINKER_FLAGS}) target_link_libraries(type_info_test ${LIBS})
add_test(NAME Type_Info_Test COMMAND type_info_test) add_test(NAME Type_Info_Test COMMAND type_info_test)
add_executable(type_name_test unittests/type_name_test.cpp)
target_link_libraries(type_name_test ${LIBS})
add_test(NAME Type_Name_Test COMMAND type_name_test)
add_executable(eval_catch_exception_test unittests/eval_catch_exception_test.cpp) add_executable(eval_catch_exception_test unittests/eval_catch_exception_test.cpp)
target_link_libraries(eval_catch_exception_test ${LIBS} ${EXTRA_LINKER_FLAGS}) target_link_libraries(eval_catch_exception_test ${LIBS})
add_test(NAME Eval_Catch_Exception_Test COMMAND eval_catch_exception_test) add_test(NAME Eval_Catch_Exception_Test COMMAND eval_catch_exception_test)
add_executable(short_comparison_test unittests/short_comparison_test.cpp) add_executable(short_comparison_test unittests/short_comparison_test.cpp)
target_link_libraries(short_comparison_test ${LIBS} ${EXTRA_LINKER_FLAGS}) target_link_libraries(short_comparison_test ${LIBS})
add_test(NAME Short_Comparison_Test COMMAND short_comparison_test) add_test(NAME Short_Comparison_Test COMMAND short_comparison_test)
add_executable(cpp_lambda_test unittests/cpp_lambda_test.cpp) add_executable(cpp_lambda_test unittests/cpp_lambda_test.cpp)
target_link_libraries(cpp_lambda_test ${LIBS} ${EXTRA_LINKER_FLAGS}) target_link_libraries(cpp_lambda_test ${LIBS})
add_test(NAME cpp_lambda_test COMMAND cpp_lambda_test) add_test(NAME cpp_lambda_test COMMAND cpp_lambda_test)
add_executable(expected_eval_errors_test unittests/expected_eval_errors_test.cpp) add_executable(expected_eval_errors_test unittests/expected_eval_errors_test.cpp)
target_link_libraries(expected_eval_errors_test ${LIBS} ${EXTRA_LINKER_FLAGS}) target_link_libraries(expected_eval_errors_test ${LIBS})
add_test(NAME Expected_Eval_Errors_Test COMMAND expected_eval_errors_test) add_test(NAME Expected_Eval_Errors_Test COMMAND expected_eval_errors_test)
add_executable(set_state_test unittests/set_state_test.cpp) add_executable(set_state_test unittests/set_state_test.cpp)
target_link_libraries(set_state_test ${LIBS} ${EXTRA_LINKER_FLAGS}) target_link_libraries(set_state_test ${LIBS})
add_test(NAME Set_State_Test COMMAND set_state_test) add_test(NAME Set_State_Test COMMAND set_state_test)
add_executable(simultaneous_chaiscript_test unittests/simultaneous_chaiscript_test.cpp) add_executable(simultaneous_chaiscript_test unittests/simultaneous_chaiscript_test.cpp)
target_link_libraries(simultaneous_chaiscript_test ${LIBS} ${EXTRA_LINKER_FLAGS}) target_link_libraries(simultaneous_chaiscript_test ${LIBS})
add_test(NAME Simultaneous_Chaiscript_Test COMMAND simultaneous_chaiscript_test) add_test(NAME Simultaneous_ChaiScript_Test COMMAND simultaneous_chaiscript_test)
add_executable(heap_allocated_chaiscript_test unittests/heap_allocated_chaiscript_test.cpp) add_executable(heap_allocated_chaiscript_test unittests/heap_allocated_chaiscript_test.cpp)
target_link_libraries(heap_allocated_chaiscript_test ${LIBS} ${EXTRA_LINKER_FLAGS}) target_link_libraries(heap_allocated_chaiscript_test ${LIBS})
add_test(NAME Heap_Allocated_Chaiscript_Test COMMAND heap_allocated_chaiscript_test) add_test(NAME Heap_Allocated_ChaiScript_Test COMMAND heap_allocated_chaiscript_test)
add_executable(c_linkage_test unittests/c_linkage_test.cpp) add_executable(c_linkage_test unittests/c_linkage_test.cpp)
target_link_libraries(c_linkage_test ${LIBS} ${EXTRA_LINKER_FLAGS}) target_link_libraries(c_linkage_test ${LIBS})
add_test(NAME C_Linkage_Test COMMAND c_linkage_test) add_test(NAME C_Linkage_Test COMMAND c_linkage_test)
add_executable(integer_literal_test unittests/integer_literal_test.cpp) add_executable(integer_literal_test unittests/integer_literal_test.cpp)
target_link_libraries(integer_literal_test ${LIBS} ${EXTRA_LINKER_FLAGS}) target_link_libraries(integer_literal_test ${LIBS})
add_test(NAME Integer_Literal_Test COMMAND integer_literal_test) add_test(NAME Integer_Literal_Test COMMAND integer_literal_test)
add_executable(arithmetic_conversions_test unittests/arithmetic_conversions_test.cpp) add_executable(arithmetic_conversions_test unittests/arithmetic_conversions_test.cpp)
target_link_libraries(arithmetic_conversions_test ${LIBS} ${EXTRA_LINKER_FLAGS}) target_link_libraries(arithmetic_conversions_test ${LIBS})
add_test(NAME Arithmetic_Conversions_Test COMMAND arithmetic_conversions_test) add_test(NAME Arithmetic_Conversions_Test COMMAND arithmetic_conversions_test)
if (MULTITHREAD_SUPPORT_ENABLED) if(MULTITHREAD_SUPPORT_ENABLED)
add_executable(multithreaded_test unittests/multithreaded_test.cpp) add_executable(multithreaded_test unittests/multithreaded_test.cpp)
target_link_libraries(multithreaded_test ${LIBS} ${EXTRA_LINKER_FLAGS}) target_link_libraries(multithreaded_test ${LIBS})
add_test(NAME Multithreaded_Test COMMAND multithreaded_test) add_test(NAME Multithreaded_Test COMMAND multithreaded_test)
set_property(TEST Multithreaded_Test set_property(TEST Multithreaded_Test
PROPERTY ENVIRONMENT PROPERTY ENVIRONMENT
"CHAI_USE_PATH=${CMAKE_CURRENT_SOURCE_DIR}/unittests/" "CHAI_USE_PATH=${CMAKE_CURRENT_SOURCE_DIR}/unittests/"
"CHAI_MODULE_PATH=${CMAKE_CURRENT_BINARY_DIR}/" "CHAI_MODULE_PATH=${CMAKE_CURRENT_BINARY_DIR}/"
) )
endif() endif()
add_executable(multifile_test unittests/multifile_test_main.cpp unittests/multifile_test_chai.cpp add_executable(multifile_test
unittests/multifile_test_module.cpp) unittests/multifile_test_main.cpp
target_link_libraries(multifile_test ${LIBS} ${EXTRA_LINKER_FLAGS}) unittests/multifile_test_chai.cpp
unittests/multifile_test_module.cpp
)
target_link_libraries(multifile_test ${LIBS})
add_test(NAME MultiFile_Test COMMAND multifile_test) add_test(NAME MultiFile_Test COMMAND multifile_test)
add_library(test_module MODULE src/test_module.cpp) add_library(test_module MODULE src/test_module.cpp)
target_link_libraries(test_module ${LIBS} ${EXTRA_LINKER_FLAGS}) target_link_libraries(test_module ${LIBS})
install(TARGETS test_module RUNTIME DESTINATION bin LIBRARY DESTINATION lib/chaiscript) install(TARGETS test_module RUNTIME DESTINATION bin LIBRARY DESTINATION lib/chaiscript)
endif() endif()
endif(BUILD_TESTING) endif()
install(TARGETS chai chaiscript_stdlib ${MODULES} RUNTIME DESTINATION bin LIBRARY DESTINATION lib/chaiscript ) install(TARGETS chai chaiscript_stdlib-${CHAI_VERSION} ${MODULES} RUNTIME DESTINATION bin LIBRARY DESTINATION lib/chaiscript)
install(DIRECTORY include/chaiscript DESTINATION include install(DIRECTORY include/chaiscript DESTINATION include
PATTERN "*.hpp" PATTERN "*.hpp"
PATTERN "*/.svn*" EXCLUDE PATTERN "*/.svn*" EXCLUDE
PATTERN "*/.git*" EXCLUDE PATTERN "*/.git*" EXCLUDE
PATTERN "*~" EXCLUDE) PATTERN "*~" EXCLUDE)
install(DIRECTORY unittests DESTINATION share/chaiscript install(DIRECTORY unittests DESTINATION share/chaiscript
PATTERN "*.chai" PATTERN "*.chai"
PATTERN "*.inc" PATTERN "*.inc"
PATTERN "*/.svn*" EXCLUDE PATTERN "*/.svn*" EXCLUDE
PATTERN "*/.git*" EXCLUDE PATTERN "*/.git*" EXCLUDE
PATTERN "*~" EXCLUDE) PATTERN "*~" EXCLUDE)
install(DIRECTORY samples DESTINATION share/chaiscript install(DIRECTORY samples DESTINATION share/chaiscript
PATTERN "*.chai" PATTERN "*.chai"
PATTERN "*/.svn*" EXCLUDE PATTERN "*/.svn*" EXCLUDE
PATTERN "*/.git*" EXCLUDE PATTERN "*/.git*" EXCLUDE
PATTERN "*~" EXCLUDE) PATTERN "*~" EXCLUDE)
configure_file(contrib/pkgconfig/chaiscript.pc.in lib/pkgconfig/chaiscript.pc @ONLY) configure_file(contrib/pkgconfig/chaiscript.pc.in lib/pkgconfig/chaiscript.pc @ONLY)
install(FILES "${chaiscript_BINARY_DIR}/lib/pkgconfig/chaiscript.pc" install(FILES "${chaiscript_BINARY_DIR}/lib/pkgconfig/chaiscript.pc"

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

@@ -38,7 +38,7 @@
************************************************************************************/ ************************************************************************************/
$language_data = array ( $language_data = array (
'LANG_NAME' => 'Chaiscript', 'LANG_NAME' => 'ChaiScript',
'COMMENT_SINGLE' => array(1 => '//'), 'COMMENT_SINGLE' => array(1 => '//'),
'COMMENT_MULTI' => array('/*' => '*/'), 'COMMENT_MULTI' => array('/*' => '*/'),
//Regular Expressions //Regular Expressions

View File

@@ -9,8 +9,8 @@
/// \mainpage /// @mainpage
/// <a href="http://www.chaiscript.com">ChaiScript</a> is a scripting language designed specifically for integration with C++. It provides /// [ChaiScript](http://www.chaiscript.com") is a scripting language designed specifically for integration with C++. It provides
/// seamless integration with C++ on all levels, including shared_ptr objects, functors and exceptions. /// seamless integration with C++ on all levels, including shared_ptr objects, functors and exceptions.
/// ///
/// The parts of the ChaiScript API that the average user will be concerned with are contained in the /// The parts of the ChaiScript API that the average user will be concerned with are contained in the
@@ -18,42 +18,42 @@
/// ///
/// The end user parts of the API are extremely simple both in size and ease of use. /// The end user parts of the API are extremely simple both in size and ease of use.
/// ///
/// Currently, all source control and project management aspects of ChaiScript occur on <a href="http://www.github.com/ChaiScript/ChaiScript">github</a>. /// Currently, all source control and project management aspects of ChaiScript occur on [github](http://www.github.com/ChaiScript/ChaiScript").
/// ///
/// <hr> /// ------------------------------------------------------------
/// ///
/// \sa chaiscript /// @sa chaiscript
/// \sa chaiscript::ChaiScript /// @sa chaiscript::ChaiScript
/// \sa ChaiScript_Language for Built in Functions /// @sa ChaiScript_Language for Built in Functions
/// \sa \ref LangGettingStarted /// @sa @ref LangGettingStarted
/// \sa \ref LangKeywordRef /// @sa @ref LangKeywordRef
/// \sa \ref LangInPlaceRef /// @sa @ref LangInPlaceRef
/// \sa \ref LangObjectSystemRef /// @sa @ref LangObjectSystemRef
/// \sa http://www.chaiscript.com /// @sa http://www.chaiscript.com
/// \sa http://www.github.com/ChaiScript/ChaiScript /// @sa http://www.github.com/ChaiScript/ChaiScript
/// ///
/// <hr> /// -----------------------------------------------------------
/// ///
/// \section gettingstarted API Getting Started /// @section gettingstarted API Getting Started
/// ///
/// \li \ref basics /// - @ref basics
/// \li \ref compiling /// - @ref compiling
/// \li \ref eval /// - @ref eval
/// \li \ref addingitems /// - @ref adding_items
/// \li \ref operatoroverloading /// - @ref operatoroverloading
/// \li \ref helpermacro /// - @ref add_class
/// \li \ref pointerconversions /// - @ref pointer_conversions
/// \li \ref baseclasses /// - @ref baseclasses
/// \li \ref functionobjects /// - @ref functionobjects
/// \li \ref threading /// - @ref threading
/// \li \ref exceptions /// - @ref exceptions
/// ///
/// ///
/// \subsection basics Basics /// @subsection basics Basics
/// ///
/// Basic simple example: /// Basic simple example:
/// ///
/// \code /// ~~~~~~~{.cpp}
/// //main.cpp /// //main.cpp
/// #include <chaiscript/chaiscript.hpp> /// #include <chaiscript/chaiscript.hpp>
/// ///
@@ -69,111 +69,115 @@
/// ///
/// double d = chai.eval<double>("function(3, 4.75);"); /// double d = chai.eval<double>("function(3, 4.75);");
/// } /// }
/// \endcode /// ~~~~~~~
/// ///
/// <hr> /// ------------------------------------------------------
/// \subsection compiling Compiling ChaiScript Applications
/// ///
/// ChaiScript is a header only library with only one dependecy: The /// @subsection compiling Compiling ChaiScript Applications
///
/// ChaiScript is a header only library with only one dependency: The
/// operating system provided dynamic library loader, which has to be specified on some platforms. /// operating system provided dynamic library loader, which has to be specified on some platforms.
/// ///
/// \subsubsection compilinggcc Compiling with GCC /// @subsubsection compilinggcc Compiling with GCC
/// ///
/// To compile the above application on a Unix like operating system (MacOS, Linux) with GCC you need to link /// To compile the above application on a Unix like operating system (MacOS, Linux) with GCC you need to link
/// the dynamic loader. For example: /// the dynamic loader. For example:
/// ///
/// \code /// ~~~~~~~~
/// gcc main.cpp -I/path/to/chaiscript/headers -ldl /// gcc main.cpp -I/path/to/chaiscript/headers -ldl
/// \endcode /// ~~~~~~~~
/// ///
/// Alternatively, you may compile without threading support. /// Alternatively, you may compile without threading support.
/// ///
/// \code /// ~~~~~~~~
/// gcc main.cpp -I/path/to/chaiscript/headers -ldl -DCHAISCRIPT_NO_THREADS /// gcc main.cpp -I/path/to/chaiscript/headers -ldl -DCHAISCRIPT_NO_THREADS
/// \endcode /// ~~~~~~~~
/// ///
/// <hr> /// ------------------------------------------
/// \subsection eval Evaluating Scripts ///
/// @subsection eval Evaluating Scripts
/// ///
/// Scripts can be evaluated with the () operator, eval method or eval_file method. /// Scripts can be evaluated with the () operator, eval method or eval_file method.
/// ///
/// \subsubsection parenoperator () Operator /// @subsubsection parenoperator () Operator
/// ///
/// operator() can be used as a handy shortcut for evaluating ChaiScript snippets. /// operator() can be used as a handy shortcut for evaluating ChaiScript snippets.
/// \code
/// chaiscript::ChaiScript chai;
/// chai("print(\"hello world\")");
/// \endcode
///
/// \sa chaiscript::ChaiScript::operator()(const std::string &)
/// ///
/// \subsubsection evalmethod Method 'eval' /// ~~~~~~~~{.cpp}
/// chaiscript::ChaiScript chai;
/// chai("print(@"hello world@")");
/// ~~~~~~~~
/// ///
/// The eval method is somewhat more verbose and can be used to get typesafely return values /// @sa chaiscript::ChaiScript::operator()(const std::string &)
///
/// @subsubsection evalmethod Method 'eval'
///
/// The eval method is somewhat more verbose and can be used to get type safely return values
/// from the script. /// from the script.
/// ///
/// \code /// ~~~~~~~~{.cpp}
/// chaiscript::ChaiScript chai; /// chaiscript::ChaiScript chai;
/// chai.eval("callsomefunc()"); /// chai.eval("callsomefunc()");
/// int result = chai.eval<int>("1 + 3"); /// int result = chai.eval<int>("1 + 3");
/// // result now equals 4 /// // result now equals 4
/// \endcode /// ~~~~~~~~
/// ///
/// \sa chaiscript::ChaiScript::eval /// @sa chaiscript::ChaiScript::eval
/// ///
/// \subsubsection evalfilemethod Method 'eval_file' /// @subsubsection evalfilemethod Method 'eval_file'
/// ///
/// The 'eval_file' method loads a file from disk and executes the script in it /// The 'eval_file' method loads a file from disk and executes the script in it
/// ///
/// \code /// ~~~~~~~~{.cpp}
/// chaiscript::ChaiScript chai; /// chaiscript::ChaiScript chai;
/// chai.eval_file("myfile.chai"); /// chai.eval_file("myfile.chai");
/// std::string result = chai.eval_file<std::string>("myfile.chai") // extract the last value returned from the file /// std::string result = chai.eval_file<std::string>("myfile.chai") // extract the last value returned from the file
/// \endcode /// ~~~~~~~~
/// ///
/// \sa chaiscript::ChaiScript::eval_file /// @sa chaiscript::ChaiScript::eval_file
/// ///
/// <hr> /// --------------------------------------------------
/// \subsection addingitems Adding Items to ChaiScript ///
/// @subsection adding_items Adding Items to ChaiScript
/// ///
/// ChaiScript supports 4 basic things that can be added: objects, functions, type infos and Modules /// ChaiScript supports 4 basic things that can be added: objects, functions, type infos and Modules
/// ///
/// \subsubsection addingobjects Adding Objects /// @subsubsection adding_objects Adding Objects
/// ///
/// Named objects can be created with the chaiscript::var function. Note: adding a object /// Named objects can be created with the chaiscript::var function. Note: adding a object
/// adds it to the current thread scope, not to a global scope. If you have multiple /// adds it to the current thread scope, not to a global scope. If you have multiple
/// threads that need to access the same variables you will need to add them /// threads that need to access the same variables you will need to add them
/// separately for each thread, from the thread itself. /// separately for each thread, from the thread itself.
/// ///
/// \code /// ~~~~~~~~~{.cpp}
/// using namespace chaiscript; /// using namespace chaiscript;
/// ChaiScript chai; /// ChaiScript chai;
/// int i = 5; /// int i = 5;
/// chai.add(var(i), "i"); /// chai.add(var(i), "i");
/// chai("print(i)"); /// chai("print(i)");
/// \endcode /// ~~~~~~~~~
/// ///
/// Immutable objects can be created with the chaiscript::const_var function. /// Immutable objects can be created with the chaiscript::const_var function.
/// ///
/// \code /// ~~~~~~~~~{.cpp}
/// chai.add(const_var(i), "i"); /// chai.add(const_var(i), "i");
/// chai("i = 5"); // exception throw, cannot assign const var /// chai("i = 5"); // exception throw, cannot assign const var
/// \endcode /// ~~~~~~~~~
/// ///
/// Named variables can only be accessed from the context they are created in. /// Named variables can only be accessed from the context they are created in.
/// If you want a global variable, it must be const, and created with the /// If you want a global variable, it must be const, and created with the
/// chaiscript::ChaiScript::add_global_const function. /// chaiscript::ChaiScript::add_global_const function.
/// ///
/// \code /// ~~~~~~~~~{.cpp}
/// chai.add_global_const(const_var(i), "i"); /// chai.add_global_const(const_var(i), "i");
/// chai("def somefun() { print(i); }; sumfun();"); /// chai("def somefun() { print(i); }; sumfun();");
/// \endcode /// ~~~~~~~~~
/// ///
/// \subsubsection addingfunctions Adding Functions /// @subsubsection adding_functions Adding Functions
/// ///
/// Functions, methods and members are all added using the same function: chaiscript::fun. /// Functions, methods and members are all added using the same function: chaiscript::fun.
/// ///
/// \code /// ~~~~~~~~~{.cpp}
/// using namespace chaiscript; /// using namespace chaiscript;
/// ///
/// class MyClass { /// class MyClass {
@@ -190,26 +194,26 @@
/// chai.add(fun(&MyClass::memberdata), "memberdata"); /// chai.add(fun(&MyClass::memberdata), "memberdata");
/// chai.add(fun(&MyClass::method), "method"); /// chai.add(fun(&MyClass::method), "method");
/// chai.add(fun(&MyClass::staticmethod), "staticmethod"); /// chai.add(fun(&MyClass::staticmethod), "staticmethod");
/// \endcode /// ~~~~~~~~~
/// ///
/// Overloaded methods will need some help, to hint the compiler as to which overload you want: /// Overloaded methods will need some help, to hint the compiler as to which overload you want:
/// ///
/// \code /// ~~~~~~~~~{.cpp}
/// chai.add(fun<void (MyClass::*)()>(&MyClass::overloadedmethod), "overloadedmethod"); /// chai.add(fun<void (MyClass::*)()>(&MyClass::overloadedmethod), "overloadedmethod");
/// chai.add(fun<void (MyClass::*)(const std::string &)>(&MyClass::overloadedmethod), "overloadedmethod"); /// chai.add(fun<void (MyClass::*)(const std::string &)>(&MyClass::overloadedmethod), "overloadedmethod");
/// \endcode /// ~~~~~~~~~
/// ///
/// There are also shortcuts built into chaiscript::fun for binding up to the first two parameters of the function. /// There are also shortcuts built into chaiscript::fun for binding up to the first two parameters of the function.
/// ///
/// \code /// ~~~~~~~~~{.cpp}
/// MyClass obj; /// MyClass obj;
/// chai.add(fun(&MyClass::method, &obj), "method"); /// chai.add(fun(&MyClass::method, &obj), "method");
/// chai("method()"); // equiv to obj.method() /// chai("method()"); // equiv to obj.method()
/// chai.add(fun(&MyClass::method2, &obj, 3), "method2"); /// chai.add(fun(&MyClass::method2, &obj, 3), "method2");
/// chai("method2()"); // equiv to obj.method2(3) /// chai("method2()"); // equiv to obj.method2(3)
/// \endcode /// ~~~~~~~~~
/// ///
/// \subsubsection addingtypeinfo Adding Type Info /// @subsubsection addingtypeinfo Adding Type Info
/// ///
/// ChaiScript will automatically support any type implicitly provided to it in the form /// ChaiScript will automatically support any type implicitly provided to it in the form
/// of objects and function parameters / return types. However, it can be nice to let ChaiScript /// of objects and function parameters / return types. However, it can be nice to let ChaiScript
@@ -219,27 +223,28 @@
/// ///
/// Continuing with the example "MyClass" from above: /// Continuing with the example "MyClass" from above:
/// ///
/// \code /// ~~~~~~~~{.cpp}
/// chai.add(user_type<MyClass>(), "MyClass"); /// chai.add(user_type<MyClass>(), "MyClass");
/// \endcode /// ~~~~~~~~
/// ///
/// \subsubsection addingmodules Adding Modules /// @subsubsection adding_modules Adding Modules
/// ///
/// Modules are holders for collections of ChaiScript registrations. /// Modules are holders for collections of ChaiScript registrations.
/// ///
/// \code /// ~~~~~~~~{.cpp}
/// ModulePtr module = get_sum_module(); /// ModulePtr module = get_sum_module();
/// chai.add(module); /// chai.add(module);
/// \endcode /// ~~~~~~~~
/// ///
/// \sa chaiscript::Module /// @sa chaiscript::Module
/// ///
/// <hr> /// -----------------------------------------------------------------------
/// \subsection operatoroverloading Operator Overloading ///
/// @subsection operatoroverloading Operator Overloading
/// ///
/// Operators are just like any other function in ChaiScript, to overload an operator, simply register it. /// Operators are just like any other function in ChaiScript, to overload an operator, simply register it.
/// ///
/// \code /// ~~~~~~~~{.cpp}
/// class MyClass { /// class MyClass {
/// MyClass operator+(const MyClass &) const; /// MyClass operator+(const MyClass &) const;
/// }; /// };
@@ -254,17 +259,18 @@
/// } /// }
/// ///
/// chai.add(fun(append_string_int), "+"); /// chai.add(fun(append_string_int), "+");
/// \endcode /// ~~~~~~~~
/// ///
/// \sa \ref addingfunctions /// @sa @ref adding_functions
/// ///
/// <hr> /// -----------------------------------------------------------------------
/// \subsection helpermacro Class Helper Macro ///
/// @subsection add_class Class Helper Utility
/// ///
/// Much of the work of adding new classes to ChaiScript can be reduced with the help /// Much of the work of adding new classes to ChaiScript can be reduced with the help
/// of the CHAISCRIPT_CLASS helper macro. /// of the add_class helper utility.
/// ///
/// \code /// ~~~~~~~~{.cpp}
/// class Test /// class Test
/// { /// {
/// public: /// public:
@@ -277,40 +283,40 @@
/// ///
/// int main() /// int main()
/// { /// {
///
/// chaiscript::ModulePtr m = chaiscript::ModulePtr(new chaiscript::Module()); /// chaiscript::ModulePtr m = chaiscript::ModulePtr(new chaiscript::Module());
/// ///
/// CHAISCRIPT_CLASS( m, /// chaiscript::utility::add_class<chaiscript::Test>(*m,
/// Test, /// "Test",
/// (Test ()) /// { constructor<Test()>(),
/// (Test (const Test &)), /// constructor<Test(const Test &)>() },
/// ((function)) /// { {fun(&Test::function), "function"},
/// ((function2)) /// {fun(&Test::function2), "function2"},
/// ((function3)) /// {fun(&Test::function2), "function3"}
/// ((functionOverload)(std::string (Test::*)(double))) /// {fun(static_cast<std::string Test::*(double)>(&Test::functionOverload)), "functionOverload"}
/// ((functionOverload)(std::string (Test::*)(int))) /// {fun(static_cast<std::string Test::*(int)>(&Test::functionOverload)), "functionOverload"} }
/// ((operator=)) /// );
/// ); ///
/// ///
/// chaiscript::ChaiScript chai; /// chaiscript::ChaiScript chai;
/// chai.add(m); /// chai.add(m);
/// } /// }
/// \endcode /// ~~~~~~~~
/// ///
/// \sa \ref addingmodules /// @sa @ref adding_modules
/// ///
/// <hr> /// -----------------------------------------------------------------------
/// \subsection pointerconversions Pointer / Object Conversions ///
/// @subsection pointer_conversions Pointer / Object Conversions
/// ///
/// As much as possible, ChaiScript attempts to convert between &, *, const &, const *, std::shared_ptr<T>, /// As much as possible, ChaiScript attempts to convert between &, *, const &, const *, std::shared_ptr<T>,
/// std::shared_ptr<const T>, std::reference_wrapper<T>, std::reference_wrapper<const T> and value types automatically. /// std::shared_ptr<const T>, std::reference_wrapper<T>, std::reference_wrapper<const T> and value types automatically.
/// ///
/// If a chaiscript::var object was created in C++ from a pointer, it cannot be convered to a shared_ptr (this would add invalid reference counting). /// If a chaiscript::var object was created in C++ from a pointer, it cannot be converted to a shared_ptr (this would add invalid reference counting).
/// Const may be added, but never removed. /// Const may be added, but never removed.
/// ///
/// The take away is that you can pretty much expect function calls to Just Work when you need them to. /// The take away is that you can pretty much expect function calls to Just Work when you need them to.
/// ///
/// \code /// ~~~~~~~~{.cpp}
/// void fun1(const int *); /// void fun1(const int *);
/// void fun2(int *); /// void fun2(int *);
/// void fun3(int); /// void fun3(int);
@@ -350,18 +356,19 @@
/// chai("fun9(i)"); /// chai("fun9(i)");
/// chai("fun10(i)"); /// chai("fun10(i)");
/// } /// }
/// \endcode /// ~~~~~~~~
/// ///
/// See the unit test unittests/boxed_cast_test.cpp for a complete breakdown of the automatic casts that /// See the unit test unittests/boxed_cast_test.cpp for a complete breakdown of the automatic casts that
/// available and tested. /// available and tested.
/// ///
/// <hr> /// -----------------------------------------------------------------------
/// \subsection baseclasses Base Classes ///
/// @subsection baseclasses Base Classes
/// ///
/// ChaiScript supports handling of passing a derived class object to a function expecting a base class object. /// ChaiScript supports handling of passing a derived class object to a function expecting a base class object.
/// For the process to work, the base/derived relationship must be registered with the engine. /// For the process to work, the base/derived relationship must be registered with the engine.
/// ///
/// \code /// ~~~~~~~~{.cpp}
/// class Base {}; /// class Base {};
/// class Derived : public Base {}; /// class Derived : public Base {};
/// void myfunction(Base *b); /// void myfunction(Base *b);
@@ -375,16 +382,17 @@
/// chai.add(chaiscript::fun(&myfunction), "myfunction"); /// chai.add(chaiscript::fun(&myfunction), "myfunction");
/// chai("myfunction(d)"); /// chai("myfunction(d)");
/// } /// }
/// \endcode /// ~~~~~~~~
/// ///
/// <hr> /// -----------------------------------------------------------------------
/// ///
/// \subsection functionobjects Function Objects
/// ///
/// Functions are first class objects in Chaiscript and ChaiScript supports automatic conversion /// @subsection functionobjects Function Objects
///
/// Functions are first class objects in ChaiScript and ChaiScript supports automatic conversion
/// between ChaiScript functions and std::function objects. /// between ChaiScript functions and std::function objects.
/// ///
/// \code /// ~~~~~~~~{.cpp}
/// void callafunc(const std::function<void (const std::string &)> &t_func) /// void callafunc(const std::function<void (const std::string &)> &t_func)
/// { /// {
/// t_func("bob"); /// t_func("bob");
@@ -400,11 +408,12 @@
/// std::function<void ()> f = chai.eval<std::function<void ()> >("dump_system"); /// std::function<void ()> f = chai.eval<std::function<void ()> >("dump_system");
/// f(); // call the ChaiScript function dump_system, from C++ /// f(); // call the ChaiScript function dump_system, from C++
/// } /// }
/// \endcode /// ~~~~~~~~
/// ///
/// <hr> /// -----------------------------------------------------------------------
/// ///
/// \subsection threading Threading ///
/// @subsection threading Threading
/// ///
/// Thread safety is automatically handled within the ChaiScript system. Objects can be added /// Thread safety is automatically handled within the ChaiScript system. Objects can be added
/// and scripts executed from multiple threads. For each thread that executes scripts, a new /// and scripts executed from multiple threads. For each thread that executes scripts, a new
@@ -414,16 +423,17 @@
/// ///
/// Disabling thread safety increases performance in many cases. /// Disabling thread safety increases performance in many cases.
/// ///
/// <hr> /// -----------------------------------------------------------------------
/// ///
/// \subsection exceptions Exception Handling ///
/// @subsection exceptions Exception Handling
/// ///
/// \subsubsection exceptionsbasics Exception Handling Basics /// @subsubsection exceptionsbasics Exception Handling Basics
/// ///
/// Exceptions can be thrown in ChaiScript and caught in C++ or thrown in C++ and caught in /// Exceptions can be thrown in ChaiScript and caught in C++ or thrown in C++ and caught in
/// ChaiScript. /// ChaiScript.
/// ///
/// \code /// ~~~~~~~~{.cpp}
/// void throwexception() /// void throwexception()
/// { /// {
/// throw std::runtime_error("err"); /// throw std::runtime_error("err");
@@ -444,19 +454,19 @@
/// // i == 1 /// // i == 1
/// } /// }
/// } /// }
/// \endcode /// ~~~~~~~~
/// ///
/// \subsubsection exceptionsautomatic Exception Handling Automatic Unboxing /// @subsubsection exceptionsautomatic Exception Handling Automatic Unboxing
/// ///
/// As an alternative to the manual unboxing of exceptions shown above, exception specifications allow the user to tell /// As an alternative to the manual unboxing of exceptions shown above, exception specifications allow the user to tell
/// ChaiScript what possible exceptions are expected from the script being executed. /// ChaiScript what possible exceptions are expected from the script being executed.
/// ///
/// Example: /// Example:
/// \code /// ~~~~~~~~{.cpp}
/// chaiscript::ChaiScript chai; /// chaiscript::ChaiScript chai;
/// ///
/// try { /// try {
/// chai.eval("throw(runtime_error(\"error\"))", chaiscript::exception_specification<int, double, float, const std::string &, const std::exception &>()); /// chai.eval("throw(runtime_error(@"error@"))", chaiscript::exception_specification<int, double, float, const std::string &, const std::exception &>());
/// } catch (const double e) { /// } catch (const double e) {
/// } catch (int) { /// } catch (int) {
/// } catch (float) { /// } catch (float) {
@@ -464,19 +474,19 @@
/// } catch (const std::exception &e) { /// } catch (const std::exception &e) {
/// // This is the one what will be called in the specific throw() above /// // This is the one what will be called in the specific throw() above
/// } /// }
/// \endcode /// ~~~~~~~~
/// ///
/// \sa chaiscript::Exception_Handler for details on automatic exception unboxing /// @sa chaiscript::Exception_Handler for details on automatic exception unboxing
/// \sa chaiscript::exception_specification /// @sa chaiscript::exception_specification
/// \page LangObjectSystemRef ChaiScript Language Object Model Reference /// @page LangObjectSystemRef ChaiScript Language Object Model Reference
/// ///
/// ///
/// ChaiScript has an object system built in, for types defined within the ChaiScript system. /// ChaiScript has an object system built in, for types defined within the ChaiScript system.
/// ///
/// \code /// ~~~~~~~~~
/// attr Rectangle::height /// attr Rectangle::height
/// attr Rectangle::width /// attr Rectangle::width
/// def Rectangle::Rectangle() { this.height = 10; this.width = 20 } /// def Rectangle::Rectangle() { this.height = 10; this.width = 20 }
@@ -485,67 +495,84 @@
/// var rect = Rectangle() /// var rect = Rectangle()
/// rect.height = 30 /// rect.height = 30
/// print(rect.area()) /// print(rect.area())
/// \endcode /// ~~~~~~~~~
/// ///
/// \sa \ref keywordattr /// Since ChaiScript 5.4.0 it has been possible to use the "class" keyword to simplify this code.
/// \sa \ref keyworddef ///
/// ~~~~~~~~~
/// class Rectangle {
/// attr height
/// attr width
/// def Rectangle() { this.height = 10; this.width = 20 }
/// def area() { this.height * this.width }
/// }
///
/// var rect = Rectangle()
/// rect.height = 30
/// print(rect.area())
/// ~~~~~~~~~
///
/// @sa @ref keywordattr
/// @sa @ref keyworddef
/// \page LangInPlaceRef ChaiScript Language In-Place Creation Reference /// @page LangInPlaceRef ChaiScript Language In-Place Creation Reference
/// \section inplacevector Vector /// @section inplacevector Vector
/// ///
/// \code /// ~~~~~~~~~
/// In-place Vector ::= "[" [expression ("," expression)*] "]" /// In-place Vector ::= "[" [expression ("," expression)*] "]"
/// \endcode /// ~~~~~~~~~
/// ///
/// \section inplacerangedvector Ranged Vector /// @section inplacerangedvector Ranged Vector
/// ///
/// \code /// ~~~~~~~~~
/// In-place Ranged Vector ::= "[" value ".." value "]" /// In-place Ranged Vector ::= "[" value ".." value "]"
/// \endcode /// ~~~~~~~~~
/// ///
/// Creates a vector over a range (eg. 1..10) /// Creates a vector over a range (eg. 1..10)
/// ///
/// \section inplacemap Map /// @section inplacemap Map
/// ///
/// \code /// ~~~~~~~~
/// In-place Map ::= "[" (string ":" expression)+ "]" /// In-place Map ::= "[" (string ":" expression)+ "]"
/// \endcode /// ~~~~~~~~
/// \page LangGettingStarted ChaiScript Language Getting Started /// @page LangGettingStarted ChaiScript Language Getting Started
/// ///
/// ChaiScript is a simple language that should feel familiar to anyone who knows /// ChaiScript is a simple language that should feel familiar to anyone who knows
/// C++ or ECMAScript (JavaScript). /// C++ or ECMAScript (JavaScript).
/// ///
/// <hr> /// -----------------------------------------------------------------------
/// \section chaiscriptloops Loops ///
/// @section chaiscriptloops Loops
/// ///
/// Common looping constructs exist in ChaiScript /// Common looping constructs exist in ChaiScript
/// ///
/// \code /// ~~~~~~~~
/// var i = 0; /// var i = 0;
/// while (i < 10) /// while (i < 10)
/// { /// {
/// // do something /// // do something
/// ++i; /// ++i;
/// } /// }
/// \endcode /// ~~~~~~~~
/// ///
/// \code /// ~~~~~~~~
/// for (var i = 0; i < 10; ++i) /// for (var i = 0; i < 10; ++i)
/// { /// {
/// // do something /// // do something
/// } /// }
/// \endcode /// ~~~~~~~~
/// ///
/// \sa \ref keywordfor /// @sa @ref keywordfor
/// \sa \ref keywordwhile /// @sa @ref keywordwhile
/// ///
/// <hr> /// -----------------------------------------------------------------------
/// \section chaiscriptifs Conditionals ///
/// @section chaiscriptifs Conditionals
/// ///
/// If statements work as expected /// If statements work as expected
/// ///
/// \code /// ~~~~~~~~
/// var b = true; /// var b = true;
/// ///
/// if (b) { /// if (b) {
@@ -555,103 +582,109 @@
/// } else { /// } else {
/// // or do this /// // or do this
/// } /// }
/// \endcode /// ~~~~~~~~
/// ///
/// \sa \ref keywordif /// @sa @ref keywordif
/// ///
/// <hr> /// -----------------------------------------------------------------------
/// \section chaiscriptfunctions Functions ///
/// @section chaiscriptfunctions Functions
/// ///
/// Functions are defined with the def keyword /// Functions are defined with the def keyword
/// ///
/// \code /// ~~~~~~~~
/// def myfun(x) { print(x); } /// def myfun(x) { print(x); }
/// ///
/// myfun(10); /// myfun(10);
/// \endcode /// ~~~~~~~~
/// ///
/// Functions may have "guards" which determine if which is called. /// Functions may have "guards" which determine if which is called.
/// ///
/// \code /// ~~~~~~~~
/// eval> def myfun2(x) : x < 10 { print("less than 10"); } /// eval> def myfun2(x) : x < 10 { print("less than 10"); }
/// eval> def myfun2(x) : x >= 10 { print("10 or greater"); } /// eval> def myfun2(x) : x >= 10 { print("10 or greater"); }
/// eval> myfun2(5) /// eval> myfun2(5)
/// less than 10 /// less than 10
/// eval> myfun2(12) /// eval> myfun2(12)
/// 10 or greater /// 10 or greater
/// \endcode /// ~~~~~~~~
/// ///
/// \sa \ref keyworddef /// @sa @ref keyworddef
/// \sa \ref keywordattr /// @sa @ref keywordattr
/// \sa \ref LangObjectSystemRef /// @sa @ref LangObjectSystemRef
/// ///
/// <hr> /// -----------------------------------------------------------------------
/// \section chaiscriptfunctionobjects Function Objects ///
/// @section chaiscriptfunctionobjects Function Objects
/// ///
/// Functions are first class types in ChaiScript and can be used as variables. /// Functions are first class types in ChaiScript and can be used as variables.
/// ///
/// \code /// ~~~~~~~~
/// eval> var p = print; /// eval> var p = print;
/// eval> p(1); /// eval> p(1);
/// 1 /// 1
/// \endcode /// ~~~~~~~~
/// ///
/// They can also be passed to functions. /// They can also be passed to functions.
/// ///
/// \code /// ~~~~~~~~
/// eval> def callfunc(f, lhs, rhs) { return f(lhs, rhs); } /// eval> def callfunc(f, lhs, rhs) { return f(lhs, rhs); }
/// eval> def dosomething(lhs, rhs) { print("lhs: ${lhs}, rhs: ${rhs}"); } /// eval> def do_something(lhs, rhs) { print("lhs: ${lhs}, rhs: ${rhs}"); }
/// eval> callfunc(dosomething, 1, 2); /// eval> callfunc(do_something, 1, 2);
/// lhs: 1, rhs: 2 /// lhs: 1, rhs: 2
/// \endcode /// ~~~~~~~~
/// ///
/// Operators can also be treated as functions by using the back tick operator. Building on the above example: /// Operators can also be treated as functions by using the back tick operator. Building on the above example:
/// ///
/// \code /// ~~~~~~~~
/// eval> callfunc(`+`, 1, 4); /// eval> callfunc(`+`, 1, 4);
/// 5 /// 5
/// eval> callfunc(`*`, 3, 2); /// eval> callfunc(`*`, 3, 2);
/// 6 /// 6
/// \endcode /// ~~~~~~~~
/// ///
/// <hr> /// -----------------------------------------------------------------------
/// \sa \ref LangKeywordRef ///
/// \sa ChaiScript_Language for Built in Functions /// @sa @ref LangKeywordRef
/// @sa ChaiScript_Language for Built in Functions
/// \page LangKeywordRef ChaiScript Language Keyword Reference /// @page LangKeywordRef ChaiScript Language Keyword Reference
/// ///
/// ///
/// <hr> /// -----------------------------------------------------------------------
/// \section keywordattr attr ///
/// @section keywordattr attr
/// Defines a ChaiScript object attribute /// Defines a ChaiScript object attribute
/// ///
/// \code /// ~~~~~~~~
/// Attribute Definition ::= "attr" class_name "::" attribute_name /// Attribute Definition ::= "attr" class_name "::" attribute_name
/// \endcode /// ~~~~~~~~
/// ///
/// \sa \ref LangObjectSystemRef /// @sa @ref LangObjectSystemRef
/// ///
/// <hr> /// -----------------------------------------------------------------------
/// \section keywordbreak break ///
/// @section keywordbreak break
/// Stops execution of a looping block. /// Stops execution of a looping block.
/// ///
/// \code /// ~~~~~~~~
/// Break Statement ::= "break" /// Break Statement ::= "break"
/// \endcode /// ~~~~~~~~
/// ///
/// \sa \ref keywordfor /// @sa @ref keywordfor
/// \sa \ref keywordwhile /// @sa @ref keywordwhile
/// ///
/// ///
/// <hr> /// -----------------------------------------------------------------------
/// \section keyworddef def ///
/// @section keyworddef def
/// Begins a function or method definition /// Begins a function or method definition
/// ///
/// \code /// ~~~~~~~~
/// Function Definition ::= [annotation + CR/LF] "def" identifier "(" [arg ("," arg)*] ")" [":" guard] block /// Function Definition ::= [annotation + CR/LF] "def" identifier "(" [arg ("," arg)*] ")" [":" guard] block
/// Method Definition ::= [annotation + CR/LF] "def" class_name "::" method_name "(" [arg ("," arg)*] ")" [":" guard] block /// Method Definition ::= [annotation + CR/LF] "def" class_name "::" method_name "(" [arg ("," arg)*] ")" [":" guard] block
/// \endcode /// ~~~~~~~~
/// ///
/// annotation: meta-annotation on function, currently used as documentation. Optional. /// annotation: meta-annotation on function, currently used as documentation. Optional.
/// identifier: name of function. Required. /// identifier: name of function. Required.
@@ -667,50 +700,56 @@
/// Method definitions for known types extend those types with new methods. This includes C++ and ChaiScript defined types. /// Method definitions for known types extend those types with new methods. This includes C++ and ChaiScript defined types.
/// Method definitions for unknown types implicitly define the named type. /// Method definitions for unknown types implicitly define the named type.
/// ///
/// \sa \ref LangObjectSystemRef /// @sa @ref LangObjectSystemRef
/// ///
/// ///
/// <hr> /// -----------------------------------------------------------------------
/// \section keywordelse else ///
/// \sa \ref keywordif /// @section keywordelse else
/// @sa @ref keywordif
/// ///
/// ///
/// <hr> /// -----------------------------------------------------------------------
/// \section keywordfor for ///
/// \code /// @section keywordfor for
/// ~~~~~~~~
/// For Block ::= "for" "(" [initial] ";" stop_condition ";" loop_expression ")" block /// For Block ::= "for" "(" [initial] ";" stop_condition ";" loop_expression ")" block
/// \endcode /// ~~~~~~~~
/// This loop can be broken using the \ref keywordbreak command. /// This loop can be broken using the @ref keywordbreak command.
/// ///
/// ///
/// <hr> /// -----------------------------------------------------------------------
/// \section keywordfun fun ///
/// @section keywordfun fun
/// Begins an anonymous function declaration (sometimes called a lambda). /// Begins an anonymous function declaration (sometimes called a lambda).
/// ///
/// \code /// ~~~~~~~~
/// Lambda ::= "fun" "(" [variable] ("," variable)* ")" block /// Lambda ::= "fun" "(" [variable] ("," variable)* ")" block
/// \endcode /// ~~~~~~~~
/// ///
/// \b Examples: /// _Example_
/// ///
/// \code /// ~~~~~~~~
/// // Generate an anonymous function object that adds 2 to its parameter /// // Generate an anonymous function object that adds 2 to its parameter
/// var f = fun(x) { x + 2; } /// var f = fun(x) { x + 2; }
/// \endcode /// ~~~~~~~~
/// ///
/// \sa \ref keyworddef for more details on ChaiScript functions /// @sa @ref keyworddef for more details on ChaiScript functions
/// ///
/// ///
/// <hr> /// -----------------------------------------------------------------------
/// \section keywordif if ///
/// @section keywordif if
/// Begins a conditional block of code that only executes if the condition evaluates as true. /// Begins a conditional block of code that only executes if the condition evaluates as true.
/// \code /// ~~~~~~~~
/// If Block ::= "if" "(" condition ")" block /// If Block ::= "if" "(" condition ")" block
/// Else If Block ::= "else if" "(" condition ")" block /// Else If Block ::= "else if" "(" condition ")" block
/// Else Block ::= "else" block /// Else Block ::= "else" block
/// \endcode /// ~~~~~~~~
/// \b Example: ///
/// \code /// _Example_
///
/// ~~~~~~~~
/// if (true) { /// if (true) {
/// // do something /// // do something
/// } else if (false) { /// } else if (false) {
@@ -718,35 +757,38 @@
/// } else { /// } else {
/// // otherwise do this /// // otherwise do this
/// } /// }
/// \endcode /// ~~~~~~~~
/// ///
/// ///
/// <hr> /// -----------------------------------------------------------------------
/// \section keywordtry try ///
/// \code /// @section keywordtry try
/// ~~~~~~~~
/// Try Block ::= "try" block /// Try Block ::= "try" block
/// ("catch" ["(" variable ")"] [":" guards] block)+ /// ("catch" ["(" variable ")"] [":" guards] block)+
/// ["finally" block] /// ["finally" block]
/// \endcode /// ~~~~~~~~
/// ///
/// \sa ChaiScript_Language::throw /// @sa ChaiScript_Language::throw
/// ///
/// <hr> /// -----------------------------------------------------------------------
/// \section keywordwhile while ///
/// @section keywordwhile while
/// ///
/// Begins a conditional block of code that loops 0 or more times, as long as the condition is true /// Begins a conditional block of code that loops 0 or more times, as long as the condition is true
/// ///
/// \code /// ~~~~~~~~
/// While Block ::= "while" "(" condition ")" block /// While Block ::= "while" "(" condition ")" block
/// \endcode /// ~~~~~~~~
/// This loop can be broken using the \ref keywordbreak command. ///
/// This loop can be broken using the @ref keywordbreak command.
/// \namespace chaiscript /// @namespace chaiscript
/// \brief Namespace chaiscript contains every API call that the average user will be concerned with. /// @brief Namespace chaiscript contains every API call that the average user will be concerned with.
/// \namespace chaiscript::detail /// @namespace chaiscript::detail
/// \brief Classes and functions reserved for internal use. Items in this namespace are not supported. /// @brief Classes and functions reserved for internal use. Items in this namespace are not supported.
#include "chaiscript_defines.hpp" #include "chaiscript_defines.hpp"

View File

@@ -1,7 +1,7 @@
// 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-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// and Jason Turner (jason@emptycrate.com) // Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
#ifndef CHAISCRIPT_DEFINES_HPP_ #ifndef CHAISCRIPT_DEFINES_HPP_
@@ -12,10 +12,22 @@
#define CHAISCRIPT_HAS_DECLSPEC #define CHAISCRIPT_HAS_DECLSPEC
#endif #endif
#ifdef _WIN32 #if defined(_WIN32) || defined(__CYGWIN__)
#define CHAISCRIPT_WINDOWS #define CHAISCRIPT_WINDOWS
#endif #endif
#if (defined(__GNUC__) && __GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)
/// Currently only g++>=4.8supports this natively
/// \todo Make this support other compilers when possible
#define CHAISCRIPT_HAS_THREAD_LOCAL
#endif
#if (defined(__GNUC__) && __GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7) || defined(CHAISCRIPT_MSVC) || defined(__llvm__)
#define CHAISCRIPT_OVERRIDE override
#else
#define CHAISCRIPT_OVERRIDE
#endif
#ifdef CHAISCRIPT_HAS_DECLSPEC #ifdef CHAISCRIPT_HAS_DECLSPEC
#define CHAISCRIPT_MODULE_EXPORT extern "C" __declspec(dllexport) #define CHAISCRIPT_MODULE_EXPORT extern "C" __declspec(dllexport)
@@ -31,7 +43,11 @@
#define CHAISCRIPT_CONSTEXPR constexpr #define CHAISCRIPT_CONSTEXPR constexpr
#endif #endif
namespace chaiscript {
static const int version_major = 5;
static const int version_minor = 5;
static const int version_patch = 1;
}
#endif #endif

View File

@@ -7,11 +7,19 @@
#ifndef CHAISCRIPT_STDLIB_HPP_ #ifndef CHAISCRIPT_STDLIB_HPP_
#define CHAISCRIPT_STDLIB_HPP_ #define CHAISCRIPT_STDLIB_HPP_
#include <map>
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "chaiscript_defines.hpp" #include "chaiscript_defines.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/boxed_value.hpp"
/// \file /// @file
/// ///
/// This file generates the standard library that normal ChaiScript usage requires. /// This file generates the standard library that normal ChaiScript usage requires.

View File

@@ -64,16 +64,59 @@ namespace chaiscript
using std::recursive_mutex; using std::recursive_mutex;
#ifdef CHAISCRIPT_HAS_THREAD_LOCAL
/// Typesafe thread specific storage. If threading is enabled, this class uses a mutex protected map. If /// Typesafe thread specific storage. If threading is enabled, this class uses a mutex protected map. If
/// threading is not enabled, the class always returns the same data, regardless of which thread it is called from. /// threading is not enabled, the class always returns the same data, regardless of which thread it is called from.
///
/// \todo move to thread_local when it exists
template<typename T> template<typename T>
class Thread_Storage class Thread_Storage
{ {
public: public:
Thread_Storage(void *t_key)
: m_key(t_key)
{
}
~Thread_Storage()
{
t().erase(m_key);
}
inline T *operator->() const
{
return &(t()[m_key]);
}
inline T &operator*() const
{
return t()[m_key];
}
void *m_key;
private:
static std::unordered_map<void*, T> &t()
{
thread_local static std::unordered_map<void *, T> my_t;
return my_t;
}
};
#else
/// Typesafe thread specific storage. If threading is enabled, this class uses a mutex protected map. If
/// threading is not enabled, the class always returns the same data, regardless of which thread it is called from.
///
/// This version is used if the compiler does not support thread_local
template<typename T>
class Thread_Storage
{
public:
Thread_Storage(void *)
{
}
inline T *operator->() const inline T *operator->() const
{ {
return get_tls().get(); return get_tls().get();
@@ -88,35 +131,26 @@ namespace chaiscript
private: private:
std::shared_ptr<T> get_tls() const std::shared_ptr<T> get_tls() const
{ {
unique_lock<mutex> lock(m_mutex); unique_lock<mutex> lock(m_mutex);
auto itr = m_instances.find(std::this_thread::get_id()); auto itr = m_instances.find(std::this_thread::get_id());
if (itr != m_instances.end()) { return itr->second; } if (itr != m_instances.end()) { return itr->second; }
std::shared_ptr<T> new_instance(new T()); std::shared_ptr<T> new_instance(new T());
m_instances.insert(std::make_pair(std::this_thread::get_id(), new_instance)); m_instances.insert(std::make_pair(std::this_thread::get_id(), new_instance));
return new_instance; return new_instance;
/*
static __thread std::shared_ptr<T> *m_data = 0;
if (!m_data) { m_data = new std::shared_ptr<T>(new T()); }
return *m_data;
*/
} }
mutable mutex m_mutex; mutable mutex m_mutex;
mutable std::unordered_map<std::thread::id, std::shared_ptr<T> > m_instances; mutable std::unordered_map<std::thread::id, std::shared_ptr<T> > m_instances;
}; };
#endif // threading enabled but no tls
#else #else // threading disabled
template<typename T> template<typename T>
class unique_lock class unique_lock
{ {
@@ -151,6 +185,10 @@ namespace chaiscript
class Thread_Storage class Thread_Storage
{ {
public: public:
Thread_Storage(void *)
{
}
inline T *operator->() const inline T *operator->() const
{ {
return &obj; return &obj;

View File

@@ -7,6 +7,8 @@
#ifndef CHAISCRIPT_ANY_HPP_ #ifndef CHAISCRIPT_ANY_HPP_
#define CHAISCRIPT_ANY_HPP_ #define CHAISCRIPT_ANY_HPP_
#include <utility>
namespace chaiscript { namespace chaiscript {
namespace detail { namespace detail {
namespace exception namespace exception
@@ -26,8 +28,8 @@ namespace chaiscript {
virtual ~bad_any_cast() CHAISCRIPT_NOEXCEPT {} virtual ~bad_any_cast() CHAISCRIPT_NOEXCEPT {}
/// \brief Description of what error occured /// \brief Description of what error occurred
virtual const char * what() const CHAISCRIPT_NOEXCEPT virtual const char * what() const CHAISCRIPT_NOEXCEPT CHAISCRIPT_OVERRIDE
{ {
return m_what.c_str(); return m_what.c_str();
} }
@@ -42,45 +44,52 @@ namespace chaiscript {
private: private:
struct Data struct Data
{ {
Data(const std::type_info &t_type)
: m_type(t_type)
{
}
Data &operator=(const Data &) = delete;
virtual ~Data() {} virtual ~Data() {}
virtual void *data() = 0; virtual void *data() = 0;
virtual const std::type_info &type() const = 0; const std::type_info &type() const
virtual std::shared_ptr<Data> clone() const = 0; {
return m_type;
}
virtual std::unique_ptr<Data> clone() const = 0;
const std::type_info &m_type;
}; };
template<typename T> template<typename T>
struct Data_Impl : Data struct Data_Impl : Data
{ {
Data_Impl(const T &t_type) explicit Data_Impl(T t_type)
: m_type(typeid(T)), : Data(typeid(T)),
m_data(t_type) m_data(std::move(t_type))
{ {
} }
virtual ~Data_Impl() {} virtual ~Data_Impl() {}
virtual void *data() virtual void *data() CHAISCRIPT_OVERRIDE
{ {
return &m_data; return &m_data;
} }
const std::type_info &type() const std::unique_ptr<Data> clone() const CHAISCRIPT_OVERRIDE
{ {
return m_type; return std::unique_ptr<Data>(new Data_Impl<T>(m_data));
}
std::shared_ptr<Data> clone() const
{
return std::shared_ptr<Data>(new Data_Impl<T>(m_data));
} }
Data_Impl &operator=(const Data_Impl&) = delete; Data_Impl &operator=(const Data_Impl&) = delete;
const std::type_info &m_type;
T m_data; T m_data;
}; };
std::shared_ptr<Data> m_data; std::unique_ptr<Data> m_data;
public: public:
// construct/copy/destruct // construct/copy/destruct
@@ -96,12 +105,19 @@ namespace chaiscript {
} }
} }
template<typename ValueType> #if _MSC_VER != 1800
Any(const ValueType &t_value) Any(Any &&) = default;
: m_data(std::shared_ptr<Data>(new Data_Impl<ValueType>(t_value))) Any &operator=(Any &&t_any) = default;
#endif
template<typename ValueType,
typename = typename std::enable_if<!std::is_same<Any, typename std::decay<ValueType>::type>::value>::type>
explicit Any(ValueType &&t_value)
: m_data(std::unique_ptr<Data>(new Data_Impl<typename std::decay<ValueType>::type>(std::forward<ValueType>(t_value))))
{ {
} }
Any & operator=(const Any &t_any) Any & operator=(const Any &t_any)
{ {
Any copy(t_any); Any copy(t_any);
@@ -109,13 +125,6 @@ namespace chaiscript {
return *this; return *this;
} }
template<typename ValueType>
Any & operator=(const ValueType &t_value)
{
m_data = std::shared_ptr<Data>(new Data_Impl<ValueType>(t_value));
return *this;
}
template<typename ToType> template<typename ToType>
ToType &cast() const ToType &cast() const
{ {
@@ -125,7 +134,6 @@ namespace chaiscript {
} else { } else {
throw chaiscript::detail::exception::bad_any_cast(); throw chaiscript::detail::exception::bad_any_cast();
} }
} }
@@ -136,9 +144,7 @@ namespace chaiscript {
// modifiers // modifiers
Any & swap(Any &t_other) Any & swap(Any &t_other)
{ {
std::shared_ptr<Data> data = t_other.m_data; std::swap(t_other.m_data, m_data);
t_other.m_data = m_data;
m_data = data;
return *this; return *this;
} }

View File

@@ -7,8 +7,16 @@
#ifndef CHAISCRIPT_BAD_BOXED_CAST_HPP_ #ifndef CHAISCRIPT_BAD_BOXED_CAST_HPP_
#define CHAISCRIPT_BAD_BOXED_CAST_HPP_ #define CHAISCRIPT_BAD_BOXED_CAST_HPP_
#include <string>
#include <typeinfo>
#include "../chaiscript_defines.hpp"
#include "type_info.hpp" #include "type_info.hpp"
namespace chaiscript {
class Type_Info;
} // namespace chaiscript
namespace chaiscript namespace chaiscript
{ {
namespace exception namespace exception
@@ -21,26 +29,26 @@ namespace chaiscript
class bad_boxed_cast : public std::bad_cast class bad_boxed_cast : public std::bad_cast
{ {
public: public:
bad_boxed_cast(const Type_Info &t_from, const std::type_info &t_to, bad_boxed_cast(Type_Info t_from, const std::type_info &t_to,
const std::string &t_what) CHAISCRIPT_NOEXCEPT std::string t_what) CHAISCRIPT_NOEXCEPT
: from(t_from), to(&t_to), m_what(t_what) : from(std::move(t_from)), to(&t_to), m_what(std::move(t_what))
{ {
} }
bad_boxed_cast(const Type_Info &t_from, const std::type_info &t_to) CHAISCRIPT_NOEXCEPT bad_boxed_cast(Type_Info t_from, const std::type_info &t_to)
: from(t_from), to(&t_to), m_what("Cannot perform boxed_cast") : from(std::move(t_from)), to(&t_to), m_what("Cannot perform boxed_cast")
{ {
} }
bad_boxed_cast(const std::string &t_what) CHAISCRIPT_NOEXCEPT bad_boxed_cast(std::string t_what) CHAISCRIPT_NOEXCEPT
: to(0), m_what(t_what) : to(nullptr), m_what(std::move(t_what))
{ {
} }
virtual ~bad_boxed_cast() CHAISCRIPT_NOEXCEPT {} virtual ~bad_boxed_cast() CHAISCRIPT_NOEXCEPT {}
/// \brief Description of what error occured /// \brief Description of what error occurred
virtual const char * what() const CHAISCRIPT_NOEXCEPT virtual const char * what() const CHAISCRIPT_NOEXCEPT CHAISCRIPT_OVERRIDE
{ {
return m_what.c_str(); return m_what.c_str();
} }

View File

@@ -14,79 +14,20 @@ namespace chaiscript
namespace detail namespace detail
{ {
template<int> struct Placeholder
struct Placeholder {
{ static std::tuple<decltype(std::placeholders::_1),decltype(std::placeholders::_2),decltype(std::placeholders::_3),decltype(std::placeholders::_4),decltype(std::placeholders::_5),decltype(std::placeholders::_6),decltype(std::placeholders::_7),decltype(std::placeholders::_8),decltype(std::placeholders::_9),decltype(std::placeholders::_10)> placeholder() {
}; return std::tuple<decltype(std::placeholders::_1),decltype(std::placeholders::_2),decltype(std::placeholders::_3),decltype(std::placeholders::_4),decltype(std::placeholders::_5),decltype(std::placeholders::_6),decltype(std::placeholders::_7),decltype(std::placeholders::_8),decltype(std::placeholders::_9),decltype(std::placeholders::_10)>(std::placeholders::_1,std::placeholders::_2,std::placeholders::_3,std::placeholders::_4,std::placeholders::_5,std::placeholders::_6,std::placeholders::_7,std::placeholders::_8,std::placeholders::_9,std::placeholders::_10);
}
template<> };
struct Placeholder<1>
{
static decltype(std::placeholders::_1) value() { return std::placeholders::_1; }
};
template<>
struct Placeholder<2>
{
static decltype(std::placeholders::_2) value() { return std::placeholders::_2; }
};
template<>
struct Placeholder<3>
{
static decltype(std::placeholders::_3) value() { return std::placeholders::_3; }
};
template<>
struct Placeholder<4>
{
static decltype(std::placeholders::_4) value() { return std::placeholders::_4; }
};
template<>
struct Placeholder<5>
{
static decltype(std::placeholders::_5) value() { return std::placeholders::_5; }
};
template<>
struct Placeholder<6>
{
static decltype(std::placeholders::_6) value() { return std::placeholders::_6; }
};
template<>
struct Placeholder<7>
{
static decltype(std::placeholders::_7) value() { return std::placeholders::_7; }
};
template<>
struct Placeholder<8>
{
static decltype(std::placeholders::_8) value() { return std::placeholders::_8; }
};
template<>
struct Placeholder<9>
{
static decltype(std::placeholders::_9) value() { return std::placeholders::_9; }
};
template<>
struct Placeholder<10>
{
static decltype(std::placeholders::_10) value() { return std::placeholders::_10; }
};
template<int count, int maxcount, typename Sig> template<int count, int maxcount, typename Sig>
struct Bind_First struct Bind_First
{ {
template<typename F, typename ... InnerParams> template<typename F, typename ... InnerParams>
static std::function<Sig> bind(F f, InnerParams ... innerparams) static std::function<Sig> bind(F&& f, InnerParams ... innerparams)
{ {
return Bind_First<count - 1, maxcount, Sig>::bind(f, innerparams..., Placeholder<maxcount - count + 1>::value()); return Bind_First<count - 1, maxcount, Sig>::bind(std::forward<F>(f), innerparams..., std::get<maxcount - count>(Placeholder::placeholder()));
} }
}; };
@@ -94,37 +35,42 @@ namespace chaiscript
struct Bind_First<0, maxcount, Sig> struct Bind_First<0, maxcount, Sig>
{ {
template<typename F, typename ... InnerParams> template<typename F, typename ... InnerParams>
static std::function<Sig> bind(F f, InnerParams ... innerparams) static std::function<Sig> bind(F&& f, InnerParams ... innerparams)
{ {
return std::bind(f, innerparams...); return std::bind(std::forward<F>(f), innerparams...);
} }
}; };
template<typename O, typename Ret, typename P1, typename ... Param> template<typename O, typename Ret, typename P1, typename ... Param>
std::function<Ret (Param...)> bind_first(Ret (*f)(P1, Param...), O o) std::function<Ret (Param...)> bind_first(Ret (*f)(P1, Param...), O&& o)
{ {
return Bind_First<sizeof...(Param), sizeof...(Param), Ret (Param...)>::bind(f, o); return Bind_First<sizeof...(Param), sizeof...(Param), Ret (Param...)>::bind(f, std::forward<O>(o));
} }
template<typename O, typename Ret, typename Class, typename ... Param> template<typename O, typename Ret, typename Class, typename ... Param>
std::function<Ret (Param...)> bind_first(Ret (Class::*f)(Param...), O o) std::function<Ret (Param...)> bind_first(Ret (Class::*f)(Param...), O&& o)
{ {
return Bind_First<sizeof...(Param), sizeof...(Param), Ret (Param...)>::bind(f, o); return Bind_First<sizeof...(Param), sizeof...(Param), Ret (Param...)>::bind(f, std::forward<O>(o));
} }
template<typename O, typename Ret, typename Class, typename ... Param> template<typename O, typename Ret, typename Class, typename ... Param>
std::function<Ret (Param...)> bind_first(Ret (Class::*f)(Param...) const, O o) std::function<Ret (Param...)> bind_first(Ret (Class::*f)(Param...) const, O&& o)
{ {
return Bind_First<sizeof...(Param), sizeof...(Param), Ret (Param...)>::bind(f, o); return Bind_First<sizeof...(Param), sizeof...(Param), Ret (Param...)>::bind(f, std::forward<O>(o));
} }
template<typename O, typename Ret, typename P1, typename ... Param> template<typename O, typename Ret, typename P1, typename ... Param>
std::function<Ret (Param...)> bind_first(const std::function<Ret (P1, Param...)> &f, O o) std::function<Ret (Param...)> bind_first(const std::function<Ret (P1, Param...)> &f, O&& o)
{ {
return Bind_First<sizeof...(Param), sizeof...(Param), Ret (Param...)>::bind(f, o); return Bind_First<sizeof...(Param), sizeof...(Param), Ret (Param...)>::bind(f, std::forward<O>(o));
} }
template<typename O, typename Ret, typename P1, typename ... Param>
std::function<Ret (Param...)> bind_first(std::function<Ret (P1, Param...)> &&f, O&& o)
{
return Bind_First<sizeof...(Param), sizeof...(Param), Ret (Param...)>::bind(std::move(f), std::forward<O>(o));
}
} }
} }

View File

@@ -7,13 +7,33 @@
#ifndef CHAISCRIPT_BOOTSTRAP_HPP_ #ifndef CHAISCRIPT_BOOTSTRAP_HPP_
#define CHAISCRIPT_BOOTSTRAP_HPP_ #define CHAISCRIPT_BOOTSTRAP_HPP_
#include "dispatchkit.hpp" #include <cstdint>
#include "dynamic_object.hpp" #include <exception>
#include "register_function.hpp" #include <functional>
#include "operators.hpp" #include <iostream>
#include "boxed_number.hpp" #include <map>
#include <memory>
#include <sstream> #include <sstream>
#include <stdexcept>
#include <string>
#include <type_traits> #include <type_traits>
#include <vector>
#include "bad_boxed_cast.hpp"
#include "boxed_cast.hpp"
#include "boxed_number.hpp"
#include "boxed_value.hpp"
#include "dispatchkit.hpp"
#include "type_conversions.hpp"
#include "dynamic_object.hpp"
#include "operators.hpp"
#include "proxy_constructors.hpp"
#include "proxy_functions.hpp"
#include "proxy_functions_detail.hpp"
#include "register_function.hpp"
#include "type_info.hpp"
#include "../utility/utility.hpp"
#include "../language/chaiscript_common.hpp"
namespace chaiscript namespace chaiscript
{ {
@@ -26,13 +46,9 @@ namespace chaiscript
/// \param[in] v Boxed_Number to copy into the new object /// \param[in] v Boxed_Number to copy into the new object
/// \returns The newly created object. /// \returns The newly created object.
template<typename P1> template<typename P1>
std::shared_ptr<P1> construct_pod(Boxed_Number v) std::shared_ptr<P1> construct_pod(const Boxed_Number &v)
{ {
std::shared_ptr<P1> p(new P1()); return std::make_shared<P1>(v.get_as<P1>());
Boxed_Value bv(p);
Boxed_Number nb(bv);
nb = v;
return p;
} }
} }
@@ -93,9 +109,7 @@ namespace chaiscript
} }
/** /// to_string function for internal use. Uses ostream operator<<
* to_string function for internal use. Uses ostream operator<<
*/
template<typename Input> template<typename Input>
std::string to_string(Input i) std::string to_string(Input i)
{ {
@@ -104,10 +118,8 @@ namespace chaiscript
return ss.str(); return ss.str();
} }
/** /// Internal function for converting from a string to a value
* Internal function for converting from a string to a value /// uses ostream operator >> to perform the conversion
* uses ostream operator >> to perform the conversion
*/
template<typename Input> template<typename Input>
Input parse_string(const std::string &i) Input parse_string(const std::string &i)
{ {
@@ -116,12 +128,10 @@ namespace chaiscript
ss >> t; ss >> t;
return t; return t;
} }
/** /// Add all common functions for a POD type. All operators, and
* Add all common functions for a POD type. All operators, and /// common conversions
* common conversions
*/
template<typename T> template<typename T>
ModulePtr bootstrap_pod_type(const std::string &name, ModulePtr m = ModulePtr(new Module())) ModulePtr bootstrap_pod_type(const std::string &name, ModulePtr m = ModulePtr(new Module()))
{ {
@@ -135,22 +145,18 @@ namespace chaiscript
} }
/** /// "clone" function for a shared_ptr type. This is used in the case
* "clone" function for a shared_ptr type. This is used in the case /// where you do not want to make a deep copy of an object during cloning
* where you do not want to make a deep copy of an object during cloning /// but want to instead maintain the shared_ptr. It is needed internally
* but want to instead maintain the shared_ptr. It is needed internally /// for handling of Proxy_Function object (that is,
* for handling of Proxy_Function object (that is, /// function variables.
* function variables.
*/
template<typename Type> template<typename Type>
std::shared_ptr<Type> shared_ptr_clone(const std::shared_ptr<Type> &p) std::shared_ptr<Type> shared_ptr_clone(const std::shared_ptr<Type> &p)
{ {
return p; return p;
} }
/** /// Specific version of shared_ptr_clone just for Proxy_Functions
* Specific version of shared_ptr_clone just for Proxy_Functions
*/
template<typename Type> template<typename Type>
std::shared_ptr<typename std::remove_const<Type>::type> std::shared_ptr<typename std::remove_const<Type>::type>
shared_ptr_unconst_clone(const std::shared_ptr<typename std::add_const<Type>::type> &p) shared_ptr_unconst_clone(const std::shared_ptr<typename std::add_const<Type>::type> &p)
@@ -160,11 +166,9 @@ namespace chaiscript
/** /// Assignment function for shared_ptr objects, does not perform a copy of the
* Assignment function for shared_ptr objects, does not perform a copy of the /// object pointed to, instead maintains the shared_ptr concept.
* object pointed to, instead maintains the shared_ptr concept. /// Similar to shared_ptr_clone. Used for Proxy_Function.
* Similar to shared_ptr_clone. Used for Proxy_Function.
*/
template<typename Type> template<typename Type>
Boxed_Value ptr_assign(Boxed_Value lhs, const std::shared_ptr<Type> &rhs) Boxed_Value ptr_assign(Boxed_Value lhs, const std::shared_ptr<Type> &rhs)
{ {
@@ -178,10 +182,8 @@ namespace chaiscript
} }
} }
/** /// Class consisting of only static functions. All default bootstrapping occurs
* Class consisting of only static functions. All default bootstrapping occurs /// from this class.
* from this class.
*/
class Bootstrap class Bootstrap
{ {
private: private:
@@ -200,18 +202,16 @@ namespace chaiscript
static void print(const std::string &s) static void print(const std::string &s)
{ {
std::cout << s; fwrite(s.c_str(), 1, s.size(), stdout);
} }
static void println(const std::string &s) static void println(const std::string &s)
{ {
std::cout << s << std::endl; puts(s.c_str());
} }
/** /// Add all arithmetic operators for PODs
* Add all arithmetic operators for PODs
*/
static void opers_arithmetic_pod(ModulePtr m = ModulePtr(new Module())) static void opers_arithmetic_pod(ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun(&Boxed_Number::equals), "=="); m->add(fun(&Boxed_Number::equals), "==");
@@ -251,11 +251,8 @@ namespace chaiscript
} }
/** /// Create a bound function object. The first param is the function to bind
* Create a bound function object. The first param is the function to bind /// the remaining parameters are the args to bind into the result
* the remaining parameters are the args to bind into the
* result
*/
static Boxed_Value bind_function(const std::vector<Boxed_Value> &params) static Boxed_Value bind_function(const std::vector<Boxed_Value> &params)
{ {
if (params.size() < 2) if (params.size() < 2)
@@ -265,7 +262,7 @@ namespace chaiscript
Const_Proxy_Function f = boxed_cast<Const_Proxy_Function>(params[0]); Const_Proxy_Function f = boxed_cast<Const_Proxy_Function>(params[0]);
return Boxed_Value(Const_Proxy_Function(new dispatch::Bound_Function(f, return Boxed_Value(Const_Proxy_Function(std::make_shared<dispatch::Bound_Function>(f,
std::vector<Boxed_Value>(params.begin() + 1, params.end())))); std::vector<Boxed_Value>(params.begin() + 1, params.end()))));
} }
@@ -304,23 +301,13 @@ namespace chaiscript
static void throw_exception(const Boxed_Value &bv) { static void throw_exception(const Boxed_Value &bv) {
throw bv; throw bv;
} }
static std::shared_ptr<chaiscript::detail::Dispatch_Engine> bootstrap2(
std::shared_ptr<chaiscript::detail::Dispatch_Engine> e
= std::shared_ptr<chaiscript::detail::Dispatch_Engine> (new chaiscript::detail::Dispatch_Engine()))
{
e->add(user_type<void>(), "void");
return e;
}
static std::string what(const std::exception &e) static std::string what(const std::exception &e)
{ {
return e.what(); return e.what();
} }
/** /// Boolean specialization of internal to_string function
* Boolean specialization of internal to_string function
*/
static std::string bool_to_string(bool b) static std::string bool_to_string(bool b)
{ {
if (b) if (b)
@@ -347,12 +334,44 @@ namespace chaiscript
return vbv; return vbv;
} }
static bool has_parse_tree(const chaiscript::Const_Proxy_Function &t_pf)
{
if (auto pf = std::dynamic_pointer_cast<const chaiscript::dispatch::Dynamic_Proxy_Function>(t_pf))
{
if (pf->get_parse_tree())
{
return true;
} else {
return false;
}
} else {
return false;
}
}
static chaiscript::AST_NodePtr get_parse_tree(const chaiscript::Const_Proxy_Function &t_pf)
{
if (auto pf = std::dynamic_pointer_cast<const chaiscript::dispatch::Dynamic_Proxy_Function>(t_pf))
{
if (pf->get_parse_tree())
{
return pf->get_parse_tree();
} else {
throw std::runtime_error("Function does not have a parse tree");
}
} else {
throw std::runtime_error("Function does not have a parse tree");
}
}
template<typename Function> template<typename Function>
static std::function<std::vector<Boxed_Value> (const dispatch::Proxy_Function_Base*)> return_boxed_value_vector(const Function &f) static std::function<std::vector<Boxed_Value> (const dispatch::Proxy_Function_Base*)> return_boxed_value_vector(const Function &f)
{ {
return std::bind(&do_return_boxed_value_vector<Function>, f, std::placeholders::_1); return std::bind(&do_return_boxed_value_vector<Function>, f, std::placeholders::_1);
} }
public: public:
/// \brief perform all common bootstrap functions for std::string, void and POD types /// \brief perform all common bootstrap functions for std::string, void and POD types
/// \param[in,out] m Module to add bootstrapped functions to /// \param[in,out] m Module to add bootstrapped functions to
@@ -370,7 +389,7 @@ namespace chaiscript
m->add(fun(&dispatch::Proxy_Function_Base::annotation), "get_annotation"); m->add(fun(&dispatch::Proxy_Function_Base::annotation), "get_annotation");
m->add(fun(&dispatch::Proxy_Function_Base::operator==), "=="); m->add(fun(&dispatch::Proxy_Function_Base::operator==), "==");
m->add(fun(return_boxed_value_vector(&dispatch::Proxy_Function_Base::get_param_types)), "get_param_types"); m->add(fun(return_boxed_value_vector(&dispatch::Proxy_Function_Base::get_param_types)), "get_param_types");
m->add(fun(return_boxed_value_vector(&dispatch::Proxy_Function_Base::get_contained_functions)), "get_contained_functions"); m->add(fun(return_boxed_value_vector(&dispatch::Proxy_Function_Base::get_contained_functions)), "get_contained_functions");
@@ -399,9 +418,12 @@ namespace chaiscript
m->add(fun(&Boxed_Value::is_ref), "is_var_reference"); m->add(fun(&Boxed_Value::is_ref), "is_var_reference");
m->add(fun(&Boxed_Value::is_pointer), "is_var_pointer"); m->add(fun(&Boxed_Value::is_pointer), "is_var_pointer");
m->add(fun(&Boxed_Value::is_type), "is_type"); m->add(fun(&Boxed_Value::is_type), "is_type");
m->add(fun(&Boxed_Value::get_attr), "get_var_attr");
m->add(fun(&Boxed_Value::copy_attrs), "copy_var_attrs");
m->add(fun(&Boxed_Value::get_type_info), "get_type_info"); m->add(fun(&Boxed_Value::get_type_info), "get_type_info");
m->add(user_type<Type_Info>(), "Type_Info"); m->add(user_type<Type_Info>(), "Type_Info");
m->add(constructor<Type_Info (const Type_Info &)>(), "Type_Info");
operators::equal<Type_Info>(m); operators::equal<Type_Info>(m);
@@ -421,8 +443,8 @@ namespace chaiscript
operators::assign<bool>(m); operators::assign<bool>(m);
operators::equal<bool>(m); operators::equal<bool>(m);
m->add(fun(&to_string<const std::string &>), "internal_to_string"); m->add(fun<std::string (const std::string &t_ss)>([](const std::string &s) -> std::string { return s; }), "to_string");
m->add(fun(&Bootstrap::bool_to_string), "internal_to_string"); m->add(fun(&Bootstrap::bool_to_string), "to_string");
m->add(fun(&unknown_assign), "="); m->add(fun(&unknown_assign), "=");
m->add(fun(&throw_exception), "throw"); m->add(fun(&throw_exception), "throw");
m->add(fun(&what), "what"); m->add(fun(&what), "what");
@@ -453,8 +475,7 @@ namespace chaiscript
m->add(fun(&print), "print_string"); m->add(fun(&print), "print_string");
m->add(fun(&println), "println_string"); m->add(fun(&println), "println_string");
m->add(Proxy_Function(new dispatch::Dynamic_Proxy_Function(std::bind(&bind_function, std::placeholders::_1))), m->add(Proxy_Function(new dispatch::Dynamic_Proxy_Function(&bind_function)), "bind");
"bind");
m->add(fun(&shared_ptr_unconst_clone<dispatch::Proxy_Function_Base>), "clone"); m->add(fun(&shared_ptr_unconst_clone<dispatch::Proxy_Function_Base>), "clone");
m->add(fun(&ptr_assign<std::remove_const<dispatch::Proxy_Function_Base>::type>), "="); m->add(fun(&ptr_assign<std::remove_const<dispatch::Proxy_Function_Base>::type>), "=");
@@ -462,6 +483,68 @@ namespace chaiscript
m->add(fun(&Boxed_Value::type_match), "type_match"); m->add(fun(&Boxed_Value::type_match), "type_match");
m->add(chaiscript::fun(&has_parse_tree), "has_parse_tree");
m->add(chaiscript::fun(&get_parse_tree), "get_parse_tree");
m->add(chaiscript::base_class<std::exception, chaiscript::exception::eval_error>());
// chaiscript::bootstrap::standard_library::vector_type<std::vector<std::shared_ptr<chaiscript::AST_Node> > >("AST_NodeVector", m);
chaiscript::utility::add_class<chaiscript::exception::eval_error>(*m,
"eval_error",
{ },
{ {fun(&chaiscript::exception::eval_error::reason), "reason"},
{fun(std::function<std::vector<Boxed_Value> (const chaiscript::exception::eval_error &t_eval_error)>([](const chaiscript::exception::eval_error &t_eval_error) -> std::vector<Boxed_Value> {
std::vector<Boxed_Value> retval;
std::transform(t_eval_error.call_stack.begin(), t_eval_error.call_stack.end(),
std::back_inserter(retval),
&chaiscript::var<std::shared_ptr<const chaiscript::AST_Node>>);
return retval;
})), "call_stack"} }
);
chaiscript::utility::add_class<chaiscript::File_Position>(*m,
"File_Position",
{ constructor<File_Position()>(),
constructor<File_Position(int, int)>() },
{ {fun(&File_Position::line), "line"},
{fun(&File_Position::column), "column"} }
);
chaiscript::utility::add_class<AST_Node>(*m,
"AST_Node",
{ },
{ {fun(&AST_Node::text), "text"},
{fun(&AST_Node::identifier), "identifier"},
{fun(&AST_Node::filename), "filename"},
{fun(&AST_Node::start), "start"},
{fun(&AST_Node::end), "end"},
{fun(&AST_Node::to_string), "to_string"},
{fun(std::function<std::vector<Boxed_Value> (const chaiscript::AST_Node &t_node)>([](const chaiscript::AST_Node &t_node) -> std::vector<Boxed_Value> {
std::vector<Boxed_Value> retval;
std::transform(t_node.children.begin(), t_node.children.end(),
std::back_inserter(retval),
&chaiscript::var<std::shared_ptr<chaiscript::AST_Node>>);
return retval;
})), "children"},
{fun(&AST_Node::replace_child), "replace_child"}
}
);
chaiscript::utility::add_class<parser::ChaiScript_Parser>(*m,
"ChaiScript_Parser",
{ constructor<parser::ChaiScript_Parser ()>() },
{ {fun(&parser::ChaiScript_Parser::parse), "parse"},
{fun(&parser::ChaiScript_Parser::ast), "ast"} }
);
return m; return m;
} }
}; };

View File

@@ -13,9 +13,21 @@
#ifndef CHAISCRIPT_BOOTSTRAP_STL_HPP_ #ifndef CHAISCRIPT_BOOTSTRAP_STL_HPP_
#define CHAISCRIPT_BOOTSTRAP_STL_HPP_ #define CHAISCRIPT_BOOTSTRAP_STL_HPP_
#include "dispatchkit.hpp" #include <functional>
#include <iterator>
#include <memory>
#include <stdexcept>
#include <string>
#include <typeinfo>
#include <vector>
#include "bootstrap.hpp" #include "bootstrap.hpp"
#include "boxed_value.hpp"
#include "dispatchkit.hpp"
#include "operators.hpp"
#include "proxy_constructors.hpp"
#include "register_function.hpp" #include "register_function.hpp"
#include "type_info.hpp"
namespace chaiscript namespace chaiscript
{ {
@@ -173,7 +185,7 @@ namespace chaiscript
copy_constructor<Bidir_Type>(type + "_Range", m); copy_constructor<Bidir_Type>(type + "_Range", m);
m->add(constructor<Bidir_Type (typename Bidir_Type::container_type &)>(), "range"); m->add(constructor<Bidir_Type (typename Bidir_Type::container_type &)>(), "range_internal");
m->add(fun(&Bidir_Type::empty), "empty"); m->add(fun(&Bidir_Type::empty), "empty");
m->add(fun(&Bidir_Type::pop_front), "pop_front"); m->add(fun(&Bidir_Type::pop_front), "pop_front");
@@ -189,8 +201,8 @@ namespace chaiscript
template<typename Type> 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(); auto itr = container.begin();
typename Type::iterator end = container.end(); auto end = container.end();
if (pos < 0 || std::distance(itr, end) < pos) if (pos < 0 || std::distance(itr, end) < pos)
{ {
@@ -206,8 +218,8 @@ namespace chaiscript
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(); auto itr = container.begin();
typename Type::iterator end = container.end(); auto end = container.end();
if (pos < 0 || std::distance(itr, end) < (pos-1)) if (pos < 0 || std::distance(itr, end) < (pos-1))
{ {
@@ -217,7 +229,7 @@ namespace chaiscript
std::advance(itr, pos); std::advance(itr, pos);
container.erase(itr); container.erase(itr);
} }
} }
template<typename ContainerType> template<typename ContainerType>
@@ -266,9 +278,9 @@ namespace chaiscript
template<typename ContainerType> template<typename ContainerType>
ModulePtr container_type(const std::string &/*type*/, ModulePtr m = ModulePtr(new Module())) ModulePtr container_type(const std::string &/*type*/, ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun( std::function<size_t (const ContainerType *)>( [](const ContainerType *a) { return a->size(); } ) ), "size"); m->add(fun<size_t (const ContainerType *)>([](const ContainerType *a) { return a->size(); } ), "size");
m->add(fun( std::function<bool (const ContainerType *)>( [](const ContainerType *a) { return a->empty(); } ) ), "empty"); m->add(fun<bool (const ContainerType *)>([](const ContainerType *a) { return a->empty(); } ), "empty");
m->add(fun( std::function<void (ContainerType *)>( [](ContainerType *a) { a->clear(); } ) ), "clear"); m->add(fun<void (ContainerType *)>([](ContainerType *a) { a->clear(); } ), "clear");
return m; return m;
} }
@@ -322,8 +334,8 @@ namespace chaiscript
push_back_name = "push_back"; push_back_name = "push_back";
} }
typedef void (ContainerType::*pushback)(const typename ContainerType::value_type &); typedef void (ContainerType::*push_back)(const typename ContainerType::value_type &);
m->add(fun(static_cast<pushback>(&ContainerType::push_back)), push_back_name); m->add(fun(static_cast<push_back>(&ContainerType::push_back)), push_back_name);
m->add(fun(&ContainerType::pop_back), "pop_back"); m->add(fun(&ContainerType::pop_back), "pop_back");
return m; return m;
} }
@@ -336,10 +348,12 @@ namespace chaiscript
ModulePtr front_insertion_sequence_type(const std::string &, ModulePtr m = ModulePtr(new Module())) ModulePtr front_insertion_sequence_type(const std::string &, ModulePtr m = ModulePtr(new Module()))
{ {
typedef typename ContainerType::reference (ContainerType::*frontptr)(); typedef typename ContainerType::reference (ContainerType::*frontptr)();
typedef typename ContainerType::const_reference (ContainerType::*constfrontptr)() const;
typedef void (ContainerType::*pushptr)(typename ContainerType::const_reference); typedef void (ContainerType::*pushptr)(typename ContainerType::const_reference);
typedef void (ContainerType::*popptr)(); typedef void (ContainerType::*popptr)();
m->add(fun(static_cast<frontptr>(&ContainerType::front)), "front"); m->add(fun(static_cast<frontptr>(&ContainerType::front)), "front");
m->add(fun(static_cast<constfrontptr>(&ContainerType::front)), "front");
std::string push_front_name; std::string push_front_name;
if (typeid(typename ContainerType::value_type) == typeid(Boxed_Value)) if (typeid(typename ContainerType::value_type) == typeid(Boxed_Value))
@@ -463,7 +477,10 @@ namespace chaiscript
m->add(user_type<VectorType>(), type); m->add(user_type<VectorType>(), type);
typedef typename VectorType::reference (VectorType::*frontptr)(); typedef typename VectorType::reference (VectorType::*frontptr)();
typedef typename VectorType::const_reference (VectorType::*constfrontptr)() const;
m->add(fun(static_cast<frontptr>(&VectorType::front)), "front"); m->add(fun(static_cast<frontptr>(&VectorType::front)), "front");
m->add(fun(static_cast<constfrontptr>(&VectorType::front)), "front");
back_insertion_sequence_type<VectorType>(type, m); back_insertion_sequence_type<VectorType>(type, m);
@@ -476,24 +493,26 @@ namespace chaiscript
if (typeid(VectorType) == typeid(std::vector<Boxed_Value>)) if (typeid(VectorType) == typeid(std::vector<Boxed_Value>))
{ {
m->eval("def Vector::`==`(rhs) : type_match(rhs, this) { \ m->eval(R"(
if ( rhs.size() != this.size() ) { \ def Vector::`==`(rhs) : type_match(rhs, this) {
return false; \ if ( rhs.size() != this.size() ) {
} else { \ return false;
auto r1 = range(this); \ } else {
auto r2 = range(rhs); \ auto r1 = range(this);
while (!r1.empty()) \ auto r2 = range(rhs);
{ \ while (!r1.empty())
if (!eq(r1.front(), r2.front())) \ {
{ \ if (!eq(r1.front(), r2.front()))
return false; \ {
} \ return false;
r1.pop_front(); \ }
r2.pop_front(); \ r1.pop_front();
} \ r2.pop_front();
return true; \ }
} \ true;
}"); }
} )"
);
} }
return m; return m;
@@ -535,13 +554,13 @@ namespace chaiscript
m->add(fun(find_func( [](const String *s, const String &f, size_t pos) { return s->find_last_not_of(f, pos); } ) ), "find_last_not_of"); m->add(fun(find_func( [](const String *s, const String &f, size_t pos) { return s->find_last_not_of(f, pos); } ) ), "find_last_not_of");
m->add(fun(find_func( [](const String *s, const String &f, size_t pos) { return s->find_first_not_of(f, pos); } ) ), "find_first_not_of"); m->add(fun(find_func( [](const String *s, const String &f, size_t pos) { return s->find_first_not_of(f, pos); } ) ), "find_first_not_of");
m->add(fun( std::function<void (String *)>( [](String *s) { return s->clear(); } ) ), "clear"); m->add(fun( std::function<void (String *)>( [](String *s) { return s->clear(); } ) ), "clear");
m->add(fun( std::function<bool (const String *)>( [](const String *s) { return s->empty(); } ) ), "empty"); m->add(fun( std::function<bool (const String *)>( [](const String *s) { return s->empty(); } ) ), "empty");
m->add(fun( std::function<size_t (const String *)>( [](const String *s) { return s->size(); } ) ), "size"); m->add(fun( std::function<size_t (const String *)>( [](const String *s) { return s->size(); } ) ), "size");
m->add(fun( std::function<const char *(const String *)>( [](const String *s) { return s->c_str(); } ) ), "c_str"); m->add(fun( std::function<const char *(const String *)>( [](const String *s) { return s->c_str(); } ) ), "c_str");
m->add(fun( std::function<const char *(const String *)>( [](const String *s) { return s->data(); } ) ), "data"); m->add(fun( std::function<const char *(const String *)>( [](const String *s) { return s->data(); } ) ), "data");
m->add(fun( std::function<String (const String *, int, int)>( [](const String *s, int pos, int len) { return s->substr(pos, len); } ) ), "substr"); m->add(fun( std::function<String (const String *, size_t, size_t)>( [](const String *s, size_t pos, size_t len) { return s->substr(pos, len); } ) ), "substr");
return m; return m;
} }

View File

@@ -7,14 +7,24 @@
#ifndef CHAISCRIPT_BOXED_CAST_HPP_ #ifndef CHAISCRIPT_BOXED_CAST_HPP_
#define CHAISCRIPT_BOXED_CAST_HPP_ #define CHAISCRIPT_BOXED_CAST_HPP_
#include <type_traits>
#include "../chaiscript_defines.hpp" #include "../chaiscript_defines.hpp"
#include "type_info.hpp"
#include "boxed_value.hpp"
#include "boxed_cast_helper.hpp"
#include "dynamic_cast_conversion.hpp"
#include "../chaiscript_threading.hpp" #include "../chaiscript_threading.hpp"
#include "bad_boxed_cast.hpp"
#include "boxed_cast_helper.hpp"
#include "boxed_value.hpp"
#include "type_conversions.hpp"
#include "type_info.hpp"
namespace chaiscript {
class Type_Conversions;
namespace detail {
namespace exception {
class bad_any_cast;
} // namespace exception
} // namespace detail
} // namespace chaiscript
namespace chaiscript namespace chaiscript
{ {
@@ -62,7 +72,7 @@ namespace chaiscript
/// assert(i == 5); /// assert(i == 5);
/// \endcode /// \endcode
template<typename Type> template<typename Type>
typename detail::Cast_Helper<Type>::Result_Type boxed_cast(const Boxed_Value &bv, const Dynamic_Cast_Conversions *t_conversions = nullptr) typename detail::Cast_Helper<Type>::Result_Type boxed_cast(const Boxed_Value &bv, const Type_Conversions *t_conversions = nullptr)
{ {
try { try {
return detail::Cast_Helper<Type>::cast(bv, t_conversions); return detail::Cast_Helper<Type>::cast(bv, t_conversions);
@@ -76,14 +86,21 @@ namespace chaiscript
#pragma warning(disable : 4127) #pragma warning(disable : 4127)
#endif #endif
if (std::is_polymorphic<typename detail::Stripped_Type<Type>::type>::value && t_conversions) if (t_conversions && t_conversions->convertable_type<Type>())
{ {
try { try {
// std::cout << "trying an up conversion " << typeid(Type).name() << '\n';
// We will not catch any bad_boxed_dynamic_cast that is thrown, let the user get it // We will not catch any bad_boxed_dynamic_cast that is thrown, let the user get it
// either way, we are not responsible if it doesn't work // either way, we are not responsible if it doesn't work
return detail::Cast_Helper<Type>::cast(t_conversions->boxed_dynamic_cast<Type>(bv), t_conversions); return detail::Cast_Helper<Type>::cast(t_conversions->boxed_type_conversion<Type>(bv), t_conversions);
} catch (const chaiscript::detail::exception::bad_any_cast &) { } catch (...) {
throw exception::bad_boxed_cast(bv.get_type_info(), typeid(Type)); try {
// std::cout << "trying a down conversion " << typeid(Type).name() << '\n';
// try going the other way - down the inheritance graph
return detail::Cast_Helper<Type>::cast(t_conversions->boxed_type_down_conversion<Type>(bv), t_conversions);
} catch (const chaiscript::detail::exception::bad_any_cast &) {
throw exception::bad_boxed_cast(bv.get_type_info(), typeid(Type));
}
} }
} else { } else {
// If it's not polymorphic, just throw the error, don't waste the time on the // If it's not polymorphic, just throw the error, don't waste the time on the

View File

@@ -7,69 +7,63 @@
#ifndef CHAISCRIPT_BOXED_CAST_HELPER_HPP_ #ifndef CHAISCRIPT_BOXED_CAST_HELPER_HPP_
#define CHAISCRIPT_BOXED_CAST_HELPER_HPP_ #define CHAISCRIPT_BOXED_CAST_HELPER_HPP_
#include "type_info.hpp" #include <functional>
#include <memory>
#include <type_traits>
#include "boxed_value.hpp" #include "boxed_value.hpp"
#include "type_info.hpp"
namespace chaiscript namespace chaiscript
{ {
class Dynamic_Cast_Conversions; class Type_Conversions;
namespace detail namespace detail
{ {
// Cast_Helper_Inner helper classes // Cast_Helper_Inner helper classes
/** template<typename T>
* Generic Cast_Helper_Inner, for casting to any type T* throw_if_null(T *t)
*/ {
if (t) return t;
throw std::runtime_error("Attempted to dereference null Boxed_Value");
}
/// Generic Cast_Helper_Inner, for casting to any type
template<typename Result> template<typename Result>
struct Cast_Helper_Inner struct Cast_Helper_Inner
{ {
typedef typename std::reference_wrapper<typename std::add_const<Result>::type > Result_Type; typedef typename std::reference_wrapper<typename std::add_const<Result>::type > Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *) static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *)
{ {
if (ob.is_ref()) if (ob.get_type_info().bare_equal_type_info(typeid(Result)))
{ {
if (!ob.get_type_info().is_const()) return *(static_cast<const Result *>(throw_if_null(ob.get_const_ptr())));
{
return std::cref((ob.get().cast<std::reference_wrapper<Result> >()).get());
} else {
return ob.get().cast<std::reference_wrapper<const Result> >();
}
} else { } else {
if (!ob.get_type_info().is_const()) throw chaiscript::detail::exception::bad_any_cast();
{
return std::cref(*(ob.get().cast<std::shared_ptr<Result> >()));
} else {
return std::cref(*(ob.get().cast<std::shared_ptr<const Result> >()));
}
} }
} }
}; };
template<typename Result> template<typename Result>
struct Cast_Helper_Inner<const Result> : Cast_Helper_Inner<Result> struct Cast_Helper_Inner<const Result> : Cast_Helper_Inner<Result>
{ {
}; };
/** /// Cast_Helper_Inner for casting to a const & type
* Cast_Helper_Inner for casting to a const & type
*/
template<typename Result> template<typename Result>
struct Cast_Helper_Inner<const Result &> : Cast_Helper_Inner<Result> struct Cast_Helper_Inner<const Result &> : Cast_Helper_Inner<Result>
{ {
}; };
/** /// Cast_Helper_Inner for casting to a const * type
* Cast_Helper_Inner for casting to a const * type
*/
template<typename Result> template<typename Result>
struct Cast_Helper_Inner<const Result *> struct Cast_Helper_Inner<const Result *>
{ {
typedef const Result * Result_Type; typedef const Result * Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *)
static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *)
{ {
if (ob.is_ref()) if (ob.is_ref())
{ {
@@ -90,15 +84,12 @@ namespace chaiscript
} }
}; };
/** /// Cast_Helper_Inner for casting to a * type
* Cast_Helper_Inner for casting to a * type
*/
template<typename Result> template<typename Result>
struct Cast_Helper_Inner<Result *> struct Cast_Helper_Inner<Result *>
{ {
typedef Result * Result_Type; typedef Result * Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *)
static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *)
{ {
if (ob.is_ref()) if (ob.is_ref())
{ {
@@ -109,49 +100,43 @@ namespace chaiscript
} }
}; };
/**
* Cast_Helper_Inner for casting to a & type /// Cast_Helper_Inner for casting to a & type
*/
template<typename Result> template<typename Result>
struct Cast_Helper_Inner<Result &> struct Cast_Helper_Inner<Result &>
{ {
typedef Result& Result_Type; typedef Result& Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *) static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *)
{ {
if (ob.is_ref()) if (!ob.get_type_info().is_const() && ob.get_type_info().bare_equal_type_info(typeid(Result)))
{ {
return ob.get().cast<std::reference_wrapper<Result> >(); return *(static_cast<Result *>(throw_if_null(ob.get_ptr())));
} else { } else {
Result &r = *(ob.get().cast<std::shared_ptr<Result> >()); throw chaiscript::detail::exception::bad_any_cast();
return r;
} }
} }
}; };
/** /// Cast_Helper_Inner for casting to a std::shared_ptr<> type
* Cast_Helper_Inner for casting to a std::shared_ptr<> type
*/
template<typename Result> template<typename Result>
struct Cast_Helper_Inner<typename std::shared_ptr<Result> > struct Cast_Helper_Inner<typename std::shared_ptr<Result> >
{ {
typedef typename std::shared_ptr<Result> Result_Type; typedef typename std::shared_ptr<Result> Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *) static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *)
{ {
return ob.get().cast<std::shared_ptr<Result> >(); return ob.get().cast<std::shared_ptr<Result> >();
} }
}; };
/** /// Cast_Helper_Inner for casting to a std::shared_ptr<const> type
* Cast_Helper_Inner for casting to a std::shared_ptr<const> type
*/
template<typename Result> template<typename Result>
struct Cast_Helper_Inner<typename std::shared_ptr<const Result> > struct Cast_Helper_Inner<typename std::shared_ptr<const Result> >
{ {
typedef typename std::shared_ptr<const Result> Result_Type; typedef typename std::shared_ptr<const Result> Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *) static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *)
{ {
if (!ob.get_type_info().is_const()) if (!ob.get_type_info().is_const())
{ {
@@ -162,9 +147,7 @@ namespace chaiscript
} }
}; };
/** /// Cast_Helper_Inner for casting to a const std::shared_ptr<> & type
* Cast_Helper_Inner for casting to a const std::shared_ptr<> & type
*/
template<typename Result> template<typename Result>
struct Cast_Helper_Inner<const std::shared_ptr<Result> > : Cast_Helper_Inner<std::shared_ptr<Result> > struct Cast_Helper_Inner<const std::shared_ptr<Result> > : Cast_Helper_Inner<std::shared_ptr<Result> >
{ {
@@ -176,9 +159,7 @@ namespace chaiscript
}; };
/** /// Cast_Helper_Inner for casting to a const std::shared_ptr<const> & type
* Cast_Helper_Inner for casting to a const std::shared_ptr<const> & type
*/
template<typename Result> template<typename Result>
struct Cast_Helper_Inner<const std::shared_ptr<const Result> > : Cast_Helper_Inner<std::shared_ptr<const Result> > struct Cast_Helper_Inner<const std::shared_ptr<const Result> > : Cast_Helper_Inner<std::shared_ptr<const Result> >
{ {
@@ -191,23 +172,32 @@ namespace chaiscript
/** /// Cast_Helper_Inner for casting to a Boxed_Value type
* Cast_Helper_Inner for casting to a Boxed_Value type
*/
template<> template<>
struct Cast_Helper_Inner<Boxed_Value> struct Cast_Helper_Inner<Boxed_Value>
{ {
typedef const Boxed_Value & Result_Type; typedef const Boxed_Value & Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *) static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *)
{ {
return ob; return ob;
} }
}; };
/** /// Cast_Helper_Inner for casting to a Boxed_Value & type
* Cast_Helper_Inner for casting to a const Boxed_Value & type template<>
*/ struct Cast_Helper_Inner<Boxed_Value &>
{
typedef Boxed_Value& Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *)
{
return const_cast<Boxed_Value &>(ob);
}
};
/// Cast_Helper_Inner for casting to a const Boxed_Value & type
template<> template<>
struct Cast_Helper_Inner<const Boxed_Value> : Cast_Helper_Inner<Boxed_Value> struct Cast_Helper_Inner<const Boxed_Value> : Cast_Helper_Inner<Boxed_Value>
{ {
@@ -217,11 +207,9 @@ namespace chaiscript
struct Cast_Helper_Inner<const Boxed_Value &> : Cast_Helper_Inner<Boxed_Value> struct Cast_Helper_Inner<const Boxed_Value &> : Cast_Helper_Inner<Boxed_Value>
{ {
}; };
/**
* Cast_Helper_Inner for casting to a std::reference_wrapper type /// Cast_Helper_Inner for casting to a std::reference_wrapper type
*/
template<typename Result> template<typename Result>
struct Cast_Helper_Inner<std::reference_wrapper<Result> > : Cast_Helper_Inner<Result &> struct Cast_Helper_Inner<std::reference_wrapper<Result> > : Cast_Helper_Inner<Result &>
{ {
@@ -252,15 +240,13 @@ namespace chaiscript
{ {
}; };
/** /// The exposed Cast_Helper object that by default just calls the Cast_Helper_Inner
* The exposed Cast_Helper object that by default just calls the Cast_Helper_Inner
*/
template<typename T> template<typename T>
struct Cast_Helper struct Cast_Helper
{ {
typedef typename Cast_Helper_Inner<T>::Result_Type Result_Type; typedef typename Cast_Helper_Inner<T>::Result_Type Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *t_conversions) static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *t_conversions)
{ {
return Cast_Helper_Inner<T>::cast(ob, t_conversions); return Cast_Helper_Inner<T>::cast(ob, t_conversions);
} }

View File

@@ -7,17 +7,30 @@
#ifndef CHAISCRIPT_BOXED_NUMERIC_HPP_ #ifndef CHAISCRIPT_BOXED_NUMERIC_HPP_
#define CHAISCRIPT_BOXED_NUMERIC_HPP_ #define CHAISCRIPT_BOXED_NUMERIC_HPP_
#include "boxed_value.hpp"
#include "../language/chaiscript_algebraic.hpp"
#include <sstream>
#include <cstdint> #include <cstdint>
#include <sstream>
#include <string>
#include "../language/chaiscript_algebraic.hpp"
#include "any.hpp"
#include "boxed_cast.hpp"
#include "boxed_cast_helper.hpp"
#include "boxed_value.hpp"
#include "type_info.hpp"
namespace chaiscript {
class Type_Conversions;
} // namespace chaiscript
namespace chaiscript namespace chaiscript
{ {
// Due to the nature of generating every possible arithmetic operation, there
// are going to be warnings generated on every platform regarding size and sign,
// this is OK, so we're disabling size/and sign type warnings
#ifdef CHAISCRIPT_MSVC #ifdef CHAISCRIPT_MSVC
#pragma warning(push) #pragma warning(push)
#pragma warning(disable : 4244 4018 4389 4146) #pragma warning(disable : 4244 4018 4389 4146 4365)
#endif #endif
/// \brief Represents any numeric type, generically. Used internally for generic operations between POD values /// \brief Represents any numeric type, generically. Used internally for generic operations between POD values
@@ -220,7 +233,7 @@ namespace chaiscript
template<typename LHS, bool Float> template<typename LHS, bool Float>
static Boxed_Value oper_rhs(Operators::Opers t_oper, const Boxed_Value &t_lhs, const Boxed_Value &t_rhs) static Boxed_Value oper_rhs(Operators::Opers t_oper, const Boxed_Value &t_lhs, const Boxed_Value &t_rhs)
{ {
const Type_Info &inp_ = t_rhs.get_type_info(); const auto &inp_ = t_rhs.get_type_info();
if (inp_ == typeid(int)) { if (inp_ == typeid(int)) {
return Go<LHS, int, Float>::go(t_oper, t_lhs, t_rhs); return Go<LHS, int, Float>::go(t_oper, t_lhs, t_rhs);
@@ -307,7 +320,7 @@ namespace chaiscript
} }
template<typename Source> template<typename Source>
std::string to_string_aux(const Boxed_Value &v) const static std::string to_string_aux(const Boxed_Value &v)
{ {
std::ostringstream oss; std::ostringstream oss;
oss << *static_cast<const Source *>(v.get_const_ptr()); oss << *static_cast<const Source *>(v.get_const_ptr());
@@ -321,10 +334,10 @@ namespace chaiscript
{ {
} }
Boxed_Number(const Boxed_Value &v) Boxed_Number(Boxed_Value v)
: bv(v) : bv(std::move(v))
{ {
validate_boxed_number(v); validate_boxed_number(bv);
} }
template<typename T> explicit Boxed_Number(T t) template<typename T> explicit Boxed_Number(T t)
@@ -520,7 +533,7 @@ namespace chaiscript
return oper(Operators::assign_bitwise_and, this->bv, t_rhs.bv); return oper(Operators::assign_bitwise_and, this->bv, t_rhs.bv);
} }
void validate_boxed_number(const Boxed_Value &v) static void validate_boxed_number(const Boxed_Value &v)
{ {
const Type_Info &inp_ = v.get_type_info(); const Type_Info &inp_ = v.get_type_info();
if (inp_ == typeid(bool)) if (inp_ == typeid(bool))
@@ -813,31 +826,25 @@ namespace chaiscript
namespace detail namespace detail
{ {
/** /// Cast_Helper for converting from Boxed_Value to Boxed_Number
* Cast_Helper for converting from Boxed_Value to Boxed_Number
*/
template<> template<>
struct Cast_Helper<Boxed_Number> struct Cast_Helper<Boxed_Number>
{ {
typedef Boxed_Number Result_Type; typedef Boxed_Number Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *) static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *)
{ {
return Boxed_Number(ob); return Boxed_Number(ob);
} }
}; };
/** /// Cast_Helper for converting from Boxed_Value to Boxed_Number
* Cast_Helper for converting from Boxed_Value to Boxed_Number
*/
template<> template<>
struct Cast_Helper<const Boxed_Number &> : Cast_Helper<Boxed_Number> struct Cast_Helper<const Boxed_Number &> : Cast_Helper<Boxed_Number>
{ {
}; };
/** /// Cast_Helper for converting from Boxed_Value to Boxed_Number
* Cast_Helper for converting from Boxed_Value to Boxed_Number
*/
template<> template<>
struct Cast_Helper<const Boxed_Number> : Cast_Helper<Boxed_Number> struct Cast_Helper<const Boxed_Number> : Cast_Helper<Boxed_Number>
{ {

View File

@@ -7,12 +7,15 @@
#ifndef CHAISCRIPT_BOXED_VALUE_HPP_ #ifndef CHAISCRIPT_BOXED_VALUE_HPP_
#define CHAISCRIPT_BOXED_VALUE_HPP_ #define CHAISCRIPT_BOXED_VALUE_HPP_
#include "type_info.hpp" #include <functional>
#include <map>
#include <memory>
#include <type_traits>
#include "../chaiscript_threading.hpp" #include "../chaiscript_threading.hpp"
#include "../chaiscript_defines.hpp"
#include <map>
#include "any.hpp" #include "any.hpp"
#include "type_info.hpp"
namespace chaiscript namespace chaiscript
{ {
@@ -22,24 +25,21 @@ namespace chaiscript
class Boxed_Value class Boxed_Value
{ {
public: public:
/** /// used for explicitly creating a "void" object
* used for explicitly creating a "void" object
*/
struct Void_Type struct Void_Type
{ {
}; };
private: private:
/** /// structure which holds the internal state of a Boxed_Value
* structure which holds the internal state of a Boxed_Value /// \todo Get rid of Any and merge it with this, reducing an allocation in the process
*/
struct Data struct Data
{ {
Data(const Type_Info &ti, Data(const Type_Info &ti,
const chaiscript::detail::Any &to, chaiscript::detail::Any to,
bool tr, bool tr,
const void *t_void_ptr) const void *t_void_ptr)
: m_type_info(ti), m_obj(to), m_data_ptr(ti.is_const()?0:const_cast<void *>(t_void_ptr)), m_const_data_ptr(t_void_ptr), : m_type_info(ti), m_obj(std::move(to)), m_data_ptr(ti.is_const()?nullptr:const_cast<void *>(t_void_ptr)), m_const_data_ptr(t_void_ptr),
m_is_ref(tr) m_is_ref(tr)
{ {
} }
@@ -52,18 +52,28 @@ namespace chaiscript
m_data_ptr = rhs.m_data_ptr; m_data_ptr = rhs.m_data_ptr;
m_const_data_ptr = rhs.m_const_data_ptr; m_const_data_ptr = rhs.m_const_data_ptr;
if (rhs.m_attrs)
{
m_attrs = std::unique_ptr<std::map<std::string, Boxed_Value>>(new std::map<std::string, Boxed_Value>(*rhs.m_attrs));
}
return *this; return *this;
} }
~Data() Data(const Data &) = delete;
{
} #if !defined(__APPLE__) && (!defined(_MSC_VER) || _MSC_VER != 1800)
Data(Data &&) = default;
Data &operator=(Data &&rhs) = default;
#endif
Type_Info m_type_info; Type_Info m_type_info;
chaiscript::detail::Any m_obj; chaiscript::detail::Any m_obj;
void *m_data_ptr; void *m_data_ptr;
const void *m_const_data_ptr; const void *m_const_data_ptr;
bool m_is_ref; bool m_is_ref;
std::unique_ptr<std::map<std::string, Boxed_Value>> m_attrs;
}; };
struct Object_Data struct Object_Data
@@ -95,32 +105,53 @@ namespace chaiscript
); );
} }
template<typename T>
static std::shared_ptr<Data> get(std::shared_ptr<T> &&obj)
{
auto ptr = obj.get();
return std::make_shared<Data>(
detail::Get_Type_Info<T>::get(),
chaiscript::detail::Any(std::move(obj)),
false,
ptr
);
}
template<typename T> template<typename T>
static std::shared_ptr<Data> get(T *t) static std::shared_ptr<Data> get(T *t)
{ {
return get(std::ref(*t)); return get(std::ref(*t));
} }
template<typename T>
static std::shared_ptr<Data> get(const T *t)
{
return get(std::cref(*t));
}
template<typename T> template<typename T>
static std::shared_ptr<Data> get(std::reference_wrapper<T> obj) static std::shared_ptr<Data> get(std::reference_wrapper<T> obj)
{ {
auto p = &obj.get();
return std::make_shared<Data>( return std::make_shared<Data>(
detail::Get_Type_Info<T>::get(), detail::Get_Type_Info<T>::get(),
chaiscript::detail::Any(obj), chaiscript::detail::Any(std::move(obj)),
true, true,
&obj.get() p
); );
} }
template<typename T> template<typename T>
static std::shared_ptr<Data> get(const T& t) static std::shared_ptr<Data> get(T t)
{ {
auto p = std::make_shared<T>(t); auto p = std::make_shared<T>(std::move(t));
auto ptr = p.get();
return std::make_shared<Data>( return std::make_shared<Data>(
detail::Get_Type_Info<T>::get(), detail::Get_Type_Info<T>::get(),
chaiscript::detail::Any(p), chaiscript::detail::Any(std::move(p)),
false, false,
p.get() ptr
); );
} }
@@ -137,115 +168,114 @@ namespace chaiscript
}; };
public: public:
/** /// Basic Boxed_Value constructor
* Basic Boxed_Value constructor template<typename T,
*/ typename = typename std::enable_if<!std::is_same<Boxed_Value, typename std::decay<T>::type>::value>::type>
template<typename T> explicit Boxed_Value(T &&t)
explicit Boxed_Value(T t) : m_data(Object_Data::get(std::forward<T>(t)))
: m_data(Object_Data::get(t))
{ {
} }
/** /// Unknown-type constructor
* Copy constructor - each copy shares the same data pointer
*/
Boxed_Value(const Boxed_Value &t_so)
: m_data(t_so.m_data)
{
}
/**
* Unknown-type constructor
*/
Boxed_Value() Boxed_Value()
: m_data(Object_Data::get()) : m_data(Object_Data::get())
{ {
} }
~Boxed_Value() #if !defined(_MSC_VER) || _MSC_VER != 1800
{ Boxed_Value(Boxed_Value&&) = default;
} Boxed_Value& operator=(Boxed_Value&&) = default;
#endif
Boxed_Value(const Boxed_Value&) = default;
Boxed_Value& operator=(const Boxed_Value&) = default;
void swap(Boxed_Value &rhs) void swap(Boxed_Value &rhs)
{ {
std::swap(m_data, rhs.m_data); std::swap(m_data, rhs.m_data);
} }
/** /// Copy the values stored in rhs.m_data to m_data.
* copy the values stored in rhs.m_data to m_data /// m_data pointers are not shared in this case
* m_data pointers are not shared in this case
*/
Boxed_Value assign(const Boxed_Value &rhs) Boxed_Value assign(const Boxed_Value &rhs)
{ {
(*m_data) = (*rhs.m_data); (*m_data) = (*rhs.m_data);
return *this; return *this;
} }
/** const Type_Info &get_type_info() const CHAISCRIPT_NOEXCEPT
* shared data assignment, same as copy construction
*/
Boxed_Value &operator=(const Boxed_Value &rhs)
{
Boxed_Value temp(rhs);
swap(temp);
return *this;
}
const Type_Info &get_type_info() const
{ {
return m_data->m_type_info; return m_data->m_type_info;
} }
/** /// return true if the object is uninitialized
* return true if the object is uninitialized bool is_undef() const CHAISCRIPT_NOEXCEPT
*/
bool is_undef() const
{ {
return m_data->m_type_info.is_undef(); return m_data->m_type_info.is_undef();
} }
bool is_const() const bool is_const() const CHAISCRIPT_NOEXCEPT
{ {
return m_data->m_type_info.is_const(); return m_data->m_type_info.is_const();
} }
bool is_type(const Type_Info &ti) const bool is_type(const Type_Info &ti) const CHAISCRIPT_NOEXCEPT
{ {
return m_data->m_type_info.bare_equal(ti); return m_data->m_type_info.bare_equal(ti);
} }
bool is_null() const bool is_null() const CHAISCRIPT_NOEXCEPT
{ {
return (m_data->m_data_ptr == 0 && m_data->m_const_data_ptr == 0); return (m_data->m_data_ptr == nullptr && m_data->m_const_data_ptr == nullptr);
} }
const chaiscript::detail::Any & get() const const chaiscript::detail::Any & get() const CHAISCRIPT_NOEXCEPT
{ {
return m_data->m_obj; return m_data->m_obj;
} }
bool is_ref() const bool is_ref() const CHAISCRIPT_NOEXCEPT
{ {
return m_data->m_is_ref; return m_data->m_is_ref;
} }
bool is_pointer() const bool is_pointer() const CHAISCRIPT_NOEXCEPT
{ {
return !is_ref(); return !is_ref();
} }
void *get_ptr() const void *get_ptr() const CHAISCRIPT_NOEXCEPT
{ {
return m_data->m_data_ptr; return m_data->m_data_ptr;
} }
const void *get_const_ptr() const const void *get_const_ptr() const CHAISCRIPT_NOEXCEPT
{ {
return m_data->m_const_data_ptr; return m_data->m_const_data_ptr;
} }
Boxed_Value get_attr(const std::string &t_name)
{
if (!m_data->m_attrs)
{
m_data->m_attrs = std::unique_ptr<std::map<std::string, Boxed_Value>>(new std::map<std::string, Boxed_Value>());
}
return (*m_data->m_attrs)[t_name];
}
Boxed_Value &copy_attrs(const Boxed_Value &t_obj)
{
if (t_obj.m_data->m_attrs)
{
m_data->m_attrs = std::unique_ptr<std::map<std::string, Boxed_Value>>(new std::map<std::string, Boxed_Value>(*t_obj.m_data->m_attrs));
}
return *this;
}
/// \returns true if the two Boxed_Values share the same internal type /// \returns true if the two Boxed_Values share the same internal type
static bool type_match(Boxed_Value l, Boxed_Value r) static bool type_match(const Boxed_Value &l, const Boxed_Value &r) CHAISCRIPT_NOEXCEPT
{ {
return l.get_type_info() == r.get_type_info(); return l.get_type_info() == r.get_type_info();
} }
@@ -254,19 +284,20 @@ namespace chaiscript
std::shared_ptr<Data> m_data; std::shared_ptr<Data> m_data;
}; };
/// \brief Creates a Boxed_Value. If the object passed in is a value type, it is copied. If it is a pointer, std::shared_ptr, or std::reference_type /// @brief Creates a Boxed_Value. If the object passed in is a value type, it is copied. If it is a pointer, std::shared_ptr, or std::reference_type
/// a copy is not made. /// a copy is not made.
/// \param t The value to box /// @param t The value to box
/// ///
/// Example: /// Example:
/// \code ///
/// ~~~{.cpp}
/// int i; /// int i;
/// chaiscript::ChaiScript chai; /// chaiscript::ChaiScript chai;
/// chai.add(chaiscript::var(i), "i"); /// chai.add(chaiscript::var(i), "i");
/// chai.add(chaiscript::var(&i), "ip"); /// chai.add(chaiscript::var(&i), "ip");
/// \endcode /// ~~~
/// ///
/// \sa \ref addingobjects /// @sa @ref adding_objects
template<typename T> template<typename T>
Boxed_Value var(T t) Boxed_Value var(T t)
{ {
@@ -281,7 +312,7 @@ namespace chaiscript
template<typename T> template<typename T>
Boxed_Value const_var_impl(const T &t) Boxed_Value const_var_impl(const T &t)
{ {
return Boxed_Value(std::shared_ptr<typename std::add_const<T>::type >(new T(t))); return Boxed_Value(std::make_shared<typename std::add_const<T>::type >(t));
} }
/// \brief Takes a pointer to a value, adds const to the pointed to type and returns an immutable Boxed_Value. /// \brief Takes a pointer to a value, adds const to the pointed to type and returns an immutable Boxed_Value.
@@ -339,7 +370,8 @@ namespace chaiscript
/// chai.add(chaiscript::const_var(Green), "Green"); /// chai.add(chaiscript::const_var(Green), "Green");
/// \endcode /// \endcode
/// ///
/// \sa \ref addingobjects /// \todo support C++11 strongly typed enums
/// \sa \ref adding_objects
template<typename T> template<typename T>
Boxed_Value const_var(const T &t) Boxed_Value const_var(const T &t)
{ {

File diff suppressed because it is too large Load Diff

View File

@@ -1,262 +0,0 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_DYNAMIC_CAST_CONVERSION_HPP_
#define CHAISCRIPT_DYNAMIC_CAST_CONVERSION_HPP_
#include <memory>
#include <set>
#include "type_info.hpp"
#include "boxed_value.hpp"
#include "boxed_cast_helper.hpp"
#include "bad_boxed_cast.hpp"
namespace chaiscript
{
namespace exception
{
class bad_boxed_dynamic_cast : public bad_boxed_cast
{
public:
bad_boxed_dynamic_cast(const Type_Info &t_from, const std::type_info &t_to,
const std::string &t_what) CHAISCRIPT_NOEXCEPT
: bad_boxed_cast(t_from, t_to, t_what)
{
}
bad_boxed_dynamic_cast(const Type_Info &t_from, const std::type_info &t_to) CHAISCRIPT_NOEXCEPT
: bad_boxed_cast(t_from, t_to)
{
}
bad_boxed_dynamic_cast(const std::string &w) CHAISCRIPT_NOEXCEPT
: bad_boxed_cast(w)
{
}
virtual ~bad_boxed_dynamic_cast() CHAISCRIPT_NOEXCEPT {}
};
}
namespace detail
{
class Dynamic_Conversion
{
public:
virtual Boxed_Value convert(const Boxed_Value &derived) const = 0;
const Type_Info &base()
{
return m_base;
}
const Type_Info &derived()
{
return m_derived;
}
protected:
Dynamic_Conversion(const Type_Info &t_base, const Type_Info &t_derived)
: m_base(t_base), m_derived(t_derived)
{
}
virtual ~Dynamic_Conversion() {}
private:
Type_Info m_base;
Type_Info m_derived;
};
template<typename Base, typename Derived>
class Dynamic_Conversion_Impl : public Dynamic_Conversion
{
public:
Dynamic_Conversion_Impl()
: Dynamic_Conversion(user_type<Base>(), user_type<Derived>())
{
}
virtual Boxed_Value convert(const Boxed_Value &t_derived) const
{
if (t_derived.get_type_info().bare_equal(user_type<Derived>()))
{
if (t_derived.is_pointer())
{
// Dynamic cast out the contained boxed value, which we know is the type we want
if (t_derived.is_const())
{
std::shared_ptr<const Base> data
= std::dynamic_pointer_cast<const Base>(detail::Cast_Helper<std::shared_ptr<const Derived> >::cast(t_derived, nullptr));
if (!data)
{
throw std::bad_cast();
}
return Boxed_Value(data);
} else {
std::shared_ptr<Base> data
= std::dynamic_pointer_cast<Base>(detail::Cast_Helper<std::shared_ptr<Derived> >::cast(t_derived, nullptr));
if (!data)
{
throw std::bad_cast();
}
return Boxed_Value(data);
}
} else {
// Pull the reference out of the contained boxed value, which we know is the type we want
if (t_derived.is_const())
{
const Derived &d = detail::Cast_Helper<const Derived &>::cast(t_derived, 0);
const Base &data = dynamic_cast<const Base &>(d);
return Boxed_Value(std::cref(data));
} else {
Derived &d = detail::Cast_Helper<Derived &>::cast(t_derived, 0);
Base &data = dynamic_cast<Base &>(d);
return Boxed_Value(std::ref(data));
}
}
} else {
throw chaiscript::exception::bad_boxed_dynamic_cast(t_derived.get_type_info(), typeid(Base), "Unknown dynamic_cast_conversion");
}
}
};
}
class Dynamic_Cast_Conversions
{
public:
Dynamic_Cast_Conversions()
{
}
Dynamic_Cast_Conversions(const Dynamic_Cast_Conversions &t_other)
: m_conversions(t_other.get_conversions())
{
}
void add_conversion(const std::shared_ptr<detail::Dynamic_Conversion> &conversion)
{
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
m_conversions.insert(conversion);
}
template<typename Base, typename Derived>
bool dynamic_cast_converts() const
{
return dynamic_cast_converts(user_type<Base>(), user_type<Derived>());
}
bool dynamic_cast_converts(const Type_Info &base, const Type_Info &derived) const
{
return has_conversion(base, derived);
}
template<typename Base>
Boxed_Value boxed_dynamic_cast(const Boxed_Value &derived) const
{
try {
return get_conversion(user_type<Base>(), derived.get_type_info())->convert(derived);
} catch (const std::out_of_range &) {
throw exception::bad_boxed_dynamic_cast(derived.get_type_info(), typeid(Base), "No known conversion");
} catch (const std::bad_cast &) {
throw exception::bad_boxed_dynamic_cast(derived.get_type_info(), typeid(Base), "Unable to perform dynamic_cast operation");
}
}
bool has_conversion(const Type_Info &base, const Type_Info &derived) const
{
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
return find(base, derived) != m_conversions.end();
}
std::shared_ptr<detail::Dynamic_Conversion> get_conversion(const Type_Info &base, const Type_Info &derived) const
{
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
std::set<std::shared_ptr<detail::Dynamic_Conversion> >::const_iterator itr =
find(base, derived);
if (itr != m_conversions.end())
{
return *itr;
} else {
throw std::out_of_range("No such conversion exists from " + derived.bare_name() + " to " + base.bare_name());
}
}
private:
std::set<std::shared_ptr<detail::Dynamic_Conversion> >::const_iterator find(
const Type_Info &base, const Type_Info &derived) const
{
for (std::set<std::shared_ptr<detail::Dynamic_Conversion> >::const_iterator itr = m_conversions.begin();
itr != m_conversions.end();
++itr)
{
if ((*itr)->base().bare_equal(base) && (*itr)->derived().bare_equal(derived))
{
return itr;
}
}
return m_conversions.end();
}
std::set<std::shared_ptr<detail::Dynamic_Conversion> > get_conversions() const
{
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
return m_conversions;
}
mutable chaiscript::detail::threading::shared_mutex m_mutex;
std::set<std::shared_ptr<detail::Dynamic_Conversion> > m_conversions;
};
typedef std::shared_ptr<chaiscript::detail::Dynamic_Conversion> Dynamic_Cast_Conversion;
/// \brief Used to register a base / parent class relationship with ChaiScript. Necessary if you
/// want automatic conversions up your inheritance hierarchy.
///
/// Create a new base class registration for applying to a module or to the chaiscript engine
/// Currently, due to limitations in module loading on Windows, and for the sake of portability,
/// if you have a type that is introduced in a loadable module and is used by multiple modules
/// (through a tertiary dll that is shared between the modules, static linking the new type
/// into both loadable modules would not be portable), you need to register the base type
/// relationship in all modules that use the newly added type in a polymorphic way.
///
/// Example:
/// \code
/// class Base
/// {};
/// class Derived : public Base
/// {};
///
/// chaiscript::ChaiScript chai;
/// chai.add(chaiscript::base_class<Base, Derived>());
/// \endcode
///
/// \todo Move share static type registration code into a mechanism that allows it to be properly
/// shared by all modules
template<typename Base, typename Derived>
Dynamic_Cast_Conversion base_class()
{
//Can only be used with related polymorphic types
//may be expanded some day to support conversions other than child -> parent
static_assert(std::is_base_of<Base,Derived>::value, "Classes are not related by inheritance");
static_assert(std::is_polymorphic<Base>::value, "Base class must be polymorphic");
static_assert(std::is_polymorphic<Derived>::value, "Derived class must be polymorphic");
return std::shared_ptr<detail::Dynamic_Conversion>(new detail::Dynamic_Conversion_Impl<Base, Derived>());
}
}
#endif

View File

@@ -7,6 +7,27 @@
#ifndef CHAISCRIPT_DYNAMIC_OBJECT_HPP_ #ifndef CHAISCRIPT_DYNAMIC_OBJECT_HPP_
#define CHAISCRIPT_DYNAMIC_OBJECT_HPP_ #define CHAISCRIPT_DYNAMIC_OBJECT_HPP_
#include <cassert>
#include <map>
#include <memory>
#include <string>
#include <typeinfo>
#include <utility>
#include <vector>
#include "../chaiscript_defines.hpp"
#include "boxed_cast.hpp"
#include "boxed_cast_helper.hpp"
#include "boxed_value.hpp"
#include "proxy_functions.hpp"
#include "type_info.hpp"
namespace chaiscript {
class Type_Conversions;
namespace dispatch {
class Proxy_Function_Base;
} // namespace dispatch
} // namespace chaiscript
namespace chaiscript namespace chaiscript
{ {
@@ -15,8 +36,8 @@ namespace chaiscript
class Dynamic_Object class Dynamic_Object
{ {
public: public:
Dynamic_Object(const std::string &t_type_name) Dynamic_Object(std::string t_type_name)
: m_type_name(t_type_name) : m_type_name(std::move(t_type_name))
{ {
} }
@@ -30,7 +51,7 @@ namespace chaiscript
return m_attrs[t_attr_name]; return m_attrs[t_attr_name];
} }
std::map<std::string, Boxed_Value> get_attrs() std::map<std::string, Boxed_Value> get_attrs() const
{ {
return m_attrs; return m_attrs;
} }
@@ -43,30 +64,28 @@ namespace chaiscript
namespace detail namespace detail
{ {
/** /// A Proxy_Function implementation designed for calling a function
* A Proxy_Function implementation designed for calling a function /// that is automatically guarded based on the first param based on the
* that is automatically guarded based on the first param based on the /// param's type name
* param's type name
*/
class Dynamic_Object_Function : public Proxy_Function_Base class Dynamic_Object_Function : public Proxy_Function_Base
{ {
public: public:
Dynamic_Object_Function( Dynamic_Object_Function(
const std::string &t_type_name, std::string t_type_name,
const Proxy_Function &t_func) const Proxy_Function &t_func)
: Proxy_Function_Base(t_func->get_param_types()), : Proxy_Function_Base(t_func->get_param_types(), t_func->get_arity()),
m_type_name(t_type_name), m_func(t_func) m_type_name(std::move(t_type_name)), m_func(t_func), m_doti(user_type<Dynamic_Object>())
{ {
assert( (t_func->get_arity() > 0 || t_func->get_arity() < 0) assert( (t_func->get_arity() > 0 || t_func->get_arity() < 0)
&& "Programming error, Dynamic_Object_Function must have at least one parameter (this)"); && "Programming error, Dynamic_Object_Function must have at least one parameter (this)");
} }
Dynamic_Object_Function( Dynamic_Object_Function(
const std::string &t_type_name, std::string t_type_name,
const Proxy_Function &t_func, const Proxy_Function &t_func,
const Type_Info &t_ti) const Type_Info &t_ti)
: Proxy_Function_Base(build_param_types(t_func->get_param_types(), t_ti)), : Proxy_Function_Base(build_param_types(t_func->get_param_types(), t_ti), t_func->get_arity()),
m_type_name(t_type_name), m_func(t_func), m_ti(new Type_Info(t_ti)) m_type_name(std::move(t_type_name)), m_func(t_func), m_ti(new Type_Info(t_ti)), m_doti(user_type<Dynamic_Object>())
{ {
assert( (t_func->get_arity() > 0 || t_func->get_arity() < 0) assert( (t_func->get_arity() > 0 || t_func->get_arity() < 0)
&& "Programming error, Dynamic_Object_Function must have at least one parameter (this)"); && "Programming error, Dynamic_Object_Function must have at least one parameter (this)");
@@ -74,10 +93,12 @@ namespace chaiscript
virtual ~Dynamic_Object_Function() {} virtual ~Dynamic_Object_Function() {}
virtual bool operator==(const Proxy_Function_Base &f) const Dynamic_Object_Function &operator=(const Dynamic_Object_Function) = delete;
Dynamic_Object_Function(Dynamic_Object_Function &) = delete;
virtual bool operator==(const Proxy_Function_Base &f) const CHAISCRIPT_OVERRIDE
{ {
const Dynamic_Object_Function *df = dynamic_cast<const Dynamic_Object_Function *>(&f); if (const auto *df = dynamic_cast<const Dynamic_Object_Function *>(&f))
if (df)
{ {
return df->m_type_name == m_type_name && (*df->m_func) == (*m_func); return df->m_type_name == m_type_name && (*df->m_func) == (*m_func);
} else { } else {
@@ -85,7 +106,7 @@ namespace chaiscript
} }
} }
virtual bool call_match(const std::vector<Boxed_Value> &vals, const Dynamic_Cast_Conversions &t_conversions) const virtual bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
{ {
if (dynamic_object_typename_match(vals, m_type_name, m_ti, t_conversions)) if (dynamic_object_typename_match(vals, m_type_name, m_ti, t_conversions))
{ {
@@ -95,25 +116,19 @@ namespace chaiscript
} }
} }
virtual std::vector<Const_Proxy_Function> get_contained_functions() const virtual std::vector<Const_Proxy_Function> get_contained_functions() const CHAISCRIPT_OVERRIDE
{ {
return {m_func}; return {m_func};
} }
virtual std::string annotation() const CHAISCRIPT_OVERRIDE
virtual int get_arity() const
{
return m_func->get_arity();
}
virtual std::string annotation() const
{ {
return m_func->annotation(); return m_func->annotation();
} }
protected: protected:
virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions) const virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
{ {
if (dynamic_object_typename_match(params, m_type_name, m_ti, t_conversions)) if (dynamic_object_typename_match(params, m_type_name, m_ti, t_conversions))
{ {
@@ -123,7 +138,7 @@ namespace chaiscript
} }
} }
virtual bool compare_first_type(const Boxed_Value &bv, const Dynamic_Cast_Conversions &t_conversions) const virtual bool compare_first_type(const Boxed_Value &bv, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
{ {
return dynamic_object_typename_match(bv, m_type_name, m_ti, t_conversions); return dynamic_object_typename_match(bv, m_type_name, m_ti, t_conversions);
} }
@@ -140,11 +155,10 @@ namespace chaiscript
return types; return types;
} }
static bool dynamic_object_typename_match(const Boxed_Value &bv, const std::string &name, bool dynamic_object_typename_match(const Boxed_Value &bv, const std::string &name,
const std::shared_ptr<Type_Info> &ti, const Dynamic_Cast_Conversions &t_conversions) const std::unique_ptr<Type_Info> &ti, const Type_Conversions &t_conversions) const
{ {
static Type_Info doti = user_type<Dynamic_Object>(); if (bv.get_type_info().bare_equal(m_doti))
if (bv.get_type_info().bare_equal(doti))
{ {
try { try {
const Dynamic_Object &d = boxed_cast<const Dynamic_Object &>(bv, &t_conversions); const Dynamic_Object &d = boxed_cast<const Dynamic_Object &>(bv, &t_conversions);
@@ -163,8 +177,8 @@ namespace chaiscript
} }
static bool dynamic_object_typename_match(const std::vector<Boxed_Value> &bvs, const std::string &name, bool dynamic_object_typename_match(const std::vector<Boxed_Value> &bvs, const std::string &name,
const std::shared_ptr<Type_Info> &ti, const Dynamic_Cast_Conversions &t_conversions) const std::unique_ptr<Type_Info> &ti, const Type_Conversions &t_conversions) const
{ {
if (bvs.size() > 0) if (bvs.size() > 0)
{ {
@@ -176,7 +190,9 @@ namespace chaiscript
std::string m_type_name; std::string m_type_name;
Proxy_Function m_func; Proxy_Function m_func;
std::shared_ptr<Type_Info> m_ti; std::unique_ptr<Type_Info> m_ti;
const Type_Info m_doti;
}; };
@@ -191,10 +207,10 @@ namespace chaiscript
{ {
public: public:
Dynamic_Object_Constructor( Dynamic_Object_Constructor(
const std::string &t_type_name, std::string t_type_name,
const Proxy_Function &t_func) const Proxy_Function &t_func)
: Proxy_Function_Base(build_type_list(t_func->get_param_types())), : Proxy_Function_Base(build_type_list(t_func->get_param_types()), t_func->get_arity() - 1),
m_type_name(t_type_name), m_func(t_func) m_type_name(std::move(t_type_name)), m_func(t_func)
{ {
assert( (t_func->get_arity() > 0 || t_func->get_arity() < 0) assert( (t_func->get_arity() > 0 || t_func->get_arity() < 0)
&& "Programming error, Dynamic_Object_Function must have at least one parameter (this)"); && "Programming error, Dynamic_Object_Function must have at least one parameter (this)");
@@ -202,8 +218,8 @@ namespace chaiscript
static std::vector<Type_Info> build_type_list(const std::vector<Type_Info> &tl) static std::vector<Type_Info> build_type_list(const std::vector<Type_Info> &tl)
{ {
std::vector<Type_Info>::const_iterator begin = tl.begin(); auto begin = tl.begin();
std::vector<Type_Info>::const_iterator end = tl.end(); auto end = tl.end();
if (begin != end) if (begin != end)
{ {
@@ -215,7 +231,7 @@ namespace chaiscript
virtual ~Dynamic_Object_Constructor() {} virtual ~Dynamic_Object_Constructor() {}
virtual bool operator==(const Proxy_Function_Base &f) const virtual bool operator==(const Proxy_Function_Base &f) const CHAISCRIPT_OVERRIDE
{ {
const Dynamic_Object_Constructor *dc = dynamic_cast<const Dynamic_Object_Constructor*>(&f); const Dynamic_Object_Constructor *dc = dynamic_cast<const Dynamic_Object_Constructor*>(&f);
if (dc) if (dc)
@@ -226,33 +242,24 @@ namespace chaiscript
} }
} }
virtual bool call_match(const std::vector<Boxed_Value> &vals, const Dynamic_Cast_Conversions &t_conversions) const virtual bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
{ {
std::vector<Boxed_Value> new_vals; std::vector<Boxed_Value> new_vals{Boxed_Value(Dynamic_Object(m_type_name))};
new_vals.push_back(Boxed_Value(Dynamic_Object(m_type_name)));
new_vals.insert(new_vals.end(), vals.begin(), vals.end()); new_vals.insert(new_vals.end(), vals.begin(), vals.end());
return m_func->call_match(new_vals, t_conversions); return m_func->call_match(new_vals, t_conversions);
} }
virtual std::string annotation() const CHAISCRIPT_OVERRIDE
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(); return m_func->annotation();
} }
protected: protected:
virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions) const virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
{ {
std::vector<Boxed_Value> new_params; auto bv = var(Dynamic_Object(m_type_name));
chaiscript::Boxed_Value bv = var(Dynamic_Object(m_type_name)); std::vector<Boxed_Value> new_params{bv};
new_params.push_back(bv);
new_params.insert(new_params.end(), params.begin(), params.end()); new_params.insert(new_params.end(), params.begin(), params.end());
(*m_func)(new_params, t_conversions); (*m_func)(new_params, t_conversions);

View File

@@ -7,12 +7,23 @@
#ifndef CHAISCRIPT_EXCEPTION_SPECIFICATION_HPP_ #ifndef CHAISCRIPT_EXCEPTION_SPECIFICATION_HPP_
#define CHAISCRIPT_EXCEPTION_SPECIFICATION_HPP_ #define CHAISCRIPT_EXCEPTION_SPECIFICATION_HPP_
#include <memory>
#include "../chaiscript_defines.hpp"
#include "boxed_cast.hpp" #include "boxed_cast.hpp"
namespace chaiscript {
class Boxed_Value;
namespace exception {
class bad_boxed_cast;
} // namespace exception
} // namespace chaiscript
namespace chaiscript namespace chaiscript
{ {
namespace detail namespace detail
{ {
/// \todo make this a variadic template
struct Exception_Handler_Base struct Exception_Handler_Base
{ {
virtual void handle(const Boxed_Value &bv, const Dispatch_Engine &t_engine) = 0; virtual void handle(const Boxed_Value &bv, const Dispatch_Engine &t_engine) = 0;
@@ -32,7 +43,7 @@ namespace chaiscript
{ {
virtual ~Exception_Handler_Impl1() {} virtual ~Exception_Handler_Impl1() {}
virtual void handle(const Boxed_Value &bv, const Dispatch_Engine &t_engine) virtual void handle(const Boxed_Value &bv, const Dispatch_Engine &t_engine) CHAISCRIPT_OVERRIDE
{ {
throw_type<T1>(bv, t_engine); throw_type<T1>(bv, t_engine);
} }
@@ -42,7 +53,7 @@ namespace chaiscript
{ {
virtual ~Exception_Handler_Impl2() {} virtual ~Exception_Handler_Impl2() {}
virtual void handle(const Boxed_Value &bv, const Dispatch_Engine &t_engine) virtual void handle(const Boxed_Value &bv, const Dispatch_Engine &t_engine) CHAISCRIPT_OVERRIDE
{ {
throw_type<T1>(bv, t_engine); throw_type<T1>(bv, t_engine);
throw_type<T2>(bv, t_engine); throw_type<T2>(bv, t_engine);
@@ -54,7 +65,7 @@ namespace chaiscript
{ {
virtual ~Exception_Handler_Impl3() {} virtual ~Exception_Handler_Impl3() {}
virtual void handle(const Boxed_Value &bv, const Dispatch_Engine &t_engine) virtual void handle(const Boxed_Value &bv, const Dispatch_Engine &t_engine) CHAISCRIPT_OVERRIDE
{ {
throw_type<T1>(bv, t_engine); throw_type<T1>(bv, t_engine);
throw_type<T2>(bv, t_engine); throw_type<T2>(bv, t_engine);
@@ -66,7 +77,7 @@ namespace chaiscript
{ {
virtual ~Exception_Handler_Impl4() {} virtual ~Exception_Handler_Impl4() {}
virtual void handle(const Boxed_Value &bv, const Dispatch_Engine &t_engine) virtual void handle(const Boxed_Value &bv, const Dispatch_Engine &t_engine) CHAISCRIPT_OVERRIDE
{ {
throw_type<T1>(bv, t_engine); throw_type<T1>(bv, t_engine);
throw_type<T2>(bv, t_engine); throw_type<T2>(bv, t_engine);
@@ -79,7 +90,7 @@ namespace chaiscript
{ {
virtual ~Exception_Handler_Impl5() {} virtual ~Exception_Handler_Impl5() {}
virtual void handle(const Boxed_Value &bv, const Dispatch_Engine &t_engine) virtual void handle(const Boxed_Value &bv, const Dispatch_Engine &t_engine) CHAISCRIPT_OVERRIDE
{ {
throw_type<T1>(bv, t_engine); throw_type<T1>(bv, t_engine);
throw_type<T2>(bv, t_engine); throw_type<T2>(bv, t_engine);

View File

@@ -7,78 +7,77 @@
#ifndef CHAISCRIPT_FUNCTION_CALL_HPP_ #ifndef CHAISCRIPT_FUNCTION_CALL_HPP_
#define CHAISCRIPT_FUNCTION_CALL_HPP_ #define CHAISCRIPT_FUNCTION_CALL_HPP_
#include <functional>
#include <iostream>
#include <string> #include <string>
#include <vector> #include <vector>
#include "proxy_functions.hpp"
#include "boxed_cast.hpp"
#include "function_call_detail.hpp" #include "function_call_detail.hpp"
#include "proxy_functions.hpp"
namespace chaiscript {
#include <iostream> class Boxed_Value;
class Type_Conversions;
namespace detail {
template <typename T> struct Cast_Helper;
} // namespace detail
} // namespace chaiscript
namespace chaiscript namespace chaiscript
{ {
namespace dispatch namespace dispatch
{ {
/** /// 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 /// example:
* example: /// std::function<void (int)> f =
* std::function<void (int)> f = /// build_function_caller(dispatchkit.get_function("print"));
* build_function_caller(dispatchkit.get_function("print")); /// \returns A std::function object for dispatching
* \returns A std::function object for dispatching /// \param[in] funcs the set of functions to dispatch on.
* \param[in] funcs the set of functions to dispatch on.
*/
template<typename FunctionType> template<typename FunctionType>
std::function<FunctionType> std::function<FunctionType>
functor(const std::vector<Const_Proxy_Function> &funcs, const Dynamic_Cast_Conversions *t_conversions) functor(const std::vector<Const_Proxy_Function> &funcs, const Type_Conversions *t_conversions)
{ {
FunctionType *p=0; FunctionType *p=nullptr;
return detail::build_function_caller_helper(p, funcs, t_conversions); return detail::build_function_caller_helper(p, funcs, t_conversions);
} }
/** /// Build a function caller for a particular Proxy_Function object
* Build a function caller for a particular Proxy_Function object /// 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(Proxy_Function f)
* void my_function(Proxy_Function f) /// {
* { /// std::function<void (int)> local_f =
* std::function<void (int)> local_f = /// build_function_caller(f);
* build_function_caller(f); /// }
* } /// \returns A std::function object for dispatching
* \returns A std::function object for dispatching /// \param[in] func A function to execute.
* \param[in] func A function to execute.
*/
template<typename FunctionType> template<typename FunctionType>
std::function<FunctionType> std::function<FunctionType>
functor(Const_Proxy_Function func, const Dynamic_Cast_Conversions *t_conversions) functor(Const_Proxy_Function func, const Type_Conversions *t_conversions)
{ {
std::vector<Const_Proxy_Function> funcs; return functor<FunctionType>(std::vector<Const_Proxy_Function>({func}), t_conversions);
funcs.push_back(func);
return functor<FunctionType>(funcs, t_conversions);
} }
/** /// Helper for automatically unboxing a Boxed_Value that contains a function object
* Helper for automatically unboxing a Boxed_Value that contains a function object /// and creating a typesafe C++ function caller from it.
* and creating a typesafe C++ function caller from it.
*/
template<typename FunctionType> template<typename FunctionType>
std::function<FunctionType> std::function<FunctionType>
functor(const Boxed_Value &bv, const Dynamic_Cast_Conversions *t_conversions) functor(const Boxed_Value &bv, const Type_Conversions *t_conversions)
{ {
return functor<FunctionType>(boxed_cast<Const_Proxy_Function >(bv, t_conversions), t_conversions); return functor<FunctionType>(boxed_cast<Const_Proxy_Function >(bv, t_conversions), t_conversions);
} }
} }
namespace detail{ namespace detail{
/** /// Cast helper to handle automatic casting to const std::function &
* Cast helper to handle automatic casting to const std::function &
*/
template<typename Signature> template<typename Signature>
struct Cast_Helper<const std::function<Signature> &> struct Cast_Helper<const std::function<Signature> &>
{ {
typedef std::function<Signature> Result_Type; typedef std::function<Signature> Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *t_conversions) static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *t_conversions)
{ {
if (ob.get_type_info().bare_equal(user_type<Const_Proxy_Function>())) if (ob.get_type_info().bare_equal(user_type<Const_Proxy_Function>()))
{ {
@@ -89,15 +88,13 @@ namespace chaiscript
} }
}; };
/** /// Cast helper to handle automatic casting to std::function
* Cast helper to handle automatic casting to std::function
*/
template<typename Signature> template<typename Signature>
struct Cast_Helper<std::function<Signature> > struct Cast_Helper<std::function<Signature> >
{ {
typedef std::function<Signature> Result_Type; typedef std::function<Signature> Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *t_conversions) static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *t_conversions)
{ {
if (ob.get_type_info().bare_equal(user_type<Const_Proxy_Function>())) if (ob.get_type_info().bare_equal(user_type<Const_Proxy_Function>()))
{ {
@@ -108,15 +105,13 @@ namespace chaiscript
} }
}; };
/** /// Cast helper to handle automatic casting to const std::function
* Cast helper to handle automatic casting to const std::function
*/
template<typename Signature> template<typename Signature>
struct Cast_Helper<const std::function<Signature> > struct Cast_Helper<const std::function<Signature> >
{ {
typedef std::function<Signature> Result_Type; typedef std::function<Signature> Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *t_conversions) static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *t_conversions)
{ {
if (ob.get_type_info().bare_equal(user_type<Const_Proxy_Function>())) if (ob.get_type_info().bare_equal(user_type<Const_Proxy_Function>()))
{ {

View File

@@ -7,8 +7,17 @@
#ifndef CHAISCRIPT_FUNCTION_CALL_DETAIL_HPP_ #ifndef CHAISCRIPT_FUNCTION_CALL_DETAIL_HPP_
#define CHAISCRIPT_FUNCTION_CALL_DETAIL_HPP_ #define CHAISCRIPT_FUNCTION_CALL_DETAIL_HPP_
#include <algorithm>
#include <functional>
#include <memory>
#include <string> #include <string>
#include <type_traits>
#include <vector> #include <vector>
#include "boxed_cast.hpp"
#include "boxed_number.hpp"
#include "boxed_value.hpp"
#include "type_conversions.hpp"
#include "proxy_functions.hpp" #include "proxy_functions.hpp"
namespace chaiscript namespace chaiscript
@@ -17,29 +26,40 @@ namespace chaiscript
{ {
namespace detail namespace detail
{ {
/// Internal helper class for handling the return
/** /// value of a build_function_caller
* Internal helper class for handling the return template<typename Ret, bool is_arithmetic>
* value of a build_function_caller
*/
template<typename Ret>
struct Function_Caller_Ret struct Function_Caller_Ret
{ {
static Ret call(const std::vector<Const_Proxy_Function> &t_funcs, static Ret call(const std::vector<Const_Proxy_Function> &t_funcs,
const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions) const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions)
{ {
return boxed_cast<Ret>(dispatch::dispatch(t_funcs, params, t_conversions)); return boxed_cast<Ret>(dispatch::dispatch(t_funcs, params, t_conversions));
} }
}; };
/**
* Specialization for arithmetic return types
*/
template<typename Ret>
struct Function_Caller_Ret<Ret, true>
{
static Ret call(const std::vector<Const_Proxy_Function> &t_funcs,
const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions)
{
return Boxed_Number(dispatch::dispatch(t_funcs, params, t_conversions)).get_as<Ret>();
}
};
/** /**
* Specialization for void return types * Specialization for void return types
*/ */
template<> template<>
struct Function_Caller_Ret<void> struct Function_Caller_Ret<void, false>
{ {
static void call(const std::vector<Const_Proxy_Function> &t_funcs, static void call(const std::vector<Const_Proxy_Function> &t_funcs,
const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions) const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions)
{ {
dispatch::dispatch(t_funcs, params, t_conversions); dispatch::dispatch(t_funcs, params, t_conversions);
} }
@@ -51,30 +71,30 @@ namespace chaiscript
template<typename Ret, typename ... Param> template<typename Ret, typename ... Param>
struct Build_Function_Caller_Helper struct Build_Function_Caller_Helper
{ {
Build_Function_Caller_Helper(const std::vector<Const_Proxy_Function> &t_funcs, const Dynamic_Cast_Conversions &t_conversions) Build_Function_Caller_Helper(std::vector<Const_Proxy_Function> t_funcs, const Type_Conversions &t_conversions)
: m_funcs(t_funcs), : m_funcs(std::move(t_funcs)),
m_conversions(t_conversions) m_conversions(t_conversions)
{ {
} }
Ret operator()(Param...param) Ret operator()(Param...param)
{ {
return Function_Caller_Ret<Ret>::call(m_funcs, { return Function_Caller_Ret<Ret, std::is_arithmetic<Ret>::value && !std::is_same<Ret, bool>::value>::call(m_funcs, {
(std::is_reference<Param>::value&&!(std::is_same<chaiscript::Boxed_Value, typename std::remove_const<typename std::remove_reference<Param>::type>::type>::value))?Boxed_Value(std::ref(param)):Boxed_Value(param)... (std::is_reference<Param>::value&&!(std::is_same<chaiscript::Boxed_Value, typename std::remove_const<typename std::remove_reference<Param>::type>::type>::value))?Boxed_Value(std::ref(param)):Boxed_Value(param)...
}, m_conversions }, m_conversions
); );
} }
std::vector<Const_Proxy_Function> m_funcs; std::vector<Const_Proxy_Function> m_funcs;
Dynamic_Cast_Conversions m_conversions; Type_Conversions m_conversions;
}; };
template<typename Ret, typename ... Params> template<typename Ret, typename ... Params>
std::function<Ret (Params...)> build_function_caller_helper(Ret (Params...), const std::vector<Const_Proxy_Function> &funcs, const Dynamic_Cast_Conversions *t_conversions) std::function<Ret (Params...)> build_function_caller_helper(Ret (Params...), const std::vector<Const_Proxy_Function> &funcs, const Type_Conversions *t_conversions)
{ {
if (funcs.size() == 1) if (funcs.size() == 1)
{ {
@@ -90,7 +110,7 @@ namespace chaiscript
// we cannot make any other guesses or assumptions really, so continuing // we cannot make any other guesses or assumptions really, so continuing
} }
return std::function<Ret (Params...)>(Build_Function_Caller_Helper<Ret, Params...>(funcs, t_conversions?*t_conversions:Dynamic_Cast_Conversions())); return std::function<Ret (Params...)>(Build_Function_Caller_Helper<Ret, Params...>(funcs, t_conversions?*t_conversions:Type_Conversions()));
} }
} }
} }

View File

@@ -7,14 +7,20 @@
#ifndef CHAISCRIPT_HANDLE_RETURN_HPP_ #ifndef CHAISCRIPT_HANDLE_RETURN_HPP_
#define CHAISCRIPT_HANDLE_RETURN_HPP_ #define CHAISCRIPT_HANDLE_RETURN_HPP_
#include "boxed_value.hpp" #include <functional>
#include "boxed_number.hpp" #include <memory>
#include "type_info.hpp"
#include <string>
#include <stdexcept> #include <stdexcept>
#include <string>
#include <vector> #include <vector>
#include "boxed_number.hpp"
#include "boxed_value.hpp"
#include "type_info.hpp"
namespace chaiscript {
class Boxed_Number;
} // namespace chaiscript
namespace chaiscript namespace chaiscript
{ {
namespace dispatch namespace dispatch
@@ -42,6 +48,15 @@ namespace chaiscript
} }
}; };
template<typename Ret>
struct Handle_Return<const Ret *>
{
static Boxed_Value handle(const Ret *p)
{
return Boxed_Value(p);
}
};
template<typename Ret> template<typename Ret>
struct Handle_Return<std::shared_ptr<Ret> &> struct Handle_Return<std::shared_ptr<Ret> &>
{ {

View File

@@ -8,6 +8,7 @@
#define CHAISCRIPT_OPERATORS_HPP_ #define CHAISCRIPT_OPERATORS_HPP_
#include "../chaiscript_defines.hpp" #include "../chaiscript_defines.hpp"
#include "register_function.hpp"
namespace chaiscript namespace chaiscript
{ {
@@ -15,442 +16,446 @@ namespace chaiscript
{ {
namespace operators namespace operators
{ {
template<typename Ret, typename L, typename R> namespace detail
Ret assign(L l, R r) {
{ /// \todo make this return a decltype once we drop gcc 4.6
return (l = r); template<typename L, typename R>
} auto assign(L l, R r) -> L&
{
return (l = r);
}
template<typename Ret, typename L, typename R> template<typename L, typename R>
Ret assign_bitwise_and(L l, R r) auto assign_bitwise_and(L l, R r) -> decltype((l &= r))
{ {
return (l &= r); return (l &= r);
} }
template<typename Ret, typename L, typename R> template<typename L, typename R>
Ret assign_xor(L l, R r) auto assign_xor(L l, R r) -> decltype((l^=r))
{ {
return (l ^= r); return (l ^= r);
} }
template<typename Ret, typename L, typename R> template<typename L, typename R>
Ret assign_bitwise_or(L l, R r) auto assign_bitwise_or(L l, R r) -> decltype((l |= r))
{ {
return (l |= r); return (l |= r);
} }
template<typename Ret, typename L, typename R> template<typename L, typename R>
Ret assign_difference(L l, R r) auto assign_difference(L l, R r) -> decltype(( l -= r))
{ {
return (l -= r); return (l -= r);
} }
template<typename Ret, typename L, typename R> template<typename L, typename R>
Ret assign_left_shift(L l, R r) auto assign_left_shift(L l, R r) -> decltype(( l <<= r))
{ {
return (l <<= r); return (l <<= r);
} }
template<typename Ret, typename L, typename R> template<typename L, typename R>
Ret assign_product(L l, R r) auto assign_product(L l, R r) -> decltype(( l *= r ))
{ {
return (l *= r); return (l *= r);
} }
template<typename Ret, typename L, typename R> template<typename L, typename R>
Ret assign_quotient(L l, R r) auto assign_quotient(L l, R r) -> decltype(( l /= r ))
{ {
return (l /= r); return (l /= r);
} }
template<typename Ret, typename L, typename R> template<typename L, typename R>
Ret assign_remainder(L l, R r) auto assign_remainder(L l, R r) -> decltype(( l %= r ))
{ {
return (l %= r); return (l %= r);
} }
template<typename Ret, typename L, typename R> template<typename L, typename R>
Ret assign_right_shift(L l, R r) auto assign_right_shift(L l, R r) -> decltype(( l >>= r))
{ {
return (l >>= r); return (l >>= r);
} }
template<typename Ret, typename L, typename R> /// \todo make this return a decltype once we drop gcc 4.6
Ret assign_sum(L l, R r) template<typename L, typename R>
{ auto assign_sum(L l, R r) -> L&
return (l += r); {
} return (l += r);
}
template<typename Ret, typename L> template<typename L>
Ret prefix_decrement(L l) auto prefix_decrement(L l) -> decltype(( --l ))
{ {
return (--l); return (--l);
} }
template<typename Ret, typename L> template<typename L>
Ret prefix_increment(L l) auto prefix_increment(L l) -> decltype(( ++l ))
{ {
return (++l); return (++l);
} }
template<typename Ret, typename L, typename R> template<typename L, typename R>
Ret equal(L l, R r) auto equal(L l, R r) -> decltype(( l == r ))
{ {
return (l == r); return (l == r);
} }
template<typename Ret, typename L, typename R> template<typename L, typename R>
Ret greater_than(L l, R r) auto greater_than(L l, R r) -> decltype(( l > r ))
{ {
return (l > r); return (l > r);
} }
template<typename Ret, typename L, typename R> template<typename L, typename R>
Ret greater_than_equal(L l, R r) auto greater_than_equal(L l, R r) -> decltype(( l >= r ))
{ {
return (l >= r); return (l >= r);
} }
template<typename Ret, typename L, typename R> template<typename L, typename R>
Ret less_than(L l, R r) auto less_than(L l, R r) -> decltype(( l < r ))
{ {
return (l < r); return (l < r);
} }
template<typename Ret, typename L, typename R> template<typename L, typename R>
Ret less_than_equal(L l, R r) auto less_than_equal(L l, R r) -> decltype(( l <= r ))
{ {
return (l <= r); return (l <= r);
} }
template<typename Ret, typename L> template<typename L>
Ret logical_compliment(L l) auto logical_compliment(L l) -> decltype(( !l ))
{ {
return (!l); return (!l);
} }
template<typename Ret, typename L, typename R> template<typename L, typename R>
Ret not_equal(L l, R r) auto not_equal(L l, R r) -> decltype(( l != r ))
{ {
return (l != r); return (l != r);
} }
template<typename Ret, typename L, typename R> template<typename L, typename R>
Ret addition(L l, R r) auto addition(L l, R r) -> decltype(( l + r ))
{ {
return (l + r); return (l + r);
} }
template<typename Ret, typename L> template<typename L>
Ret unary_plus(L l) auto unary_plus(L l) -> decltype(( +l ))
{ {
return (+l); return (+l);
} }
template<typename Ret, typename L, typename R> template<typename L, typename R>
Ret subtraction(L l, R r) auto subtraction(L l, R r) -> decltype(( l - r ))
{ {
return (l - r); return (l - r);
} }
template<typename Ret, typename L> template<typename L>
Ret unary_minus(L l) auto unary_minus(L l) -> decltype(( -l ))
{ {
#ifdef CHAISCRIPT_MSVC #ifdef CHAISCRIPT_MSVC
#pragma warning(push) #pragma warning(push)
#pragma warning(disable : 4146) #pragma warning(disable : 4146)
return (-l); return (-l);
#pragma warning(pop) #pragma warning(pop)
#else #else
return (-l); return (-l);
#endif #endif
} }
template<typename Ret, typename L, typename R> template<typename L, typename R>
Ret bitwise_and(L l, R r) auto bitwise_and(L l, R r) -> decltype(( l & r ))
{ {
return (l & r); return (l & r);
} }
template<typename Ret, typename L> template<typename L>
Ret bitwise_compliment(L l) auto bitwise_compliment(L l) -> decltype(( ~l ))
{ {
return (~l); return (~l);
} }
template<typename Ret, typename L, typename R> template<typename L, typename R>
Ret bitwise_xor(L l, R r) auto bitwise_xor(L l, R r) -> decltype(( l ^ r ))
{ {
return (l ^ r); return (l ^ r);
} }
template<typename Ret, typename L, typename R> template<typename L, typename R>
Ret bitwise_or(L l, R r) auto bitwise_or(L l, R r) -> decltype(( l | r ))
{ {
return (l | r); return (l | r);
} }
template<typename Ret, typename L, typename R> template<typename L, typename R>
Ret division(L l, R r) auto division(L l, R r) -> decltype(( l / r ))
{ {
return (l / r); return (l / r);
} }
template<typename Ret, typename L, typename R> template<typename L, typename R>
Ret left_shift(L l, R r) auto left_shift(L l, R r) -> decltype(( l << r ))
{ {
return l << r; return l << r;
} }
template<typename Ret, typename L, typename R> template<typename L, typename R>
Ret multiplication(L l, R r) auto multiplication(L l, R r) -> decltype(( l * r ))
{ {
return l * r; return l * r;
} }
template<typename Ret, typename L, typename R> template<typename L, typename R>
Ret remainder(L l, R r) auto remainder(L l, R r) -> decltype(( l % r ))
{ {
return (l % r); return (l % r);
} }
template<typename Ret, typename L, typename R>
Ret right_shift(L l, R r)
{
return (l >> r);
}
template<typename L, typename R>
auto right_shift(L l, R r) -> decltype(( l >> r ))
{
return (l >> r);
}
}
template<typename T> template<typename T>
ModulePtr assign(ModulePtr m = ModulePtr(new Module())) ModulePtr assign(ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun(&assign<T &, T &, const T&>), "="); m->add(chaiscript::fun(&detail::assign<T &, const T&>), "=");
return m; return m;
} }
template<typename T> template<typename T>
ModulePtr assign_bitwise_and(ModulePtr m = ModulePtr(new Module())) ModulePtr assign_bitwise_and(ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun(&assign_bitwise_and<T &, T &, const T&>), "&="); m->add(chaiscript::fun(&detail::assign_bitwise_and<T &, const T&>), "&=");
return m; return m;
} }
template<typename T> template<typename T>
ModulePtr assign_xor(ModulePtr m = ModulePtr(new Module())) ModulePtr assign_xor(ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun(&assign_xor<T &, T &, const T&>), "^="); m->add(chaiscript::fun(&detail::assign_xor<T &, const T&>), "^=");
return m; return m;
} }
template<typename T> template<typename T>
ModulePtr assign_bitwise_or(ModulePtr m = ModulePtr(new Module())) ModulePtr assign_bitwise_or(ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun(&assign_bitwise_or<T &, T &, const T&>), "|="); m->add(chaiscript::fun(&detail::assign_bitwise_or<T &, const T&>), "|=");
return m; return m;
} }
template<typename T> template<typename T>
ModulePtr assign_difference(ModulePtr m = ModulePtr(new Module())) ModulePtr assign_difference(ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun(&assign_difference<T &, T &, const T&>), "-="); m->add(chaiscript::fun(&detail::assign_difference<T &, const T&>), "-=");
return m; return m;
} }
template<typename T> template<typename T>
ModulePtr assign_left_shift(ModulePtr m = ModulePtr(new Module())) ModulePtr assign_left_shift(ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun(&assign_left_shift<T &, T &, const T&>), "<<="); m->add(chaiscript::fun(&detail::assign_left_shift<T &, const T&>), "<<=");
return m; return m;
} }
template<typename T> template<typename T>
ModulePtr assign_product(ModulePtr m = ModulePtr(new Module())) ModulePtr assign_product(ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun(&assign_product<T &, T &, const T&>), "*="); m->add(chaiscript::fun(&detail::assign_product<T &, const T&>), "*=");
return m; return m;
} }
template<typename T> template<typename T>
ModulePtr assign_quotient(ModulePtr m = ModulePtr(new Module())) ModulePtr assign_quotient(ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun(&assign_quotient<T &, T &, const T&>), "/="); m->add(chaiscript::fun(&detail::assign_quotient<T &, const T&>), "/=");
return m; return m;
} }
template<typename T> template<typename T>
ModulePtr assign_remainder(ModulePtr m = ModulePtr(new Module())) ModulePtr assign_remainder(ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun(&assign_remainder<T &, T &, const T&>), "%="); m->add(chaiscript::fun(&detail::assign_remainder<T &, const T&>), "%=");
return m; return m;
} }
template<typename T> template<typename T>
ModulePtr assign_right_shift(ModulePtr m = ModulePtr(new Module())) ModulePtr assign_right_shift(ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun(&assign_right_shift<T &, T &, const T&>), ">>="); m->add(chaiscript::fun(&detail::assign_right_shift<T &, const T&>), ">>=");
return m; return m;
} }
template<typename T> template<typename T>
ModulePtr assign_sum(ModulePtr m = ModulePtr(new Module())) ModulePtr assign_sum(ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun(&assign_sum<T &, T &, const T&>), "+="); m->add(chaiscript::fun(&detail::assign_sum<T &, const T&>), "+=");
return m; return m;
} }
template<typename T> template<typename T>
ModulePtr prefix_decrement(ModulePtr m = ModulePtr(new Module())) ModulePtr prefix_decrement(ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun(&prefix_decrement<T &, T &>), "--"); m->add(chaiscript::fun(&detail::prefix_decrement<T &>), "--");
return m; return m;
} }
template<typename T> template<typename T>
ModulePtr prefix_increment(ModulePtr m = ModulePtr(new Module())) ModulePtr prefix_increment(ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun(&prefix_increment<T &, T &>), "++"); m->add(chaiscript::fun(&detail::prefix_increment<T &>), "++");
return m; return m;
} }
template<typename T> template<typename T>
ModulePtr equal(ModulePtr m = ModulePtr(new Module())) ModulePtr equal(ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun(&equal<bool, const T&, const T&>), "=="); m->add(chaiscript::fun(&detail::equal<const T&, const T&>), "==");
return m; return m;
} }
template<typename T> template<typename T>
ModulePtr greater_than(ModulePtr m = ModulePtr(new Module())) ModulePtr greater_than(ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun(&greater_than<bool, const T&, const T&>), ">"); m->add(chaiscript::fun(&detail::greater_than<const T&, const T&>), ">");
return m; return m;
} }
template<typename T> template<typename T>
ModulePtr greater_than_equal(ModulePtr m = ModulePtr(new Module())) ModulePtr greater_than_equal(ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun(&greater_than_equal<bool, const T&, const T&>), ">="); m->add(chaiscript::fun(&detail::greater_than_equal<const T&, const T&>), ">=");
return m; return m;
} }
template<typename T> template<typename T>
ModulePtr less_than(ModulePtr m = ModulePtr(new Module())) ModulePtr less_than(ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun(&less_than<bool, const T&, const T&>), "<"); m->add(chaiscript::fun(&detail::less_than<const T&, const T&>), "<");
return m; return m;
} }
template<typename T> template<typename T>
ModulePtr less_than_equal(ModulePtr m = ModulePtr(new Module())) ModulePtr less_than_equal(ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun(&less_than_equal<bool, const T&, const T&>), "<="); m->add(chaiscript::fun(&detail::less_than_equal<const T&, const T&>), "<=");
return m; return m;
} }
template<typename T> template<typename T>
ModulePtr logical_compliment(ModulePtr m = ModulePtr(new Module())) ModulePtr logical_compliment(ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun(&logical_compliment<bool, const T &>), "!"); m->add(chaiscript::fun(&detail::logical_compliment<const T &>), "!");
return m; return m;
} }
template<typename T> template<typename T>
ModulePtr not_equal(ModulePtr m = ModulePtr(new Module())) ModulePtr not_equal(ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun(&not_equal<bool, const T &, const T &>), "!="); m->add(chaiscript::fun(&detail::not_equal<const T &, const T &>), "!=");
return m; return m;
} }
template<typename T> template<typename T>
ModulePtr addition(ModulePtr m = ModulePtr(new Module())) ModulePtr addition(ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun(&addition<T, const T &, const T &>), "+"); m->add(chaiscript::fun(&detail::addition<const T &, const T &>), "+");
return m; return m;
} }
template<typename T> template<typename T>
ModulePtr unary_plus(ModulePtr m = ModulePtr(new Module())) ModulePtr unary_plus(ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun(&unary_plus<T, const T &>), "+"); m->add(chaiscript::fun(&detail::unary_plus<const T &>), "+");
return m; return m;
} }
template<typename T> template<typename T>
ModulePtr subtraction(ModulePtr m = ModulePtr(new Module())) ModulePtr subtraction(ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun(&subtraction<T, const T &, const T &>), "-"); m->add(chaiscript::fun(&detail::subtraction<const T &, const T &>), "-");
return m; return m;
} }
template<typename T> template<typename T>
ModulePtr unary_minus(ModulePtr m = ModulePtr(new Module())) ModulePtr unary_minus(ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun(&unary_minus<T, const T &>), "-"); m->add(chaiscript::fun(&detail::unary_minus<const T &>), "-");
return m; return m;
} }
template<typename T> template<typename T>
ModulePtr bitwise_and(ModulePtr m = ModulePtr(new Module())) ModulePtr bitwise_and(ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun(&bitwise_and<T, const T &, const T &>), "&"); m->add(chaiscript::fun(&detail::bitwise_and<const T &, const T &>), "&");
return m; return m;
} }
template<typename T> template<typename T>
ModulePtr bitwise_compliment(ModulePtr m = ModulePtr(new Module())) ModulePtr bitwise_compliment(ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun(&bitwise_compliment<T, const T &>), "~"); m->add(chaiscript::fun(&detail::bitwise_compliment<const T &>), "~");
return m; return m;
} }
template<typename T> template<typename T>
ModulePtr bitwise_xor(ModulePtr m = ModulePtr(new Module())) ModulePtr bitwise_xor(ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun(&bitwise_xor<T, const T &, const T &>), "^"); m->add(chaiscript::fun(&detail::bitwise_xor<const T &, const T &>), "^");
return m; return m;
} }
template<typename T> template<typename T>
ModulePtr bitwise_or(ModulePtr m = ModulePtr(new Module())) ModulePtr bitwise_or(ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun(&bitwise_or<T, const T &, const T &>), "|"); m->add(chaiscript::fun(&detail::bitwise_or<const T &, const T &>), "|");
return m; return m;
} }
template<typename T> template<typename T>
ModulePtr division(ModulePtr m = ModulePtr(new Module())) ModulePtr division(ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun(&division<T, const T &, const T &>), "/"); m->add(chaiscript::fun(&detail::division<const T &, const T &>), "/");
return m; return m;
} }
template<typename T> template<typename T>
ModulePtr left_shift(ModulePtr m = ModulePtr(new Module())) ModulePtr left_shift(ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun(&left_shift<T, const T &, const T &>), "<<"); m->add(chaiscript::fun(&detail::left_shift<const T &, const T &>), "<<");
return m; return m;
} }
template<typename T> template<typename T>
ModulePtr multiplication(ModulePtr m = ModulePtr(new Module())) ModulePtr multiplication(ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun(&multiplication<T, const T &, const T &>), "*"); m->add(chaiscript::fun(&detail::multiplication<const T &, const T &>), "*");
return m; return m;
} }
template<typename T> template<typename T>
ModulePtr remainder(ModulePtr m = ModulePtr(new Module())) ModulePtr remainder(ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun(&remainder<T, const T &, const T &>), "%"); m->add(chaiscript::fun(&detail::remainder<const T &, const T &>), "%");
return m; return m;
} }
template<typename T> template<typename T>
ModulePtr right_shift(ModulePtr m = ModulePtr(new Module())) ModulePtr right_shift(ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun(&right_shift<T, const T &, const T &>), ">>"); m->add(chaiscript::fun(&detail::right_shift<const T &, const T &>), ">>");
return m; return m;
} }
} }

View File

@@ -21,7 +21,7 @@ namespace chaiscript
template<typename Class, typename ... Params> template<typename Class, typename ... Params>
std::shared_ptr<Class> constructor_(Params ... params) std::shared_ptr<Class> constructor_(Params ... params)
{ {
return std::shared_ptr<Class>(new Class(params...)); return std::make_shared<Class>(params...);
} }
template<typename Class, typename ... Params > template<typename Class, typename ... Params >
@@ -48,7 +48,7 @@ namespace chaiscript
template<typename T> template<typename T>
Proxy_Function constructor() Proxy_Function constructor()
{ {
T *f = 0; T *f = nullptr;
return (dispatch::detail::build_constructor_(f)); return (dispatch::detail::build_constructor_(f));
} }

View File

@@ -9,21 +9,36 @@
#define CHAISCRIPT_PROXY_FUNCTIONS_HPP_ #define CHAISCRIPT_PROXY_FUNCTIONS_HPP_
#include "boxed_value.hpp" #include <algorithm>
#include "type_info.hpp" #include <cassert>
#include <functional>
#include <memory>
#include <stdexcept>
#include <string> #include <string>
#include <type_traits> #include <type_traits>
#include <stdexcept>
#include <vector> #include <vector>
#include <cassert>
#include "../chaiscript_defines.hpp"
#include "boxed_cast.hpp"
#include "boxed_cast_helper.hpp"
#include "boxed_value.hpp"
#include "proxy_functions_detail.hpp" #include "proxy_functions_detail.hpp"
#include "type_info.hpp"
namespace chaiscript {
class Type_Conversions;
namespace exception {
class bad_boxed_cast;
struct arity_error;
} // namespace exception
} // namespace chaiscript
namespace chaiscript namespace chaiscript
{ {
class Boxed_Number; class Boxed_Number;
struct AST_Node; struct AST_Node;
typedef std::shared_ptr<struct AST_Node> AST_NodePtr; typedef std::shared_ptr<AST_Node> AST_NodePtr;
namespace dispatch namespace dispatch
{ {
@@ -40,7 +55,7 @@ namespace chaiscript
public: public:
virtual ~Proxy_Function_Base() {} virtual ~Proxy_Function_Base() {}
Boxed_Value operator()(const std::vector<Boxed_Value> &params, const chaiscript::Dynamic_Cast_Conversions &t_conversions) const Boxed_Value operator()(const std::vector<Boxed_Value> &params, const chaiscript::Type_Conversions &t_conversions) const
{ {
Boxed_Value bv = do_call(params, t_conversions); Boxed_Value bv = do_call(params, t_conversions);
return bv; return bv;
@@ -48,12 +63,12 @@ namespace chaiscript
/// Returns a vector containing all of the types of the parameters the function returns/takes /// Returns a vector containing all of the types of the parameters the function returns/takes
/// if the function is variadic or takes no arguments (arity of 0 or -1), the returned /// if the function is variadic or takes no arguments (arity of 0 or -1), the returned
/// value containes exactly 1 Type_Info object: the return type /// value contains exactly 1 Type_Info object: the return type
/// \returns the types of all parameters. /// \returns the types of all parameters.
const std::vector<Type_Info> &get_param_types() const { return m_types; } const std::vector<Type_Info> &get_param_types() const { return m_types; }
virtual bool operator==(const Proxy_Function_Base &) const = 0; virtual bool operator==(const Proxy_Function_Base &) const = 0;
virtual bool call_match(const std::vector<Boxed_Value> &vals, const Dynamic_Cast_Conversions &t_conversions) const = 0; virtual bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions &t_conversions) const = 0;
bool has_arithmetic_param() const bool has_arithmetic_param() const
{ {
@@ -67,15 +82,13 @@ namespace chaiscript
//! Return true if the function is a possible match //! Return true if the function is a possible match
//! to the passed in values //! to the passed in values
bool filter(const std::vector<Boxed_Value> &vals, const Dynamic_Cast_Conversions &t_conversions) const bool filter(const std::vector<Boxed_Value> &vals, const Type_Conversions &t_conversions) const
{ {
int arity = get_arity(); if (m_arity < 0)
if (arity < 0)
{ {
return true; return true;
} else if (size_t(arity) == vals.size()) { } else if (size_t(m_arity) == vals.size()) {
if (arity == 0) if (m_arity == 0)
{ {
return true; return true;
} else { } else {
@@ -87,11 +100,14 @@ namespace chaiscript
} }
/// \returns the number of arguments the function takes or -1 if it is variadic /// \returns the number of arguments the function takes or -1 if it is variadic
virtual int get_arity() const = 0; int get_arity() const
{
return m_arity;
}
virtual std::string annotation() const = 0; virtual std::string annotation() const = 0;
static bool compare_type_to_param(const Type_Info &ti, const Boxed_Value &bv, const Dynamic_Cast_Conversions &t_conversions) static bool compare_type_to_param(const Type_Info &ti, const Boxed_Value &bv, const Type_Conversions &t_conversions)
{ {
if (ti.is_undef() if (ti.is_undef()
|| ti.bare_equal(user_type<Boxed_Value>()) || ti.bare_equal(user_type<Boxed_Value>())
@@ -99,7 +115,7 @@ namespace chaiscript
&& (ti.bare_equal(user_type<Boxed_Number>()) && (ti.bare_equal(user_type<Boxed_Number>())
|| ti.bare_equal(bv.get_type_info()) || ti.bare_equal(bv.get_type_info())
|| bv.get_type_info().bare_equal(user_type<std::shared_ptr<const Proxy_Function_Base> >()) || bv.get_type_info().bare_equal(user_type<std::shared_ptr<const Proxy_Function_Base> >())
|| t_conversions.dynamic_cast_converts(ti, bv.get_type_info()) || t_conversions.converts(ti, bv.get_type_info())
) )
) )
) )
@@ -110,10 +126,10 @@ namespace chaiscript
} }
} }
protected: protected:
virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions) const = 0; virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions) const = 0;
Proxy_Function_Base(const std::vector<Type_Info> &t_types) Proxy_Function_Base(std::vector<Type_Info> t_types, int t_arity)
: m_types(t_types), m_has_arithmetic_param(false) : m_types(std::move(t_types)), m_has_arithmetic_param(false), m_arity(t_arity)
{ {
for (size_t i = 1; i < m_types.size(); ++i) for (size_t i = 1; i < m_types.size(); ++i)
{ {
@@ -126,7 +142,7 @@ namespace chaiscript
} }
virtual bool compare_first_type(const Boxed_Value &bv, const Dynamic_Cast_Conversions &t_conversions) const virtual bool compare_first_type(const Boxed_Value &bv, const Type_Conversions &t_conversions) const
{ {
const std::vector<Type_Info> &types = get_param_types(); const std::vector<Type_Info> &types = get_param_types();
@@ -160,14 +176,14 @@ namespace chaiscript
std::vector<Type_Info> m_types; std::vector<Type_Info> m_types;
bool m_has_arithmetic_param; bool m_has_arithmetic_param;
int m_arity;
}; };
} }
/// \brief Common typedef used for passing of any registered function in ChaiScript /// \brief Common typedef used for passing of any registered function in ChaiScript
typedef std::shared_ptr<dispatch::Proxy_Function_Base> Proxy_Function; typedef std::shared_ptr<dispatch::Proxy_Function_Base> Proxy_Function;
/// \brief Const version of Proxy_Function chaiscript. Points to a const Proxy_Function. This is how most registered functions /// \brief Const version of Proxy_Function. Points to a const Proxy_Function. This is how most registered functions
/// are handled internally. /// are handled internally.
typedef std::shared_ptr<const dispatch::Proxy_Function_Base> Const_Proxy_Function; typedef std::shared_ptr<const dispatch::Proxy_Function_Base> Const_Proxy_Function;
@@ -196,19 +212,19 @@ namespace chaiscript
{ {
public: public:
Dynamic_Proxy_Function( Dynamic_Proxy_Function(
const std::function<Boxed_Value (const std::vector<Boxed_Value> &)> &t_f, std::function<Boxed_Value (const std::vector<Boxed_Value> &)> t_f,
int t_arity=-1, int t_arity=-1,
const AST_NodePtr &t_parsenode = AST_NodePtr(), AST_NodePtr t_parsenode = AST_NodePtr(),
const std::string &t_description = "", std::string t_description = "",
const Proxy_Function &t_guard = Proxy_Function()) Proxy_Function t_guard = Proxy_Function())
: Proxy_Function_Base(build_param_type_list(t_arity)), : Proxy_Function_Base(build_param_type_list(t_arity), t_arity),
m_f(t_f), m_arity(t_arity), m_description(t_description), m_guard(t_guard), m_parsenode(t_parsenode) m_f(std::move(t_f)), m_arity(t_arity), m_description(std::move(t_description)), m_guard(std::move(t_guard)), m_parsenode(std::move(t_parsenode))
{ {
} }
virtual ~Dynamic_Proxy_Function() {} virtual ~Dynamic_Proxy_Function() {}
virtual bool operator==(const Proxy_Function_Base &rhs) const virtual bool operator==(const Proxy_Function_Base &rhs) const CHAISCRIPT_OVERRIDE
{ {
const Dynamic_Proxy_Function *prhs = dynamic_cast<const Dynamic_Proxy_Function *>(&rhs); const Dynamic_Proxy_Function *prhs = dynamic_cast<const Dynamic_Proxy_Function *>(&rhs);
@@ -218,16 +234,12 @@ namespace chaiscript
&& !this->m_guard && !prhs->m_guard); && !this->m_guard && !prhs->m_guard);
} }
virtual bool call_match(const std::vector<Boxed_Value> &vals, const Dynamic_Cast_Conversions &t_conversions) const virtual bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
{ {
return (m_arity < 0 || vals.size() == size_t(m_arity)) return (m_arity < 0 || vals.size() == size_t(m_arity))
&& test_guard(vals, t_conversions); && test_guard(vals, t_conversions);
} }
virtual int get_arity() const
{
return m_arity;
}
Proxy_Function get_guard() const Proxy_Function get_guard() const
{ {
@@ -239,13 +251,13 @@ namespace chaiscript
return m_parsenode; return m_parsenode;
} }
virtual std::string annotation() const virtual std::string annotation() const CHAISCRIPT_OVERRIDE
{ {
return m_description; return m_description;
} }
protected: protected:
virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions) const virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
{ {
if (m_arity < 0 || params.size() == size_t(m_arity)) if (m_arity < 0 || params.size() == size_t(m_arity))
{ {
@@ -263,7 +275,7 @@ namespace chaiscript
} }
private: private:
bool test_guard(const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions) const bool test_guard(const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions) const
{ {
if (m_guard) if (m_guard)
{ {
@@ -323,25 +335,25 @@ namespace chaiscript
public: public:
Bound_Function(const Const_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)
: Proxy_Function_Base(build_param_type_info(t_f, t_args)), : Proxy_Function_Base(build_param_type_info(t_f, t_args), (t_f->get_arity()<0?-1:static_cast<int>(build_param_type_info(t_f, t_args).size())-1)),
m_f(t_f), m_args(t_args), m_arity(t_f->get_arity()<0?-1:static_cast<int>(get_param_types().size())-1) m_f(t_f), m_args(t_args)
{ {
assert(m_f->get_arity() < 0 || m_f->get_arity() == static_cast<int>(m_args.size())); assert(m_f->get_arity() < 0 || m_f->get_arity() == static_cast<int>(m_args.size()));
} }
virtual bool operator==(const Proxy_Function_Base &t_f) const virtual bool operator==(const Proxy_Function_Base &t_f) const CHAISCRIPT_OVERRIDE
{ {
return &t_f == this; return &t_f == this;
} }
virtual ~Bound_Function() {} virtual ~Bound_Function() {}
virtual bool call_match(const std::vector<Boxed_Value> &vals, const Dynamic_Cast_Conversions &t_conversions) const virtual bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
{ {
return m_f->call_match(build_param_list(vals), t_conversions); return m_f->call_match(build_param_list(vals), t_conversions);
} }
virtual std::vector<Const_Proxy_Function> get_contained_functions() const virtual std::vector<Const_Proxy_Function> get_contained_functions() const CHAISCRIPT_OVERRIDE
{ {
std::vector<Const_Proxy_Function> fs; std::vector<Const_Proxy_Function> fs;
fs.push_back(m_f); fs.push_back(m_f);
@@ -351,10 +363,8 @@ namespace chaiscript
std::vector<Boxed_Value> build_param_list(const std::vector<Boxed_Value> &params) const std::vector<Boxed_Value> build_param_list(const std::vector<Boxed_Value> &params) const
{ {
typedef std::vector<Boxed_Value>::const_iterator pitr; auto parg = params.begin();
auto barg = m_args.begin();
pitr parg = params.begin();
pitr barg = m_args.begin();
std::vector<Boxed_Value> args; std::vector<Boxed_Value> args;
@@ -382,12 +392,7 @@ namespace chaiscript
return args; return args;
} }
virtual int get_arity() const virtual std::string annotation() const CHAISCRIPT_OVERRIDE
{
return m_arity;
}
virtual std::string annotation() const
{ {
return "Bound: " + m_f->annotation(); return "Bound: " + m_f->annotation();
} }
@@ -416,7 +421,7 @@ namespace chaiscript
return retval; return retval;
} }
virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions) const virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
{ {
return (*m_f)(build_param_list(params), t_conversions); return (*m_f)(build_param_list(params), t_conversions);
} }
@@ -424,7 +429,34 @@ namespace chaiscript
private: private:
Const_Proxy_Function m_f; Const_Proxy_Function m_f;
std::vector<Boxed_Value> m_args; std::vector<Boxed_Value> m_args;
int m_arity; };
class Proxy_Function_Impl_Base : public Proxy_Function_Base
{
public:
Proxy_Function_Impl_Base(const std::vector<Type_Info> &t_types)
: Proxy_Function_Base(t_types, static_cast<int>(t_types.size()) - 1)
{
}
virtual ~Proxy_Function_Impl_Base() {}
virtual std::string annotation() const CHAISCRIPT_OVERRIDE
{
return "";
}
virtual bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
{
if (int(vals.size()) != get_arity())
{
return false;
}
return compare_types(m_types, vals) || compare_types_with_cast(vals, t_conversions);
}
virtual bool compare_types_with_cast(const std::vector<Boxed_Value> &vals, const Type_Conversions &t_conversions) const = 0;
}; };
/** /**
@@ -433,41 +465,25 @@ namespace chaiscript
* 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_Base class Proxy_Function_Impl : public Proxy_Function_Impl_Base
{ {
public: public:
Proxy_Function_Impl(const std::function<Func> &f) Proxy_Function_Impl(std::function<Func> f)
: Proxy_Function_Base(detail::build_param_type_list(static_cast<Func *>(0))), : Proxy_Function_Impl_Base(detail::build_param_type_list(static_cast<Func *>(nullptr))),
m_f(f), m_dummy_func(0) m_f(std::move(f)), m_dummy_func(nullptr)
{ {
} }
virtual ~Proxy_Function_Impl() {} virtual ~Proxy_Function_Impl() {}
virtual bool operator==(const Proxy_Function_Base &t_func) const virtual bool compare_types_with_cast(const std::vector<Boxed_Value> &vals, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
{ {
const Proxy_Function_Impl *pimpl = dynamic_cast<const Proxy_Function_Impl<Func> *>(&t_func); return detail::compare_types_cast(m_dummy_func, vals, t_conversions);
return pimpl != 0;
} }
virtual int get_arity() const virtual bool operator==(const Proxy_Function_Base &t_func) const CHAISCRIPT_OVERRIDE
{ {
return static_cast<int>(m_types.size()) - 1; return dynamic_cast<const Proxy_Function_Impl<Func> *>(&t_func) != nullptr;
}
virtual bool call_match(const std::vector<Boxed_Value> &vals, const Dynamic_Cast_Conversions &t_conversions) const
{
if (int(vals.size()) != get_arity())
{
return false;
}
return compare_types(m_types, vals) || detail::compare_types_cast(m_dummy_func, vals, t_conversions);
}
virtual std::string annotation() const
{
return "";
} }
std::function<Func> internal_function() const std::function<Func> internal_function() const
@@ -476,7 +492,7 @@ namespace chaiscript
} }
protected: protected:
virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions) const virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions) const
{ {
return detail::Do_Call<typename std::function<Func>::result_type>::go(m_f, params, t_conversions); return detail::Do_Call<typename std::function<Func>::result_type>::go(m_f, params, t_conversions);
} }
@@ -494,14 +510,14 @@ namespace chaiscript
{ {
public: public:
Attribute_Access(T Class::* t_attr) Attribute_Access(T Class::* t_attr)
: Proxy_Function_Base(param_types()), : Proxy_Function_Base(param_types(), 1),
m_attr(t_attr) m_attr(t_attr)
{ {
} }
virtual ~Attribute_Access() {} virtual ~Attribute_Access() {}
virtual bool operator==(const Proxy_Function_Base &t_func) const virtual bool operator==(const Proxy_Function_Base &t_func) const CHAISCRIPT_OVERRIDE
{ {
const Attribute_Access<T, Class> * aa const Attribute_Access<T, Class> * aa
= dynamic_cast<const Attribute_Access<T, Class> *>(&t_func); = dynamic_cast<const Attribute_Access<T, Class> *>(&t_func);
@@ -513,13 +529,7 @@ namespace chaiscript
} }
} }
virtual bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions &) const CHAISCRIPT_OVERRIDE
virtual int get_arity() const
{
return 1;
}
virtual bool call_match(const std::vector<Boxed_Value> &vals, const Dynamic_Cast_Conversions &) const
{ {
if (vals.size() != 1) if (vals.size() != 1)
{ {
@@ -529,13 +539,13 @@ namespace chaiscript
return vals[0].get_type_info().bare_equal(user_type<Class>()); return vals[0].get_type_info().bare_equal(user_type<Class>());
} }
virtual std::string annotation() const virtual std::string annotation() const CHAISCRIPT_OVERRIDE
{ {
return ""; return "";
} }
protected: protected:
virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions) const virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
{ {
if (params.size() == 1) if (params.size() == 1)
{ {
@@ -573,9 +583,9 @@ namespace chaiscript
class dispatch_error : public std::runtime_error class dispatch_error : public std::runtime_error
{ {
public: public:
dispatch_error(const std::vector<Boxed_Value> &t_parameters, dispatch_error(std::vector<Boxed_Value> t_parameters,
const std::vector<Const_Proxy_Function> &t_functions) std::vector<Const_Proxy_Function> t_functions)
: std::runtime_error("Error with function dispatch"), parameters(t_parameters), functions(t_functions) : std::runtime_error("Error with function dispatch"), parameters(std::move(t_parameters)), functions(std::move(t_functions))
{ {
} }
@@ -592,7 +602,7 @@ namespace chaiscript
{ {
template<typename FuncType> template<typename FuncType>
bool types_match_except_for_arithmetic(const FuncType &t_func, const std::vector<Boxed_Value> &plist, bool types_match_except_for_arithmetic(const FuncType &t_func, const std::vector<Boxed_Value> &plist,
const Dynamic_Cast_Conversions &t_conversions) const Type_Conversions &t_conversions)
{ {
if (t_func->get_arity() != static_cast<int>(plist.size())) if (t_func->get_arity() != static_cast<int>(plist.size()))
{ {
@@ -620,7 +630,7 @@ namespace chaiscript
template<typename InItr> template<typename InItr>
Boxed_Value dispatch_with_conversions(InItr begin, const InItr &end, const std::vector<Boxed_Value> &plist, Boxed_Value dispatch_with_conversions(InItr begin, const InItr &end, const std::vector<Boxed_Value> &plist,
const Dynamic_Cast_Conversions &t_conversions) const Type_Conversions &t_conversions)
{ {
InItr orig(begin); InItr orig(begin);
@@ -682,17 +692,42 @@ namespace chaiscript
* 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
*/ */
template<typename InItr> template<typename Funcs>
Boxed_Value dispatch(InItr begin, const InItr &end, Boxed_Value dispatch(const Funcs &funcs,
const std::vector<Boxed_Value> &plist, const Dynamic_Cast_Conversions &t_conversions) const std::vector<Boxed_Value> &plist, const Type_Conversions &t_conversions)
{ {
InItr orig(begin);
while (begin != end) std::multimap<size_t, const Proxy_Function_Base *> ordered_funcs;
for (const auto &func : funcs)
{
size_t numdiffs = 0;
const auto arity = func->get_arity();
if (arity == -1)
{
numdiffs = plist.size();
} else if (arity == static_cast<int>(plist.size())) {
for (size_t i = 0; i < plist.size(); ++i)
{
if (!func->get_param_types()[i+1].bare_equal(plist[i].get_type_info()))
{
++numdiffs;
}
}
} else {
continue;
}
ordered_funcs.insert(std::make_pair(numdiffs, func.get()));
}
for (const auto &func : ordered_funcs )
{ {
try { try {
if ((*begin)->filter(plist, t_conversions)) if (func.second->filter(plist, t_conversions))
{ {
return (*(*begin))(plist, t_conversions); return (*(func.second))(plist, t_conversions);
} }
} catch (const exception::bad_boxed_cast &) { } catch (const exception::bad_boxed_cast &) {
//parameter failed to cast, try again //parameter failed to cast, try again
@@ -702,22 +737,9 @@ namespace chaiscript
//guard failed to allow the function to execute, //guard failed to allow the function to execute,
//try again //try again
} }
++begin;
} }
return detail::dispatch_with_conversions(orig, end, plist, t_conversions); return detail::dispatch_with_conversions(funcs.cbegin(), funcs.cend(), plist, t_conversions);
}
/**
* 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, const Dynamic_Cast_Conversions &t_conversions)
{
return dispatch::dispatch(funcs.begin(), funcs.end(), plist, t_conversions);
} }
} }
} }

View File

@@ -7,15 +7,25 @@
#ifndef CHAISCRIPT_PROXY_FUNCTIONS_DETAIL_HPP_ #ifndef CHAISCRIPT_PROXY_FUNCTIONS_DETAIL_HPP_
#define CHAISCRIPT_PROXY_FUNCTIONS_DETAIL_HPP_ #define CHAISCRIPT_PROXY_FUNCTIONS_DETAIL_HPP_
#include "boxed_value.hpp" #include <algorithm>
#include "boxed_cast.hpp" #include <functional>
#include "type_info.hpp"
#include "handle_return.hpp"
#include <string>
#include <stdexcept> #include <stdexcept>
#include <string>
#include <vector> #include <vector>
#include "../chaiscript_defines.hpp"
#include "boxed_cast.hpp"
#include "boxed_value.hpp"
#include "handle_return.hpp"
#include "type_info.hpp"
namespace chaiscript {
class Type_Conversions;
namespace exception {
class bad_boxed_cast;
} // namespace exception
} // namespace chaiscript
namespace chaiscript namespace chaiscript
{ {
namespace exception namespace exception
@@ -43,29 +53,6 @@ namespace chaiscript
{ {
namespace detail namespace detail
{ {
template<typename ... Rest>
struct Build_Param_Type_List;
template<typename Param, typename ... Rest>
struct Build_Param_Type_List<Param, Rest...>
{
static void build(std::vector<Type_Info> &t_params)
{
t_params.push_back(chaiscript::detail::Get_Type_Info<Param>::get());
Build_Param_Type_List<Rest...>::build(t_params);
}
};
// 0th case
template<>
struct Build_Param_Type_List<>
{
static void build(std::vector<Type_Info> &)
{
}
};
/** /**
* Used by Proxy_Function_Impl to return a list of all param types * Used by Proxy_Function_Impl to return a list of all param types
* it contains. * it contains.
@@ -73,12 +60,8 @@ namespace chaiscript
template<typename Ret, typename ... Params> template<typename Ret, typename ... Params>
std::vector<Type_Info> build_param_type_list(Ret (*)(Params...)) std::vector<Type_Info> build_param_type_list(Ret (*)(Params...))
{ {
/// \todo this code was previously using { chaiscript::detail::Get_Type_Info<Ret>::get()... } /// \note somehow this is responsible for a large part of the code generation
/// but this seems to indicate another bug with MSVC's uniform initializer lists return { user_type<Ret>(), user_type<Params>()... };
std::vector<Type_Info> params;
params.push_back(chaiscript::detail::Get_Type_Info<Ret>::get());
Build_Param_Type_List<Params...>::build(params);
return params;
} }
@@ -89,7 +72,7 @@ namespace chaiscript
template<typename Param, typename ... Rest> template<typename Param, typename ... Rest>
struct Try_Cast<Param, Rest...> struct Try_Cast<Param, Rest...>
{ {
static void do_try(const std::vector<Boxed_Value> &params, int generation, const Dynamic_Cast_Conversions &t_conversions) static void do_try(const std::vector<Boxed_Value> &params, int generation, const Type_Conversions &t_conversions)
{ {
boxed_cast<Param>(params[generation], &t_conversions); boxed_cast<Param>(params[generation], &t_conversions);
Try_Cast<Rest...>::do_try(params, generation+1, t_conversions); Try_Cast<Rest...>::do_try(params, generation+1, t_conversions);
@@ -100,20 +83,20 @@ namespace chaiscript
template<> template<>
struct Try_Cast<> struct Try_Cast<>
{ {
static void do_try(const std::vector<Boxed_Value> &, int, const Dynamic_Cast_Conversions &) static void do_try(const std::vector<Boxed_Value> &, int, const Type_Conversions &)
{ {
} }
}; };
/** /**
* Used by Proxy_Function_Impl to determine if it is equivalent to another * Used by Proxy_Function_Impl to determine if it is equivalent to another
* Proxy_Function_Impl object. This function is primarly used to prevent * Proxy_Function_Impl object. This function is primarily used to prevent
* registration of two functions with the exact same signatures * registration of two functions with the exact same signatures
*/ */
template<typename Ret, typename ... Params> template<typename Ret, typename ... Params>
bool compare_types_cast(Ret (*)(Params...), bool compare_types_cast(Ret (*)(Params...),
const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions) const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions)
{ {
try { try {
Try_Cast<Params...>::do_try(params, 0, t_conversions); Try_Cast<Params...>::do_try(params, 0, t_conversions);
@@ -130,7 +113,7 @@ namespace chaiscript
template<typename ... InnerParams> template<typename ... InnerParams>
static Ret do_call(const std::function<Ret (Params...)> &f, static Ret do_call(const std::function<Ret (Params...)> &f,
const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions, InnerParams &&... innerparams) const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions, InnerParams &&... innerparams)
{ {
return Call_Func<Ret, count - 1, Params...>::do_call(f, params, t_conversions, std::forward<InnerParams>(innerparams)..., params[sizeof...(Params) - count]); return Call_Func<Ret, count - 1, Params...>::do_call(f, params, t_conversions, std::forward<InnerParams>(innerparams)..., params[sizeof...(Params) - count]);
} }
@@ -145,7 +128,7 @@ namespace chaiscript
#endif #endif
template<typename ... InnerParams> template<typename ... InnerParams>
static Ret do_call(const std::function<Ret (Params...)> &f, static Ret do_call(const std::function<Ret (Params...)> &f,
const std::vector<Boxed_Value> &, const Dynamic_Cast_Conversions &t_conversions, InnerParams &&... innerparams) const std::vector<Boxed_Value> &, const Type_Conversions &t_conversions, InnerParams &&... innerparams)
{ {
return f(boxed_cast<Params>(std::forward<InnerParams>(innerparams), &t_conversions)...); return f(boxed_cast<Params>(std::forward<InnerParams>(innerparams), &t_conversions)...);
} }
@@ -156,13 +139,13 @@ namespace chaiscript
/** /**
* Used by Proxy_Function_Impl to perform typesafe execution of a function. * Used by Proxy_Function_Impl to perform typesafe execution of a function.
* The function attempts to unbox each paramter to the expected type. * The function attempts to unbox each parameter to the expected type.
* if any unboxing fails the execution of the function fails and * if any unboxing fails the execution of the function fails and
* the bad_boxed_cast is passed up to the caller. * the bad_boxed_cast is passed up to the caller.
*/ */
template<typename Ret, typename ... Params> template<typename Ret, typename ... Params>
Ret call_func(const std::function<Ret (Params...)> &f, Ret call_func(const std::function<Ret (Params...)> &f,
const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions) const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions)
{ {
if (params.size() == sizeof...(Params)) if (params.size() == sizeof...(Params))
{ {
@@ -171,7 +154,7 @@ namespace chaiscript
throw exception::arity_error(static_cast<int>(params.size()), sizeof...(Params)); throw exception::arity_error(static_cast<int>(params.size()), sizeof...(Params));
} }
} }
} }
@@ -188,7 +171,7 @@ namespace chaiscript
struct Do_Call struct Do_Call
{ {
template<typename Fun> template<typename Fun>
static Boxed_Value go(const std::function<Fun> &fun, const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions) static Boxed_Value go(const std::function<Fun> &fun, const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions)
{ {
return Handle_Return<Ret>::handle(call_func(fun, params, t_conversions)); return Handle_Return<Ret>::handle(call_func(fun, params, t_conversions));
} }
@@ -198,7 +181,7 @@ namespace chaiscript
struct Do_Call<void> struct Do_Call<void>
{ {
template<typename Fun> template<typename Fun>
static Boxed_Value go(const std::function<Fun> &fun, const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions) static Boxed_Value go(const std::function<Fun> &fun, const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions)
{ {
call_func(fun, params, t_conversions); call_func(fun, params, t_conversions);
return Handle_Return<void>::handle(); return Handle_Return<void>::handle();

View File

@@ -7,8 +7,12 @@
#ifndef CHAISCRIPT_REGISTER_FUNCTION_HPP_ #ifndef CHAISCRIPT_REGISTER_FUNCTION_HPP_
#define CHAISCRIPT_REGISTER_FUNCTION_HPP_ #define CHAISCRIPT_REGISTER_FUNCTION_HPP_
#include "dispatchkit.hpp" #include <functional>
#include <type_traits>
#include "bind_first.hpp" #include "bind_first.hpp"
#include "dispatchkit.hpp"
#include "proxy_functions.hpp"
namespace chaiscript namespace chaiscript
{ {
@@ -92,7 +96,7 @@ namespace chaiscript
/// chai.add(fun(&MyClass::memberdata), "memberdata"); /// chai.add(fun(&MyClass::memberdata), "memberdata");
/// \endcode /// \endcode
/// ///
/// \sa \ref addingfunctions /// \sa \ref adding_functions
template<typename T> template<typename T>
Proxy_Function fun(T t) Proxy_Function fun(T t)
{ {
@@ -110,7 +114,7 @@ namespace chaiscript
/// chai.add(fun(f), "some_function"); /// chai.add(fun(f), "some_function");
/// \endcode /// \endcode
/// ///
/// \sa \ref addingfunctions /// \sa \ref adding_functions
template<typename T> template<typename T>
Proxy_Function fun(const std::function<T> &f) Proxy_Function fun(const std::function<T> &f)
{ {
@@ -135,7 +139,7 @@ namespace chaiscript
/// chai.add(fun(&MyClass::memberfunction, std::ref(obj)), "memberfunction"); /// chai.add(fun(&MyClass::memberfunction, std::ref(obj)), "memberfunction");
/// \endcode /// \endcode
/// ///
/// \sa \ref addingfunctions /// \sa \ref adding_functions
template<typename T, typename Q> template<typename T, typename Q>
Proxy_Function fun(T t, const Q &q) Proxy_Function fun(T t, const Q &q)
{ {
@@ -161,7 +165,7 @@ namespace chaiscript
/// chai.add(fun(&MyClass::memberfunction, std::ref(obj), 1), "memberfunction"); /// chai.add(fun(&MyClass::memberfunction, std::ref(obj), 1), "memberfunction");
/// \endcode /// \endcode
/// ///
/// \sa \ref addingfunctions /// \sa \ref adding_functions
template<typename T, typename Q, typename R> template<typename T, typename Q, typename R>
Proxy_Function fun(T t, const Q &q, const R &r) Proxy_Function fun(T t, const Q &q, const R &r)
{ {

View File

@@ -0,0 +1,443 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_DYNAMIC_CAST_CONVERSION_HPP_
#define CHAISCRIPT_DYNAMIC_CAST_CONVERSION_HPP_
#include <atomic>
#include <memory>
#include <set>
#include <stdexcept>
#include <string>
#include <type_traits>
#include <typeinfo>
#include "../chaiscript_threading.hpp"
#include "bad_boxed_cast.hpp"
#include "boxed_cast_helper.hpp"
#include "boxed_value.hpp"
#include "type_info.hpp"
namespace chaiscript
{
namespace exception
{
class bad_boxed_dynamic_cast : public bad_boxed_cast
{
public:
bad_boxed_dynamic_cast(const Type_Info &t_from, const std::type_info &t_to,
const std::string &t_what) CHAISCRIPT_NOEXCEPT
: bad_boxed_cast(t_from, t_to, t_what)
{
}
bad_boxed_dynamic_cast(const Type_Info &t_from, const std::type_info &t_to) CHAISCRIPT_NOEXCEPT
: bad_boxed_cast(t_from, t_to)
{
}
bad_boxed_dynamic_cast(const std::string &w) CHAISCRIPT_NOEXCEPT
: bad_boxed_cast(w)
{
}
virtual ~bad_boxed_dynamic_cast() CHAISCRIPT_NOEXCEPT {}
};
class bad_boxed_type_cast : public bad_boxed_cast
{
public:
bad_boxed_type_cast(const Type_Info &t_from, const std::type_info &t_to,
const std::string &t_what) CHAISCRIPT_NOEXCEPT
: bad_boxed_cast(t_from, t_to, t_what)
{
}
bad_boxed_type_cast(const Type_Info &t_from, const std::type_info &t_to) CHAISCRIPT_NOEXCEPT
: bad_boxed_cast(t_from, t_to)
{
}
bad_boxed_type_cast(const std::string &w) CHAISCRIPT_NOEXCEPT
: bad_boxed_cast(w)
{
}
virtual ~bad_boxed_type_cast() CHAISCRIPT_NOEXCEPT {}
};
}
namespace detail
{
class Type_Conversion_Base
{
public:
virtual Boxed_Value convert(const Boxed_Value &from) const = 0;
virtual Boxed_Value convert_down(const Boxed_Value &to) const = 0;
const Type_Info &to() const
{
return m_to;
}
const Type_Info &from() const
{
return m_from;
}
protected:
Type_Conversion_Base(const Type_Info &t_to, const Type_Info &t_from)
: m_to(t_to), m_from(t_from)
{
}
virtual ~Type_Conversion_Base() {}
private:
Type_Info m_to;
Type_Info m_from;
};
template<typename From, typename To>
class Dynamic_Caster
{
public:
static Boxed_Value cast(const Boxed_Value &t_from)
{
if (t_from.get_type_info().bare_equal(chaiscript::user_type<From>()))
{
if (t_from.is_pointer())
{
// Dynamic cast out the contained boxed value, which we know is the type we want
if (t_from.is_const())
{
std::shared_ptr<const To> data
= std::dynamic_pointer_cast<const To>(detail::Cast_Helper<std::shared_ptr<const From> >::cast(t_from, nullptr));
if (!data)
{
throw std::bad_cast();
}
return Boxed_Value(data);
} else {
std::shared_ptr<To> data
= std::dynamic_pointer_cast<To>(detail::Cast_Helper<std::shared_ptr<From> >::cast(t_from, nullptr));
if (!data)
{
throw std::bad_cast();
}
return Boxed_Value(data);
}
} else {
// Pull the reference out of the contained boxed value, which we know is the type we want
if (t_from.is_const())
{
const From &d = detail::Cast_Helper<const From &>::cast(t_from, nullptr);
const To &data = dynamic_cast<const To &>(d);
return Boxed_Value(std::cref(data));
} else {
From &d = detail::Cast_Helper<From &>::cast(t_from, nullptr);
To &data = dynamic_cast<To &>(d);
return Boxed_Value(std::ref(data));
}
}
} else {
throw chaiscript::exception::bad_boxed_dynamic_cast(t_from.get_type_info(), typeid(To), "Unknown dynamic_cast_conversion");
}
}
};
template<typename Base, typename Derived>
class Dynamic_Conversion_Impl : public Type_Conversion_Base
{
public:
Dynamic_Conversion_Impl()
: Type_Conversion_Base(chaiscript::user_type<Base>(), chaiscript::user_type<Derived>())
{
}
virtual Boxed_Value convert_down(const Boxed_Value &t_base) const CHAISCRIPT_OVERRIDE
{
return Dynamic_Caster<Base, Derived>::cast(t_base);
}
virtual Boxed_Value convert(const Boxed_Value &t_derived) const CHAISCRIPT_OVERRIDE
{
return Dynamic_Caster<Derived, Base>::cast(t_derived);
}
};
template<typename Callable>
class Type_Conversion_Impl : public Type_Conversion_Base
{
public:
Type_Conversion_Impl(Type_Info t_from, Type_Info t_to, Callable t_func)
: Type_Conversion_Base(std::move(t_to), std::move(t_from)),
m_func(std::move(t_func))
{
}
virtual Boxed_Value convert_down(const Boxed_Value &) const CHAISCRIPT_OVERRIDE
{
throw chaiscript::exception::bad_boxed_type_cast("No conversion exists");
}
virtual Boxed_Value convert(const Boxed_Value &t_from) const CHAISCRIPT_OVERRIDE
{
/// \todo better handling of errors from the conversion function
return m_func(t_from);
}
private:
Callable m_func;
};
}
class Type_Conversions
{
public:
struct Less_Than
{
bool operator()(const std::type_info *t_lhs, const std::type_info *t_rhs) const
{
return *t_lhs != *t_rhs && t_lhs->before(*t_rhs);
}
};
Type_Conversions()
: m_num_types(0),
m_thread_cache(this),
m_conversion_saves(this)
{
}
Type_Conversions(const Type_Conversions &t_other)
: m_conversions(t_other.get_conversions()), m_num_types(m_conversions.size()),
m_thread_cache(this),
m_conversion_saves(this)
{
}
const std::set<const std::type_info *, Less_Than> &thread_cache() const
{
auto &cache = *m_thread_cache;
if (cache.size() != m_num_types)
{
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
cache = m_convertableTypes;
}
return cache;
}
void add_conversion(const std::shared_ptr<detail::Type_Conversion_Base> &conversion)
{
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
/// \todo error if a conversion already exists
m_conversions.insert(conversion);
m_convertableTypes.insert({conversion->to().bare_type_info(), conversion->from().bare_type_info()});
m_num_types = m_convertableTypes.size();
}
template<typename T>
bool convertable_type() const
{
return thread_cache().count(user_type<T>().bare_type_info()) != 0;
}
template<typename To, typename From>
bool converts() const
{
return converts(user_type<To>(), user_type<From>());
}
bool converts(const Type_Info &to, const Type_Info &from) const
{
const auto &types = thread_cache();
if (types.count(to.bare_type_info()) != 0 && types.count(from.bare_type_info()) != 0)
{
return has_conversion(to, from) || has_conversion(from, to);
} else {
return false;
}
}
template<typename To>
Boxed_Value boxed_type_conversion(const Boxed_Value &from) const
{
try {
Boxed_Value ret = get_conversion(user_type<To>(), from.get_type_info())->convert(from);
if (m_conversion_saves->enabled) m_conversion_saves->saves.push_back(ret);
return ret;
} catch (const std::out_of_range &) {
throw exception::bad_boxed_dynamic_cast(from.get_type_info(), typeid(To), "No known conversion");
} catch (const std::bad_cast &) {
throw exception::bad_boxed_dynamic_cast(from.get_type_info(), typeid(To), "Unable to perform dynamic_cast operation");
}
}
template<typename From>
Boxed_Value boxed_type_down_conversion(const Boxed_Value &to) const
{
try {
Boxed_Value ret = get_conversion(to.get_type_info(), user_type<From>())->convert_down(to);
if (m_conversion_saves->enabled) m_conversion_saves->saves.push_back(ret);
return ret;
} catch (const std::out_of_range &) {
throw exception::bad_boxed_dynamic_cast(to.get_type_info(), typeid(From), "No known conversion");
} catch (const std::bad_cast &) {
throw exception::bad_boxed_dynamic_cast(to.get_type_info(), typeid(From), "Unable to perform dynamic_cast operation");
}
}
void enable_conversion_saves(bool t_val)
{
m_conversion_saves->enabled = t_val;
}
std::vector<Boxed_Value> take_saves()
{
std::vector<Boxed_Value> ret;
std::swap(ret, m_conversion_saves->saves);
return ret;
}
bool has_conversion(const Type_Info &to, const Type_Info &from) const
{
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
return find(to, from) != m_conversions.end();
}
std::shared_ptr<detail::Type_Conversion_Base> get_conversion(const Type_Info &to, const Type_Info &from) const
{
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
auto itr = find(to, from);
if (itr != m_conversions.end())
{
return *itr;
} else {
throw std::out_of_range("No such conversion exists from " + from.bare_name() + " to " + to.bare_name());
}
}
private:
std::set<std::shared_ptr<detail::Type_Conversion_Base> >::const_iterator find(
const Type_Info &to, const Type_Info &from) const
{
return std::find_if(m_conversions.begin(), m_conversions.end(),
[&to, &from](const std::shared_ptr<detail::Type_Conversion_Base> &conversion)
{
return conversion->to().bare_equal(to) && conversion->from().bare_equal(from);
}
);
}
std::set<std::shared_ptr<detail::Type_Conversion_Base>> get_conversions() const
{
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
return m_conversions;
}
struct Conversion_Saves
{
Conversion_Saves()
: enabled(false)
{}
bool enabled;
std::vector<Boxed_Value> saves;
};
mutable chaiscript::detail::threading::shared_mutex m_mutex;
std::set<std::shared_ptr<detail::Type_Conversion_Base>> m_conversions;
std::set<const std::type_info *, Less_Than> m_convertableTypes;
std::atomic_size_t m_num_types;
chaiscript::detail::threading::Thread_Storage<std::set<const std::type_info *, Less_Than>> m_thread_cache;
chaiscript::detail::threading::Thread_Storage<Conversion_Saves> m_conversion_saves;
};
typedef std::shared_ptr<chaiscript::detail::Type_Conversion_Base> Type_Conversion;
/// \brief Used to register a to / parent class relationship with ChaiScript. Necessary if you
/// want automatic conversions up your inheritance hierarchy.
///
/// Create a new to class registration for applying to a module or to the ChaiScript engine
/// Currently, due to limitations in module loading on Windows, and for the sake of portability,
/// if you have a type that is introduced in a loadable module and is used by multiple modules
/// (through a tertiary dll that is shared between the modules, static linking the new type
/// into both loadable modules would not be portable), you need to register the type
/// relationship in all modules that use the newly added type in a polymorphic way.
///
/// Example:
/// \code
/// class Base
/// {};
/// class Derived : public Base
/// {};
///
/// chaiscript::ChaiScript chai;
/// chai.add(chaiscript::to_class<Base, Derived>());
/// \endcode
///
template<typename Base, typename Derived>
Type_Conversion base_class()
{
//Can only be used with related polymorphic types
//may be expanded some day to support conversions other than child -> parent
static_assert(std::is_base_of<Base,Derived>::value, "Classes are not related by inheritance");
static_assert(std::is_polymorphic<Base>::value, "Base class must be polymorphic");
static_assert(std::is_polymorphic<Derived>::value, "Derived class must be polymorphic");
return std::make_shared<detail::Dynamic_Conversion_Impl<Base, Derived>>();
}
template<typename Callable>
Type_Conversion type_conversion(const Type_Info &t_from, const Type_Info &t_to,
const Callable &t_func)
{
return std::make_shared<detail::Type_Conversion_Impl<Callable>>(t_from, t_to, t_func);
}
template<typename From, typename To, typename Callable>
Type_Conversion type_conversion(const Callable &t_function)
{
auto func = [t_function](const Boxed_Value &t_bv) -> Boxed_Value {
// not even attempting to call boxed_cast so that we don't get caught in some call recursion
return chaiscript::Boxed_Value(t_function(detail::Cast_Helper<const From &>::cast(t_bv, nullptr)));
};
return std::make_shared<detail::Type_Conversion_Impl<decltype(func)>>(user_type<From>(), user_type<To>(), func);
}
template<typename From, typename To>
Type_Conversion type_conversion()
{
static_assert(std::is_convertible<From, To>::value, "Types are not automatically convertible");
auto func = [](const Boxed_Value &t_bv) -> Boxed_Value {
// not even attempting to call boxed_cast so that we don't get caught in some call recursion
auto &&from = detail::Cast_Helper<From>::cast(t_bv, nullptr);
To to(from);
return chaiscript::Boxed_Value(to);
};
return std::make_shared<detail::Type_Conversion_Impl<decltype(func)>>(user_type<From>(), user_type<To>(), func);
}
}
#endif

View File

@@ -7,10 +7,11 @@
#ifndef CHAISCRIPT_TYPE_INFO_HPP_ #ifndef CHAISCRIPT_TYPE_INFO_HPP_
#define CHAISCRIPT_TYPE_INFO_HPP_ #define CHAISCRIPT_TYPE_INFO_HPP_
#include <string> #include <functional>
#include <typeinfo>
#include <memory> #include <memory>
#include <string>
#include <type_traits> #include <type_traits>
#include <typeinfo>
namespace chaiscript namespace chaiscript
{ {
@@ -24,6 +25,7 @@ namespace chaiscript
}; };
} }
/// \brief Compile time deduced information about a type /// \brief Compile time deduced information about a type
class Type_Info class Type_Info
{ {
@@ -37,71 +39,57 @@ namespace chaiscript
{ {
} }
Type_Info() CHAISCRIPT_CONSTEXPR Type_Info()
: m_type_info(0), m_bare_type_info(0), : m_type_info(nullptr), m_bare_type_info(nullptr),
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_is_arithmetic(false), m_is_void(false), m_is_arithmetic(false),
m_is_undef(true) m_is_undef(true)
{ {
} }
Type_Info(const Type_Info &ti) #if !defined(_MSC_VER) || _MSC_VER != 1800
: m_type_info(ti.m_type_info), Type_Info(Type_Info&&) = default;
m_bare_type_info(ti.m_bare_type_info), Type_Info& operator=(Type_Info&&) = default;
m_is_const(ti.m_is_const), m_is_reference(ti.m_is_reference), #endif
m_is_pointer(ti.m_is_pointer),
m_is_void(ti.m_is_void), m_is_arithmetic(ti.m_is_arithmetic),
m_is_undef(ti.m_is_undef)
{
}
Type_Info &operator=(const Type_Info &ti) Type_Info(const Type_Info&) = default;
{ Type_Info& operator=(const Type_Info&) = default;
m_type_info = ti.m_type_info;
m_bare_type_info = ti.m_bare_type_info;
m_is_const = ti.m_is_const;
m_is_reference = ti.m_is_reference;
m_is_pointer = ti.m_is_pointer;
m_is_void = ti.m_is_void;
m_is_arithmetic = ti.m_is_arithmetic;
m_is_undef = ti.m_is_undef;
return *this;
}
bool operator<(const Type_Info &ti) const
CHAISCRIPT_CONSTEXPR bool operator<(const Type_Info &ti) const CHAISCRIPT_NOEXCEPT
{ {
return m_type_info < ti.m_type_info; return m_type_info < ti.m_type_info;
} }
bool operator==(const Type_Info &ti) const CHAISCRIPT_CONSTEXPR bool operator==(const Type_Info &ti) const CHAISCRIPT_NOEXCEPT
{ {
return ti.m_type_info == m_type_info return ti.m_type_info == m_type_info
|| (ti.m_type_info && m_type_info && *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 CHAISCRIPT_CONSTEXPR bool operator==(const std::type_info &ti) const CHAISCRIPT_NOEXCEPT
{ {
return m_type_info != 0 && (*m_type_info) == ti; return m_type_info != nullptr && (*m_type_info) == ti;
} }
bool bare_equal(const Type_Info &ti) const CHAISCRIPT_CONSTEXPR bool bare_equal(const Type_Info &ti) const CHAISCRIPT_NOEXCEPT
{ {
return ti.m_bare_type_info == m_bare_type_info 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); || (ti.m_bare_type_info && m_bare_type_info && *ti.m_bare_type_info == *m_bare_type_info);
} }
bool bare_equal_type_info(const std::type_info &ti) const CHAISCRIPT_CONSTEXPR bool bare_equal_type_info(const std::type_info &ti) const CHAISCRIPT_NOEXCEPT
{ {
return m_bare_type_info != 0 return m_bare_type_info != nullptr
&& (*m_bare_type_info) == ti; && (*m_bare_type_info) == ti;
} }
bool is_const() const { return m_is_const; } CHAISCRIPT_CONSTEXPR bool is_const() const CHAISCRIPT_NOEXCEPT { return m_is_const; }
bool is_reference() const { return m_is_reference; } CHAISCRIPT_CONSTEXPR bool is_reference() const CHAISCRIPT_NOEXCEPT { return m_is_reference; }
bool is_void() const { return m_is_void; } CHAISCRIPT_CONSTEXPR bool is_void() const CHAISCRIPT_NOEXCEPT { return m_is_void; }
bool is_arithmetic() const { return m_is_arithmetic; } CHAISCRIPT_CONSTEXPR bool is_arithmetic() const CHAISCRIPT_NOEXCEPT { return m_is_arithmetic; }
bool is_undef() const { return m_is_undef || m_bare_type_info == 0; } CHAISCRIPT_CONSTEXPR bool is_undef() const CHAISCRIPT_NOEXCEPT { return m_is_undef || m_bare_type_info == nullptr; }
bool is_pointer() const { return m_is_pointer; } CHAISCRIPT_CONSTEXPR bool is_pointer() const CHAISCRIPT_NOEXCEPT { return m_is_pointer; }
std::string name() const std::string name() const
{ {
@@ -113,7 +101,7 @@ namespace chaiscript
} }
} }
std::string bare_name() const std::string bare_name() const
{ {
if (m_bare_type_info) if (m_bare_type_info)
{ {
@@ -123,6 +111,11 @@ namespace chaiscript
} }
} }
CHAISCRIPT_CONSTEXPR const std::type_info *bare_type_info() const
{
return m_bare_type_info;
}
private: private:
const std::type_info *m_type_info; const std::type_info *m_type_info;
const std::type_info *m_bare_type_info; const std::type_info *m_bare_type_info;
@@ -214,11 +207,6 @@ namespace chaiscript
} }
}; };
template<typename T>
struct Stripped_Type
{
typedef typename Bare_Type<typename detail::Get_Type_Info<T>::type>::type type;
};
} }
/// \brief Creates a Type_Info object representing the type passed in /// \brief Creates a Type_Info object representing the type passed in

View File

@@ -5,7 +5,9 @@
// http://www.chaiscript.com // http://www.chaiscript.com
#ifndef CHAISCRIPT_ALGEBRAIC_HPP_ #ifndef CHAISCRIPT_ALGEBRAIC_HPP_
#define CHAISCRIPT_ALGEBRAIC_HPP_ #define CHAISCRIPT_ALGEBRAIC_HPP_
#include <string>
#include "../dispatchkit/dispatchkit.hpp" #include "../dispatchkit/dispatchkit.hpp"
@@ -126,5 +128,5 @@ namespace chaiscript
}; };
} }
#endif /* _CHAISCRIPT_ALGEBRAIC_HPP */ #endif /* _CHAISCRIPT_ALGEBRAIC_HPP */

View File

@@ -5,10 +5,24 @@
// http://www.chaiscript.com // http://www.chaiscript.com
#ifndef CHAISCRIPT_COMMON_HPP_ #ifndef CHAISCRIPT_COMMON_HPP_
#define CHAISCRIPT_COMMON_HPP_ #define CHAISCRIPT_COMMON_HPP_
#include <algorithm>
#include <memory>
#include <sstream> #include <sstream>
#include <stdexcept>
#include <string>
#include <vector>
#include "../chaiscript_defines.hpp"
#include "../dispatchkit/boxed_value.hpp"
#include "../dispatchkit/dispatchkit.hpp" #include "../dispatchkit/dispatchkit.hpp"
#include "../dispatchkit/proxy_functions.hpp"
#include "../dispatchkit/type_info.hpp"
namespace chaiscript {
struct AST_Node;
} // namespace chaiscript
namespace chaiscript namespace chaiscript
{ {
@@ -23,7 +37,7 @@ namespace chaiscript
Comparison, Addition, Subtraction, Multiplication, Division, Modulus, Array_Call, Dot_Access, Quoted_String, Single_Quoted_String, Comparison, Addition, Subtraction, Multiplication, Division, Modulus, Array_Call, Dot_Access, Quoted_String, Single_Quoted_String,
Lambda, Block, Def, While, If, For, Inline_Array, Inline_Map, Return, File, Prefix, Break, Continue, Map_Pair, Value_Range, Lambda, Block, Def, While, If, For, Inline_Array, Inline_Map, Return, File, Prefix, Break, Continue, Map_Pair, Value_Range,
Inline_Range, Annotation, Try, Catch, Finally, Method, Attr_Decl, Shift, Equality, Bitwise_And, Bitwise_Xor, Bitwise_Or, Inline_Range, Annotation, Try, Catch, Finally, Method, Attr_Decl, Shift, Equality, Bitwise_And, Bitwise_Xor, Bitwise_Or,
Logical_And, Logical_Or, Reference, Switch, Case, Default, Ternary_Cond, Noop Logical_And, Logical_Or, Reference, Switch, Case, Default, Ternary_Cond, Noop, Class, Binary
}; };
}; };
@@ -36,7 +50,7 @@ namespace chaiscript
"Comparison", "Addition", "Subtraction", "Multiplication", "Division", "Modulus", "Array_Call", "Dot_Access", "Quoted_String", "Single_Quoted_String", "Comparison", "Addition", "Subtraction", "Multiplication", "Division", "Modulus", "Array_Call", "Dot_Access", "Quoted_String", "Single_Quoted_String",
"Lambda", "Block", "Def", "While", "If", "For", "Inline_Array", "Inline_Map", "Return", "File", "Prefix", "Break", "Continue", "Map_Pair", "Value_Range", "Lambda", "Block", "Def", "While", "If", "For", "Inline_Array", "Inline_Map", "Return", "File", "Prefix", "Break", "Continue", "Map_Pair", "Value_Range",
"Inline_Range", "Annotation", "Try", "Catch", "Finally", "Method", "Attr_Decl", "Shift", "Equality", "Bitwise_And", "Bitwise_Xor", "Bitwise_Or", "Inline_Range", "Annotation", "Try", "Catch", "Finally", "Method", "Attr_Decl", "Shift", "Equality", "Bitwise_And", "Bitwise_Xor", "Bitwise_Or",
"Logical_And", "Logical_Or", "Reference", "Switch", "Case", "Default", "Ternary Condition", "Noop"}; "Logical_And", "Logical_Or", "Reference", "Switch", "Case", "Default", "Ternary Condition", "Noop", "Class", "Binary"};
return ast_node_types[ast_node_type]; return ast_node_types[ast_node_type];
} }
@@ -54,7 +68,8 @@ namespace chaiscript
}; };
/// \brief Typedef for pointers to AST_Node objects. Used in building of the AST_Node tree /// \brief Typedef for pointers to AST_Node objects. Used in building of the AST_Node tree
typedef std::shared_ptr<struct AST_Node> AST_NodePtr; typedef std::shared_ptr<AST_Node> AST_NodePtr;
typedef std::shared_ptr<const AST_Node> AST_NodePtr_Const;
/// \brief Classes which may be thrown during error cases when ChaiScript is executing. /// \brief Classes which may be thrown during error cases when ChaiScript is executing.
@@ -68,7 +83,7 @@ namespace chaiscript
File_Position end_position; File_Position end_position;
std::string filename; std::string filename;
std::string detail; std::string detail;
std::vector<AST_NodePtr> call_stack; std::vector<AST_NodePtr_Const> call_stack;
eval_error(const std::string &t_why, const File_Position &t_where, const std::string &t_fname, eval_error(const std::string &t_why, const File_Position &t_where, const std::string &t_fname,
const std::vector<Boxed_Value> &t_parameters, const std::vector<chaiscript::Const_Proxy_Function> &t_functions, const std::vector<Boxed_Value> &t_parameters, const std::vector<chaiscript::Const_Proxy_Function> &t_functions,
@@ -103,19 +118,19 @@ namespace chaiscript
ss << what(); ss << what();
if (call_stack.size() > 0) { if (call_stack.size() > 0) {
ss << "during evaluation at (" << fname(call_stack[0]) << " " << startpos(call_stack[0]) << ")" << std::endl; ss << "during evaluation at (" << fname(call_stack[0]) << " " << startpos(call_stack[0]) << ")\n";
ss << std::endl << detail << std::endl; ss << '\n' << detail << '\n';
ss << " " << fname(call_stack[0]) << " (" << startpos(call_stack[0]) << ") '" << pretty(call_stack[0]) << "'"; ss << " " << fname(call_stack[0]) << " (" << startpos(call_stack[0]) << ") '" << pretty(call_stack[0]) << "'";
for (size_t j = 1; j < call_stack.size(); ++j) { for (size_t j = 1; j < call_stack.size(); ++j) {
if (id(call_stack[j]) != chaiscript::AST_Node_Type::Block if (id(call_stack[j]) != chaiscript::AST_Node_Type::Block
&& id(call_stack[j]) != chaiscript::AST_Node_Type::File) && id(call_stack[j]) != chaiscript::AST_Node_Type::File)
{ {
ss << std::endl; ss << '\n';
ss << " from " << fname(call_stack[j]) << " (" << startpos(call_stack[j]) << ") '" << pretty(call_stack[j]) << "'"; ss << " from " << fname(call_stack[j]) << " (" << startpos(call_stack[j]) << ") '" << pretty(call_stack[j]) << "'";
} }
} }
} }
ss << std::endl; ss << '\n';
return ss.str(); return ss.str();
} }
@@ -249,15 +264,13 @@ namespace chaiscript
std::stringstream ss; std::stringstream ss;
if (t_functions.size() == 1) if (t_functions.size() == 1)
{ {
ss << " Expected: " << format_types(t_functions[0], t_dot_notation, t_ss) << std::endl; ss << " Expected: " << format_types(t_functions[0], t_dot_notation, t_ss) << '\n';
} else { } else {
ss << " " << t_functions.size() << " overloads available:" << std::endl; ss << " " << t_functions.size() << " overloads available:\n";
for (std::vector<chaiscript::Const_Proxy_Function>::const_iterator itr = t_functions.begin(); for (const auto & t_function : t_functions)
itr != t_functions.end();
++itr)
{ {
ss << " " << format_types((*itr), t_dot_notation, t_ss) << std::endl; ss << " " << format_types((t_function), t_dot_notation, t_ss) << '\n';
} }
} }
@@ -277,7 +290,7 @@ namespace chaiscript
{ {
std::string paramstr; std::string paramstr;
for (std::vector<Boxed_Value>::const_iterator itr = t_parameters.begin(); for (auto itr = t_parameters.begin();
itr != t_parameters.end(); itr != t_parameters.end();
++itr) ++itr)
{ {
@@ -404,8 +417,8 @@ namespace chaiscript
oss << text; oss << text;
for (unsigned int j = 0; j < this->children.size(); ++j) { for (auto & elem : this->children) {
oss << this->children[j]->pretty_print(); oss << elem->pretty_print();
} }
return oss.str(); return oss.str();
@@ -413,29 +426,25 @@ namespace chaiscript
/// Prints the contents of an AST node, including its children, recursively /// Prints the contents of an AST node, including its children, recursively
std::string to_string(std::string t_prepend = "") { std::string to_string(const std::string &t_prepend = "") const {
std::ostringstream oss; std::ostringstream oss;
oss << t_prepend << "(" << ast_node_type_to_string(this->identifier) << ") " oss << t_prepend << "(" << ast_node_type_to_string(this->identifier) << ") "
<< this->text << " : " << this->start.line << ", " << this->start.column << std::endl; << this->text << " : " << this->start.line << ", " << this->start.column << '\n';
for (unsigned int j = 0; j < this->children.size(); ++j) { for (size_t j = 0; j < this->children.size(); ++j) {
oss << this->children[j]->to_string(t_prepend + " "); oss << this->children[j]->to_string(t_prepend + " ");
} }
return oss.str(); return oss.str();
} }
std::string internal_to_string() { Boxed_Value eval(chaiscript::detail::Dispatch_Engine &t_e) const
return to_string();
}
Boxed_Value eval(chaiscript::detail::Dispatch_Engine &t_e)
{ {
try { try {
return eval_internal(t_e); return eval_internal(t_e);
} catch (exception::eval_error &ee) { } catch (exception::eval_error &ee) {
ee.call_stack.push_back(shared_from_this()); ee.call_stack.push_back(shared_from_this());
throw ee; throw;
} }
} }
@@ -446,19 +455,19 @@ namespace chaiscript
} }
protected: protected:
AST_Node(const std::string &t_ast_node_text, int t_id, const std::shared_ptr<std::string> &t_fname, AST_Node(std::string t_ast_node_text, int t_id, const std::shared_ptr<std::string> &t_fname,
int t_start_line, int t_start_col, int t_end_line, int t_end_col) : int t_start_line, int t_start_col, int t_end_line, int t_end_col) :
text(t_ast_node_text), identifier(t_id), filename(t_fname), text(std::move(t_ast_node_text)), identifier(t_id), filename(t_fname),
start(t_start_line, t_start_col), end(t_end_line, t_end_col) start(t_start_line, t_start_col), end(t_end_line, t_end_col)
{ {
} }
AST_Node(const std::string &t_ast_node_text, int t_id, const std::shared_ptr<std::string> &t_fname) : AST_Node(std::string t_ast_node_text, int t_id, const std::shared_ptr<std::string> &t_fname) :
text(t_ast_node_text), identifier(t_id), filename(t_fname) {} text(std::move(t_ast_node_text)), identifier(t_id), filename(t_fname) {}
virtual ~AST_Node() {} virtual ~AST_Node() {}
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &) virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &) const
{ {
throw std::runtime_error("Undispatched ast_node (internal error)"); throw std::runtime_error("Undispatched ast_node (internal error)");
} }
@@ -498,6 +507,9 @@ namespace chaiscript
/// Creates a new scope then pops it on destruction /// Creates a new scope then pops it on destruction
struct Scope_Push_Pop struct Scope_Push_Pop
{ {
Scope_Push_Pop(const Scope_Push_Pop &) = delete;
Scope_Push_Pop& operator=(const Scope_Push_Pop &) = delete;
Scope_Push_Pop(chaiscript::detail::Dispatch_Engine &t_de) Scope_Push_Pop(chaiscript::detail::Dispatch_Engine &t_de)
: m_de(t_de) : m_de(t_de)
{ {
@@ -511,16 +523,16 @@ namespace chaiscript
private: private:
// explicitly unimplemented copy and assignment
Scope_Push_Pop(const Scope_Push_Pop &);
Scope_Push_Pop& operator=(const Scope_Push_Pop &);
chaiscript::detail::Dispatch_Engine &m_de; chaiscript::detail::Dispatch_Engine &m_de;
}; };
/// Creates a new functon call and pops it on destruction /// Creates a new function call and pops it on destruction
struct Function_Push_Pop struct Function_Push_Pop
{ {
Function_Push_Pop(const Function_Push_Pop &) = delete;
Function_Push_Pop& operator=(const Function_Push_Pop &) = delete;
Function_Push_Pop(chaiscript::detail::Dispatch_Engine &t_de) Function_Push_Pop(chaiscript::detail::Dispatch_Engine &t_de)
: m_de(t_de) : m_de(t_de)
{ {
@@ -537,11 +549,13 @@ namespace chaiscript
m_de.save_function_params(t_params); m_de.save_function_params(t_params);
} }
void save_params(std::initializer_list<Boxed_Value> t_params)
{
m_de.save_function_params(std::move(t_params));
}
private: private:
// explicitly unimplemented copy and assignment
Function_Push_Pop(const Function_Push_Pop &);
Function_Push_Pop& operator=(const Function_Push_Pop &);
chaiscript::detail::Dispatch_Engine &m_de; chaiscript::detail::Dispatch_Engine &m_de;
}; };
@@ -549,6 +563,9 @@ namespace chaiscript
/// Creates a new scope then pops it on destruction /// Creates a new scope then pops it on destruction
struct Stack_Push_Pop struct Stack_Push_Pop
{ {
Stack_Push_Pop(const Stack_Push_Pop &) = delete;
Stack_Push_Pop& operator=(const Stack_Push_Pop &) = delete;
Stack_Push_Pop(chaiscript::detail::Dispatch_Engine &t_de) Stack_Push_Pop(chaiscript::detail::Dispatch_Engine &t_de)
: m_de(t_de) : m_de(t_de)
{ {
@@ -562,9 +579,6 @@ namespace chaiscript
private: private:
// explicitly unimplemented copy and assignment
Stack_Push_Pop(const Stack_Push_Pop &);
Stack_Push_Pop& operator=(const Stack_Push_Pop &);
chaiscript::detail::Dispatch_Engine &m_de; chaiscript::detail::Dispatch_Engine &m_de;
}; };
@@ -572,5 +586,5 @@ namespace chaiscript
} }
} }
#endif /* _CHAISCRIPT_COMMON_HPP */ #endif /* _CHAISCRIPT_COMMON_HPP */

View File

@@ -7,17 +7,34 @@
#ifndef CHAISCRIPT_ENGINE_HPP_ #ifndef CHAISCRIPT_ENGINE_HPP_
#define CHAISCRIPT_ENGINE_HPP_ #define CHAISCRIPT_ENGINE_HPP_
#include <cassert>
#include <cstring>
#include <algorithm>
#include <exception> #include <exception>
#include <fstream> #include <fstream>
#include <functional>
#include <map>
#include <memory>
#include <mutex>
#include <set>
#include <stdexcept>
#include <string>
#include <vector>
#include "../chaiscript_defines.hpp" #include "../chaiscript_defines.hpp"
#include "../chaiscript_threading.hpp"
#include "../dispatchkit/boxed_cast_helper.hpp"
#include "../dispatchkit/boxed_value.hpp"
#include "../dispatchkit/dispatchkit.hpp"
#include "../dispatchkit/type_conversions.hpp"
#include "../dispatchkit/proxy_functions.hpp"
#include "chaiscript_common.hpp" #include "chaiscript_common.hpp"
#if defined(__linux__) || defined(__unix__) || defined(__APPLE__) #if defined(__linux__) || defined(__unix__) || defined(__APPLE__) || defined(__HAIKU__)
#include <unistd.h> #include <unistd.h>
#endif #endif
#ifdef _POSIX_VERSION #if defined(_POSIX_VERSION) && !defined(__CYGWIN__)
#include <dlfcn.h> #include <dlfcn.h>
#else #else
#ifdef CHAISCRIPT_WINDOWS #ifdef CHAISCRIPT_WINDOWS
@@ -28,9 +45,9 @@
#endif #endif
#include "chaiscript_prelude.chai"
#include "chaiscript_parser.hpp"
#include "../dispatchkit/exception_specification.hpp" #include "../dispatchkit/exception_specification.hpp"
#include "chaiscript_parser.hpp"
#include "chaiscript_prelude.chai"
namespace chaiscript namespace chaiscript
{ {
@@ -52,7 +69,7 @@ namespace chaiscript
namespace detail namespace detail
{ {
#ifdef _POSIX_VERSION #if defined(_POSIX_VERSION) && !defined(__CYGWIN__)
struct Loadable_Module struct Loadable_Module
{ {
struct DLModule struct DLModule
@@ -123,32 +140,32 @@ namespace chaiscript
struct Loadable_Module struct Loadable_Module
{ {
template<typename T> template<typename T>
static std::wstring towstring(const T &t_str) static std::wstring to_wstring(const T &t_str)
{ {
return std::wstring(t_str.begin(), t_str.end()); return std::wstring(t_str.begin(), t_str.end());
} }
template<typename T> template<typename T>
static std::string tostring(const T &t_str) static std::string to_string(const T &t_str)
{ {
return std::string(t_str.begin(), t_str.end()); return std::string(t_str.begin(), t_str.end());
} }
#ifdef _UNICODE #ifdef _UNICODE
template<typename T> template<typename T>
static std::wstring toproperstring(const T &t_str) static std::wstring to_proper_string(const T &t_str)
{ {
return towstring(t_str); return to_wstring(t_str);
} }
#else #else
template<typename T> template<typename T>
static std::string toproperstring(const T &t_str) static std::string to_proper_string(const T &t_str)
{ {
return tostring(t_str); return to_string(t_str);
} }
#endif #endif
static std::string GetErrorMessage(DWORD t_err) static std::string get_error_message(DWORD t_err)
{ {
#ifdef _UNICODE #ifdef _UNICODE
typedef LPWSTR StringType; typedef LPWSTR StringType;
@@ -173,17 +190,17 @@ namespace chaiscript
LocalFree(lpMsgBuf); LocalFree(lpMsgBuf);
} }
return tostring(retval); return to_string(retval);
} }
struct DLModule struct DLModule
{ {
DLModule(const std::string &t_filename) DLModule(const std::string &t_filename)
: m_data(LoadLibrary(toproperstring(t_filename).c_str())) : m_data(LoadLibrary(to_proper_string(t_filename).c_str()))
{ {
if (!m_data) if (!m_data)
{ {
throw chaiscript::exception::load_module_error(GetErrorMessage(GetLastError())); throw chaiscript::exception::load_module_error(get_error_message(GetLastError()));
} }
} }
@@ -203,7 +220,7 @@ namespace chaiscript
{ {
if (!m_symbol) if (!m_symbol)
{ {
throw chaiscript::exception::load_module_error(GetErrorMessage(GetLastError())); throw chaiscript::exception::load_module_error(get_error_message(GetLastError()));
} }
} }
@@ -253,8 +270,6 @@ namespace chaiscript
chaiscript::detail::Dispatch_Engine m_engine; chaiscript::detail::Dispatch_Engine m_engine;
/// Evaluates the given string in by parsing it and running the results through the evaluator /// Evaluates the given string in by parsing it and running the results through the evaluator
Boxed_Value do_eval(const std::string &t_input, const std::string &t_filename = "__EVAL__", bool /* t_internal*/ = false) Boxed_Value do_eval(const std::string &t_input, const std::string &t_filename = "__EVAL__", bool /* t_internal*/ = false)
{ {
@@ -267,7 +282,7 @@ namespace chaiscript
return Boxed_Value(); return Boxed_Value();
} }
} }
catch (const chaiscript::eval::detail::Return_Value &rv) { catch (chaiscript::eval::detail::Return_Value &rv) {
return rv.retval; return rv.retval;
} }
} }
@@ -315,6 +330,7 @@ namespace chaiscript
m_engine.add_reserved_word("break"); m_engine.add_reserved_word("break");
m_engine.add_reserved_word("true"); m_engine.add_reserved_word("true");
m_engine.add_reserved_word("false"); m_engine.add_reserved_word("false");
m_engine.add_reserved_word("class");
m_engine.add_reserved_word("_"); m_engine.add_reserved_word("_");
if (t_lib) if (t_lib)
@@ -329,13 +345,21 @@ namespace chaiscript
m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::function_exists, std::ref(m_engine)), "function_exists"); m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::function_exists, std::ref(m_engine)), "function_exists");
m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::get_function_objects, std::ref(m_engine)), "get_functions"); m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::get_function_objects, std::ref(m_engine)), "get_functions");
m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::get_scripting_objects, std::ref(m_engine)), "get_objects"); m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::get_scripting_objects, std::ref(m_engine)), "get_objects");
m_engine.add(Proxy_Function(new dispatch::Dynamic_Proxy_Function(
m_engine.add(Proxy_Function(new dispatch::Dynamic_Proxy_Function(std::bind(&chaiscript::detail::Dispatch_Engine::call_exists, std::ref(m_engine), std::placeholders::_1))), [this](const std::vector<Boxed_Value> &t_params) {
"call_exists"); return m_engine.call_exists(t_params);
})), "call_exists");
m_engine.add(fun<Boxed_Value (const dispatch::Proxy_Function_Base *, const std::vector<Boxed_Value> &)>(std::bind(&chaiscript::dispatch::Proxy_Function_Base::operator(), std::placeholders::_1, std::placeholders::_2, std::ref(m_engine.conversions()))), "call"); m_engine.add(fun<Boxed_Value (const dispatch::Proxy_Function_Base *, const std::vector<Boxed_Value> &)>(std::bind(&chaiscript::dispatch::Proxy_Function_Base::operator(), std::placeholders::_1, std::placeholders::_2, std::ref(m_engine.conversions()))), "call");
m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::get_type_name, std::ref(m_engine)), "name"); m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::get_type_name, std::ref(m_engine)), "name");
m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::get_type, std::ref(m_engine)), "type");
m_engine.add(fun<void (const Type_Info &, const Type_Info &, const std::function<Boxed_Value (const Boxed_Value &)> &)> (
[=](const Type_Info &t_from, const Type_Info &t_to, const std::function<Boxed_Value (const Boxed_Value &)> &t_func) {
m_engine.add(chaiscript::type_conversion(t_from, t_to, t_func));
}
), "add_type_conversion");
typedef std::string (ChaiScript::*load_mod_1)(const std::string&); typedef std::string (ChaiScript::*load_mod_1)(const std::string&);
typedef void (ChaiScript::*load_mod_2)(const std::string&, const std::string&); typedef void (ChaiScript::*load_mod_2)(const std::string&, const std::string&);
@@ -347,19 +371,27 @@ namespace chaiscript
m_engine.add(fun(&ChaiScript::internal_eval, this), "eval"); m_engine.add(fun(&ChaiScript::internal_eval, this), "eval");
m_engine.add(fun(&ChaiScript::internal_eval_ast, this), "eval"); m_engine.add(fun(&ChaiScript::internal_eval_ast, this), "eval");
m_engine.add(fun(&ChaiScript::version_major, this), "version_major");
m_engine.add(fun(&ChaiScript::version_minor, this), "version_minor");
m_engine.add(fun(&ChaiScript::version_patch, this), "version_patch");
m_engine.add(fun(&ChaiScript::version, this), "version");
m_engine.add(fun(&ChaiScript::add_global_const, this), "add_global_const");
m_engine.add(fun(&ChaiScript::add_global, this), "add_global");
do_eval(ChaiScript_Prelude::chaiscript_prelude(), "standard prelude"); do_eval(ChaiScript_Prelude::chaiscript_prelude(), "standard prelude");
} }
/// Helper function for loading a file /// Helper function for loading a file
std::string load_file(const std::string &t_filename) { static std::string load_file(const std::string &t_filename) {
std::ifstream infile(t_filename.c_str(), std::ios::in | std::ios::ate | std::ios::binary ); std::ifstream infile(t_filename.c_str(), std::ios::in | std::ios::ate | std::ios::binary );
if (!infile.is_open()) { if (!infile.is_open()) {
throw chaiscript::exception::file_not_found_error(t_filename); throw chaiscript::exception::file_not_found_error(t_filename);
} }
std::streampos size = infile.tellg(); const auto size = infile.tellg();
infile.seekg(0, std::ios::beg); infile.seekg(0, std::ios::beg);
assert(size >= 0); assert(size >= 0);
@@ -368,7 +400,7 @@ namespace chaiscript
{ {
return std::string(); return std::string();
} else { } else {
std::vector<char> v(static_cast<unsigned int>(size)); std::vector<char> v(static_cast<size_t>(size));
infile.read(&v[0], size); infile.read(&v[0], size);
return std::string(v.begin(), v.end()); return std::string(v.begin(), v.end());
} }
@@ -380,9 +412,9 @@ namespace chaiscript
/// \param[in] t_modulepaths Vector of paths to search when attempting to load a binary module /// \param[in] t_modulepaths Vector of paths to search when attempting to load a binary module
/// \param[in] t_usepaths Vector of paths to search when attempting to "use" an included ChaiScript file /// \param[in] t_usepaths Vector of paths to search when attempting to "use" an included ChaiScript file
ChaiScript(const ModulePtr &t_lib, ChaiScript(const ModulePtr &t_lib,
const std::vector<std::string> &t_modulepaths = std::vector<std::string>(), std::vector<std::string> t_modulepaths = std::vector<std::string>(),
const std::vector<std::string> &t_usepaths = std::vector<std::string>()) std::vector<std::string> t_usepaths = std::vector<std::string>())
: m_modulepaths(t_modulepaths), m_usepaths(t_usepaths) : m_modulepaths(std::move(t_modulepaths)), m_usepaths(std::move(t_usepaths))
{ {
if (m_modulepaths.empty()) if (m_modulepaths.empty())
{ {
@@ -404,9 +436,9 @@ namespace chaiscript
/// ///
/// \param[in] t_modulepaths Vector of paths to search when attempting to load a binary module /// \param[in] t_modulepaths Vector of paths to search when attempting to load a binary module
/// \param[in] t_usepaths Vector of paths to search when attempting to "use" an included ChaiScript file /// \param[in] t_usepaths Vector of paths to search when attempting to "use" an included ChaiScript file
ChaiScript( const std::vector<std::string> &t_modulepaths = std::vector<std::string>(), ChaiScript( std::vector<std::string> t_modulepaths = std::vector<std::string>(),
const std::vector<std::string> &t_usepaths = std::vector<std::string>()) std::vector<std::string> t_usepaths = std::vector<std::string>())
: m_modulepaths(t_modulepaths), m_usepaths(t_usepaths) : m_modulepaths(std::move(t_modulepaths)), m_usepaths(std::move(t_usepaths))
{ {
if (m_modulepaths.empty()) if (m_modulepaths.empty())
{ {
@@ -418,8 +450,7 @@ namespace chaiscript
m_usepaths.push_back(""); m_usepaths.push_back("");
} }
#if defined(_POSIX_VERSION) && !defined(__CYGWIN__)
#ifdef _POSIX_VERSION
// If on Unix, add the path of the current executable to the module search path // If on Unix, add the path of the current executable to the module search path
// as windows would do // as windows would do
@@ -435,7 +466,7 @@ namespace chaiscript
u.in_ptr = &ChaiScript::use; u.in_ptr = &ChaiScript::use;
if ( dladdr((void*)(u.out_ptr), &rInfo) && rInfo.dli_fname ) { if ( dladdr((void*)(u.out_ptr), &rInfo) && rInfo.dli_fname ) {
std::string dllpath(rInfo.dli_fname); std::string dllpath(rInfo.dli_fname);
size_t lastslash = dllpath.rfind('/'); const size_t lastslash = dllpath.rfind('/');
if (lastslash != std::string::npos) if (lastslash != std::string::npos)
{ {
dllpath.erase(lastslash); dllpath.erase(lastslash);
@@ -443,23 +474,55 @@ namespace chaiscript
// Let's see if this is a link that we should expand // Let's see if this is a link that we should expand
std::vector<char> buf(2048); std::vector<char> buf(2048);
size_t pathlen = readlink(dllpath.c_str(), &buf.front(), buf.size()); const size_t pathlen = readlink(dllpath.c_str(), &buf.front(), buf.size());
if (pathlen > 0 && pathlen < buf.size()) if (pathlen > 0 && pathlen < buf.size())
{ {
dllpath = std::string(&buf.front(), pathlen); dllpath = std::string(&buf.front(), pathlen);
} }
m_modulepaths.insert(m_modulepaths.begin(), dllpath+"/"); m_modulepaths.insert(m_modulepaths.begin(), dllpath+"/");
} }
#endif #endif
// attempt to load the stdlib // attempt to load the stdlib
load_module("chaiscript_stdlib"); load_module("chaiscript_stdlib-" + version());
build_eval_system(ModulePtr()); build_eval_system(ModulePtr());
} }
int version_major() const
{
return chaiscript::version_major;
}
int version_minor() const
{
return chaiscript::version_minor;
}
int version_patch() const
{
return chaiscript::version_patch;
}
std::string version() const
{
std::stringstream ss;
ss << version_major() << "." << version_minor() << "." << version_patch();
return ss.str();
}
std::string get_type_name(const Type_Info &ti) const
{
return m_engine.get_type_name(ti);
}
template<typename T>
std::string get_type_name() const
{
return get_type_name(user_type<T>());
}
/// \brief Loads and parses a file. If the file is already, it is not reloaded /// \brief Loads and parses a file. If the file is already, it is not reloaded
@@ -469,10 +532,10 @@ namespace chaiscript
/// \param[in] t_filename Filename to load and evaluate /// \param[in] t_filename Filename to load and evaluate
void use(const std::string &t_filename) void use(const std::string &t_filename)
{ {
for (size_t i = 0; i < m_usepaths.size(); ++i) for (const auto &path : m_usepaths)
{ {
try { try {
const std::string appendedpath = m_usepaths[i] + t_filename; const auto appendedpath = path + t_filename;
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::recursive_mutex> l(m_use_mutex); chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::recursive_mutex> l(m_use_mutex);
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l2(m_mutex); chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l2(m_mutex);
@@ -487,14 +550,12 @@ namespace chaiscript
return; // return, we loaded it, or it was already loaded return; // return, we loaded it, or it was already loaded
} catch (const exception::file_not_found_error &) { } catch (const exception::file_not_found_error &) {
if (i == m_usepaths.size() - 1)
{
throw exception::file_not_found_error(t_filename);
}
// failed to load, try the next path // failed to load, try the next path
} }
} }
// failed to load by any name
throw exception::file_not_found_error(t_filename);
} }
/// \brief Adds a constant object that is available in all contexts and to all threads /// \brief Adds a constant object that is available in all contexts and to all threads
@@ -608,7 +669,7 @@ namespace chaiscript
/// chai.add(chaiscript::var(&obj), "obj"); // Add a pointer to a locally defined object /// chai.add(chaiscript::var(&obj), "obj"); // Add a pointer to a locally defined object
/// \endcode /// \endcode
/// ///
/// \sa \ref addingitems /// \sa \ref adding_items
template<typename T> template<typename T>
ChaiScript &add(const T &t_t, const std::string &t_name) ChaiScript &add(const T &t_t, const std::string &t_name)
{ {
@@ -625,7 +686,7 @@ namespace chaiscript
/// chaiscript::ChaiScript chai; /// chaiscript::ChaiScript chai;
/// chai.add(chaiscript::base_class<std::runtime_error, chaiscript::dispatch_error>()); /// chai.add(chaiscript::base_class<std::runtime_error, chaiscript::dispatch_error>());
/// \endcode /// \endcode
ChaiScript &add(const Dynamic_Cast_Conversion &d) ChaiScript &add(const Type_Conversion &d)
{ {
m_engine.add(d); m_engine.add(d);
return *this; return *this;
@@ -655,29 +716,30 @@ namespace chaiscript
std::string load_module(const std::string &t_module_name) std::string load_module(const std::string &t_module_name)
{ {
std::vector<exception::load_module_error> errors; std::vector<exception::load_module_error> errors;
std::string version_stripped_name = t_module_name;
std::vector<std::string> prefixes; size_t version_pos = version_stripped_name.find("-"+version());
prefixes.push_back("lib"); if (version_pos != std::string::npos)
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 < m_modulepaths.size(); ++i)
{ {
for (size_t j = 0; j < prefixes.size(); ++j) version_stripped_name.erase(version_pos);
}
std::vector<std::string> prefixes{"lib", "cyg", ""};
std::vector<std::string> postfixes{".dll", ".so", ""};
for (auto & elem : m_modulepaths)
{
for (auto & prefix : prefixes)
{ {
for (size_t k = 0; k < postfixes.size(); ++k) for (auto & postfix : postfixes)
{ {
try { try {
std::string name = m_modulepaths[i] + prefixes[j] + t_module_name + postfixes[k]; const auto name = elem + prefix + t_module_name + postfix;
// std::cerr << "trying location: " << name << std::endl; // std::cerr << "trying location: " << name << '\n';
load_module(t_module_name, name); load_module(version_stripped_name, name);
return name; return name;
} catch (const chaiscript::exception::load_module_error &e) { } catch (const chaiscript::exception::load_module_error &e) {
// std::cerr << "error: " << e.what() << std::endl; // std::cerr << "error: " << e.what() << '\n';
errors.push_back(e); errors.push_back(e);
// Try next set // Try next set
} }
@@ -742,7 +804,7 @@ namespace chaiscript
if (t_handler) { if (t_handler) {
t_handler->handle(bv, m_engine); t_handler->handle(bv, m_engine);
} }
throw bv; throw;
} }
} }
@@ -768,7 +830,7 @@ namespace chaiscript
if (t_handler) { if (t_handler) {
t_handler->handle(bv, m_engine); t_handler->handle(bv, m_engine);
} }
throw bv; throw;
} }
} }
@@ -784,7 +846,7 @@ namespace chaiscript
/// ///
/// \param[in] t_input Script to execute /// \param[in] t_input Script to execute
/// \param[in] t_handler Optional Exception_Handler used for automatic unboxing of script thrown exceptions /// \param[in] t_handler Optional Exception_Handler used for automatic unboxing of script thrown exceptions
/// \param[in] t_filename Optional filename to report to the user for where the error occured. Useful /// \param[in] t_filename Optional filename to report to the user for where the error occurred. Useful
/// in special cases where you are loading a file internally instead of using eval_file /// in special cases where you are loading a file internally instead of using eval_file
/// ///
/// \return result of the script execution /// \return result of the script execution
@@ -798,7 +860,7 @@ namespace chaiscript
if (t_handler) { if (t_handler) {
t_handler->handle(bv, m_engine); t_handler->handle(bv, m_engine);
} }
throw bv; throw;
} }
} }
@@ -814,11 +876,11 @@ namespace chaiscript
if (t_handler) { if (t_handler) {
t_handler->handle(bv, m_engine); t_handler->handle(bv, m_engine);
} }
throw bv; throw;
} }
} }
/// \brief Loads the file specified by filename, evaluates it, and returns the typesafe result. /// \brief Loads the file specified by filename, evaluates it, and returns the type safe result.
/// \tparam T Type to extract from the result value of the script execution /// \tparam T Type to extract from the result value of the script execution
/// \param[in] t_filename File to load and parse. /// \param[in] t_filename File to load and parse.
/// \param[in] t_handler Optional Exception_Handler used for automatic unboxing of script thrown exceptions /// \param[in] t_handler Optional Exception_Handler used for automatic unboxing of script thrown exceptions
@@ -834,7 +896,7 @@ namespace chaiscript
if (t_handler) { if (t_handler) {
t_handler->handle(bv, m_engine); t_handler->handle(bv, m_engine);
} }
throw bv; throw;
} }
} }
}; };

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -40,9 +40,9 @@ def new(x) {
eval(type_name(x))(); eval(type_name(x))();
} }
def clone(x) : function_exists(type_name(x)) && call_exists(eval(type_name(x)), x) def clone(x) : function_exists(type_name(x)) && call_exists(eval(type_name(x)), x)
{ {
eval(type_name(x))(x); eval(type_name(x))(x).copy_var_attrs(x);
} }
@@ -56,11 +56,6 @@ def to_string(x) : call_exists(range, x) && !x.is_type("string"){
"[" + x.join(", ") + "]"; "[" + x.join(", ") + "]";
} }
# Basic to_string function
def to_string(x) {
internal_to_string(x);
}
# Prints to console with no carriage return # Prints to console with no carriage return
def puts(x) { def puts(x) {
print_string(x.to_string()); print_string(x.to_string());
@@ -136,8 +131,8 @@ def insert_at(container, pos, x)
# Returns the reverse of the given container # Returns the reverse of the given container
def reverse(container) { def reverse(container) {
auto retval = new(container); auto retval := new(container);
auto r = range(container); auto r := range(container);
while (!r.empty()) { while (!r.empty()) {
retval.push_back(r.back()); retval.push_back(r.back());
r.pop_back(); r.pop_back();
@@ -147,10 +142,16 @@ def reverse(container) {
# Return a range from a range # Return a range from a range
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) 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); clone(r);
} }
def range(r) : call_exists(range_internal, r)
{
var ri := range_internal(r);
ri.get_var_attr("internal_obj") := r;
ri;
}
# The retro attribute that contains the underlying range # The retro attribute that contains the underlying range
attr retro::m_range; attr retro::m_range;
@@ -200,19 +201,19 @@ def retro::empty()
# Performs the second value function over the container first value # Performs the second value function over the container first value
def for_each(container, func) : call_exists(range, container) { def for_each(container, func) : call_exists(range, container) {
var t_range = range(container); var t_range := range(container);
while (!t_range.empty()) { while (!t_range.empty()) {
func(t_range.front()); func(t_range.front());
t_range.pop_front(); t_range.pop_front();
} }
} }
def back_inserter(container) { def back_inserter(container) {
bind(push_back, container, _); bind(push_back, container, _);
} }
def contains(container, item, compare_func) : call_exists(range, container) { def contains(container, item, compare_func) : call_exists(range, container) {
auto t_range = range(container); auto t_range := range(container);
while (!t_range.empty()) { while (!t_range.empty()) {
if ( compare_func(t_range.front(), item) ) { if ( compare_func(t_range.front(), item) ) {
return true; return true;
@@ -220,15 +221,15 @@ def contains(container, item, compare_func) : call_exists(range, container) {
t_range.pop_front(); t_range.pop_front();
} }
return false; false;
} }
def contains(container, item) { def contains(container, item) {
return contains(container, item, eq) contains(container, item, eq)
} }
def map(container, func, inserter) : call_exists(range, container) { def map(container, func, inserter) : call_exists(range, container) {
auto range = range(container); auto range := range(container);
while (!range.empty()) { while (!range.empty()) {
inserter(func(range.front())); inserter(func(range.front()));
range.pop_front(); range.pop_front();
@@ -237,7 +238,7 @@ def map(container, func, inserter) : call_exists(range, container) {
# Performs the second value function over the container first value. Creates a new container with the results # Performs the second value function over the container first value. Creates a new container with the results
def map(container, func) { def map(container, func) {
auto retval = new(container); auto retval := new(container);
map(container, func, back_inserter(retval)); map(container, func, back_inserter(retval));
retval; retval;
} }
@@ -245,7 +246,7 @@ def map(container, func) {
# Performs the second value function over the container first value. Starts with initial and continues with each element. # Performs the second value function over the container first value. Starts with initial and continues with each element.
def foldl(container, func, initial) : call_exists(range, container){ def foldl(container, func, initial) : call_exists(range, container){
auto retval = initial; auto retval = initial;
auto range = range(container); auto range := range(container);
while (!range.empty()) { while (!range.empty()) {
retval = (func(range.front(), retval)); retval = (func(range.front(), retval));
range.pop_front(); range.pop_front();
@@ -266,8 +267,8 @@ def product(container) {
# Returns a new container with the elements of the first value concatenated with the elements of the second value # Returns a new container with the elements of the first value concatenated with the elements of the second value
def concat(x, y) : call_exists(clone, x) { def concat(x, y) : call_exists(clone, x) {
auto retval = x; auto retval = x;
auto inserter = back_inserter(retval); auto inserter := back_inserter(retval);
auto range = range(y); auto range := range(y);
while (!range.empty()) { while (!range.empty()) {
inserter(range.front()); inserter(range.front());
range.pop_front(); range.pop_front();
@@ -277,7 +278,7 @@ def concat(x, y) : call_exists(clone, x) {
def take(container, num, inserter) : call_exists(range, container) { def take(container, num, inserter) : call_exists(range, container) {
auto r = range(container); auto r := range(container);
auto i = num; auto i = num;
while ((i > 0) && (!r.empty())) { while ((i > 0) && (!r.empty())) {
inserter(r.front()); inserter(r.front());
@@ -289,14 +290,14 @@ def take(container, num, inserter) : call_exists(range, container) {
# Returns a new container with the given number of elements taken from the container # Returns a new container with the given number of elements taken from the container
def take(container, num) { def take(container, num) {
auto retval = new(container); auto retval := new(container);
take(container, num, back_inserter(retval)); take(container, num, back_inserter(retval));
retval; retval;
} }
def take_while(container, f, inserter) : call_exists(range, container) { def take_while(container, f, inserter) : call_exists(range, container) {
auto r = range(container); auto r := range(container);
while ((!r.empty()) && f(r.front())) { while ((!r.empty()) && f(r.front())) {
inserter(r.front()); inserter(r.front());
r.pop_front(); r.pop_front();
@@ -306,14 +307,14 @@ def take_while(container, f, inserter) : call_exists(range, container) {
# Returns a new container with the given elements match the second value function # Returns a new container with the given elements match the second value function
def take_while(container, f) { def take_while(container, f) {
auto retval = new(container); auto retval := new(container);
take_while(container, f, back_inserter(retval)); take_while(container, f, back_inserter(retval));
retval; retval;
} }
def drop(container, num, inserter) : call_exists(range, container) { def drop(container, num, inserter) : call_exists(range, container) {
auto r = range(container); auto r := range(container);
auto i = num; auto i = num;
while ((i > 0) && (!r.empty())) { while ((i > 0) && (!r.empty())) {
r.pop_front(); r.pop_front();
@@ -328,14 +329,14 @@ def drop(container, num, inserter) : call_exists(range, container) {
# Returns a new container with the given number of elements dropped from the given container # Returns a new container with the given number of elements dropped from the given container
def drop(container, num) { def drop(container, num) {
auto retval = new(container); auto retval := new(container);
drop(container, num, back_inserter(retval)); drop(container, num, back_inserter(retval));
retval; retval;
} }
def drop_while(container, f, inserter) : call_exists(range, container) { def drop_while(container, f, inserter) : call_exists(range, container) {
auto r = range(container); auto r := range(container);
while ((!r.empty())&& f(r.front())) { while ((!r.empty())&& f(r.front())) {
r.pop_front(); r.pop_front();
} }
@@ -348,7 +349,7 @@ def drop_while(container, f, inserter) : call_exists(range, container) {
# Returns a new container with the given elements dropped that match the second value function # Returns a new container with the given elements dropped that match the second value function
def drop_while(container, f) { def drop_while(container, f) {
auto retval = new(container); auto retval := new(container);
drop_while(container, f, back_inserter(retval)); drop_while(container, f, back_inserter(retval));
retval; retval;
} }
@@ -356,7 +357,7 @@ def drop_while(container, f) {
# Applies the second value function to the container. Starts with the first two elements. Expects at least 2 elements. # Applies the second value function to the container. Starts with the first two elements. Expects at least 2 elements.
def reduce(container, func) : container.size() >= 2 && call_exists(range, container) { def reduce(container, func) : container.size() >= 2 && call_exists(range, container) {
auto r = range(container); auto r := range(container);
auto retval = r.front(); auto retval = r.front();
r.pop_front(); r.pop_front();
retval = func(retval, r.front()); retval = func(retval, r.front());
@@ -372,7 +373,7 @@ def reduce(container, func) : container.size() >= 2 && call_exists(range, contai
# Returns a string of the elements in container delimited by the second value string # Returns a string of the elements in container delimited by the second value string
def join(container, delim) { def join(container, delim) {
auto retval = ""; auto retval = "";
auto range = range(container); auto range := range(container);
if (!range.empty()) { if (!range.empty()) {
retval += to_string(range.front()); retval += to_string(range.front());
range.pop_front(); range.pop_front();
@@ -387,7 +388,7 @@ def join(container, delim) {
def filter(container, f, inserter) : call_exists(range, container) { def filter(container, f, inserter) : call_exists(range, container) {
auto r = range(container); auto r := range(container);
while (!r.empty()) { while (!r.empty()) {
if (f(r.front())) { if (f(r.front())) {
inserter(r.front()); inserter(r.front());
@@ -399,7 +400,7 @@ def filter(container, f, inserter) : call_exists(range, container) {
# Returns a new Vector which match the second value function # Returns a new Vector which match the second value function
def filter(container, f) { def filter(container, f) {
auto retval = new(container); auto retval := new(container);
filter(container, f, back_inserter(retval)); filter(container, f, back_inserter(retval));
retval; retval;
} }
@@ -416,7 +417,7 @@ def generate_range(x, y, inserter) {
# Returns a new Vector which represents the range from the first value to the second value # Returns a new Vector which represents the range from the first value to the second value
def generate_range(x, y) { def generate_range(x, y) {
auto retval = Vector(); auto retval := Vector();
generate_range(x,y,back_inserter(retval)); generate_range(x,y,back_inserter(retval));
retval; retval;
} }
@@ -429,8 +430,8 @@ def collate(x, y) {
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) {
auto r_x = range(x); auto r_x := range(x);
auto r_y = range(y); auto r_y := range(y);
while (!r_x.empty() && !r_y.empty()) { while (!r_x.empty() && !r_y.empty()) {
inserter(f(r_x.front(), r_y.front())); inserter(f(r_x.front(), r_y.front()));
r_x.pop_front(); r_x.pop_front();
@@ -441,7 +442,7 @@ def zip_with(f, x, y, inserter) : call_exists(range, x) && call_exists(range, y)
# Returns a new Vector which joins matching elements of the second and third value with the first value function # Returns a new Vector which joins matching elements of the second and third value with the first value function
def zip_with(f, x, y) { def zip_with(f, x, y) {
auto retval = Vector(); auto retval := Vector();
zip_with(f,x,y,back_inserter(retval)); zip_with(f,x,y,back_inserter(retval));
retval; retval;
} }
@@ -505,7 +506,7 @@ def string::trim() {
def find(container, value, compare_func) : call_exists(range, container) && is_type(compare_func, "Function") { def find(container, value, compare_func) : call_exists(range, container) && is_type(compare_func, "Function") {
auto range = range(container); auto range := range(container);
while (!range.empty()) { while (!range.empty()) {
if (compare_func(range.front(), value)) { if (compare_func(range.front(), value)) {
return range; return range;
@@ -513,12 +514,12 @@ def find(container, value, compare_func) : call_exists(range, container) && is_t
range.pop_front(); range.pop_front();
} }
} }
return range; range;
} }
def find(container, value) { def find(container, value) {
return find(container, value, eq) find(container, value, eq)
} }

View File

@@ -5,7 +5,7 @@
namespace ChaiScript_Language namespace ChaiScript_Language
{ {
/// \page LangStandardLibraryRef ChaiScript Language Standard Libary Reference /// \page LangStandardLibraryRef ChaiScript Language Standard Library Reference
/// ///
/// ChaiScript, at its core, has some very functional programming-inspired habits. Few places show this off as clearly /// ChaiScript, at its core, has some very functional programming-inspired habits. Few places show this off as clearly
/// as the prelude, itself a name taken as a nod to the popular functional language Haskell. This prelude is available /// as the prelude, itself a name taken as a nod to the popular functional language Haskell. This prelude is available
@@ -112,7 +112,7 @@ class Map
}; };
/// \brief A concept implemented by string, Vector and Map. It is convertable to Range, default constructable and back_insertable /// \brief A concept implemented by string, Vector and Map. It is convertible to Range, default constructable and back_insertable
class Container class Container
{ {
public: public:
@@ -153,10 +153,10 @@ void print(Object o);
/// \brief ChaiScript representation of std::string. It is an std::string but only some member are exposed to ChaiScript. /// \brief ChaiScript representation of std::string. It is an std::string but only some member are exposed to ChaiScript.
/// ///
/// Because the ChaiScript string object is an std::string, it is directly convertable to and from std::string /// Because the ChaiScript string object is an std::string, it is directly convertible to and from std::string
/// using the chaiscript::boxed_cast and chaiscript::var functions. /// using the chaiscript::boxed_cast and chaiscript::var functions.
/// ///
/// With the exception of string::trim, string::rtrim, string::ltrim, all members are direct passthroughs to the /// With the exception of string::trim, string::rtrim, string::ltrim, all members are direct pass-throughs to the
/// std::string of the same name. /// std::string of the same name.
/// ///
/// \note Object and function notations are equivalent in ChaiScript. This means that /// \note Object and function notations are equivalent in ChaiScript. This means that
@@ -519,7 +519,7 @@ class Function
/// \brief Returns a vector of Type_Info objects that represent the param types for this function. /// \brief Returns a vector of Type_Info objects that represent the param types for this function.
/// The first value in the list is the return type. /// The first value in the list is the return type.
/// ///
/// If this function is a conglomeration of several functions (get_contained_values().size() > 0) /// If this function is a conglomerate of several functions (get_contained_values().size() > 0)
/// then the function returns as many Type_Info objects as it can. If the functions contained all have /// then the function returns as many Type_Info objects as it can. If the functions contained all have
/// the same arity, then it represents the arity. If they have different arities, it returns only /// the same arity, then it represents the arity. If they have different arities, it returns only
/// one value - the return type. /// one value - the return type.
@@ -534,7 +534,7 @@ class Function
/// \endcode /// \endcode
Vector get_param_types() const; Vector get_param_types() const;
/// \brief Returns true if the function has a guard to it. Always returns falls for a conglomerate function /// \brief Returns true if the function has a guard to it. Always returns false for a conglomerate function
bool has_guard() const; bool has_guard() const;
/// \brief Calls the function with the given set of parameters and returns the value; /// \brief Calls the function with the given set of parameters and returns the value;

View File

@@ -7,8 +7,13 @@
#ifndef CHAISCRIPT_UTILITY_UTILITY_HPP_ #ifndef CHAISCRIPT_UTILITY_UTILITY_HPP_
#define CHAISCRIPT_UTILITY_UTILITY_HPP_ #define CHAISCRIPT_UTILITY_UTILITY_HPP_
#include "../chaiscript.hpp"
#include <string> #include <string>
#include <utility>
#include <vector>
#include "../chaiscript.hpp"
#include "../dispatchkit/proxy_functions.hpp"
#include "../dispatchkit/type_info.hpp"
namespace chaiscript namespace chaiscript
@@ -16,28 +21,47 @@ namespace chaiscript
namespace utility namespace utility
{ {
/// \todo Use of this utility, and uniform initializer lists, is causing memory errors in MSVC /// Single step command for registering a class with ChaiScript
///
/// \param[in,out] t_module Model to add class to
/// \param[in] t_class_name Name of the class being registered
/// \param[in] t_constructors Vector of constructors to add
/// \param[in] t_funcs Vector of methods to add
///
/// \example Adding a basic class to ChaiScript in one step
///
/// \code
/// chaiscript::utility::add_class<test>(*m,
/// "test",
/// { constructor<test ()>(),
/// constructor<test (const test &)>() },
/// { {fun(&test::function), "function"},
/// {fun(&test::function2), "function2"},
/// {fun(&test::function3), "function3"},
/// {fun(static_cast<std::string(test::*)(double)>(&test::functionoverload)), "functionoverload" },
/// {fun(static_cast<std::string(test::*)(int)>(&test::functionoverload)), "functionoverload" },
/// {fun(static_cast<test & (test::*)(const test &)>(&test::operator=)), "=" }
/// }
/// );
///
template<typename Class, typename ModuleType> template<typename Class, typename ModuleType>
void add_class(ModuleType &t_module, void add_class(ModuleType &t_module,
const std::string &t_classname, const std::string &t_class_name,
const std::vector<chaiscript::Proxy_Function> &t_constructors, const std::vector<chaiscript::Proxy_Function> &t_constructors,
const std::vector<std::pair<chaiscript::Proxy_Function, std::string>> &t_funcs) const std::vector<std::pair<chaiscript::Proxy_Function, std::string>> &t_funcs)
{ {
t_module.add(chaiscript::user_type<Class>(), t_classname); t_module.add(chaiscript::user_type<Class>(), t_class_name);
for(const chaiscript::Proxy_Function &ctor: t_constructors) for(const chaiscript::Proxy_Function &ctor: t_constructors)
{ {
t_module.add(ctor, t_classname); t_module.add(ctor, t_class_name);
} }
for(auto fun: t_funcs) for(const auto &fun: t_funcs)
{ {
t_module.add(fun.first, fun.second); t_module.add(fun.first, fun.second);
} }
} }
} }
} }

View File

@@ -1,5 +1,7 @@
[![Build Status](https://travis-ci.org/ChaiScript/ChaiScript.png?branch=ChaiScript_5_0_CPP_11)](https://travis-ci.org/ChaiScript/ChaiScript) Master Status: [![Build Status](https://travis-ci.org/ChaiScript/ChaiScript.png?branch=master)](https://travis-ci.org/ChaiScript/ChaiScript) [![Coverage Status](https://coveralls.io/repos/ChaiScript/ChaiScript/badge.png?branch=master)](https://coveralls.io/r/ChaiScript/ChaiScript?branch=master)
[![Coverage Status](https://coveralls.io/repos/ChaiScript/ChaiScript/badge.png?branch=ChaiScript_5_0_CPP_11)](https://coveralls.io/r/ChaiScript/ChaiScript?branch=ChaiScript_5_0_CPP_11)
Develop Status: [![Build Status](https://travis-ci.org/ChaiScript/ChaiScript.png?branch=develop)](https://travis-ci.org/ChaiScript/ChaiScript) [![Coverage Status](https://coveralls.io/repos/ChaiScript/ChaiScript/badge.png?branch=develop)](https://coveralls.io/r/ChaiScript/ChaiScript?branch=develop)
ChaiScript ChaiScript
@@ -14,6 +16,8 @@ Release under the BSD license, see "license.txt" for details.
Introduction Introduction
============ ============
[![Gitter](https://badges.gitter.im/Join Chat.svg)](https://gitter.im/ChaiScript/ChaiScript?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
ChaiScript is one of the only embedded scripting language designed from the ChaiScript is one of the only embedded scripting language designed from the
ground up to directly target C++ and take advantage of modern C++ development ground up to directly target C++ and take advantage of modern C++ development
techniques, working with the developer like he expects it to work. Being a techniques, working with the developer like he expects it to work. Being a

View File

@@ -1,11 +1,51 @@
Notes: Notes:
=======
Current Version: 5.5.1
* There was overlap during the 5.x and 4.x development cycle, so some of the notes appear twice as the new features were developed for 4.x (which required boost) then ported to 5.x (which requires C++11). ### Changes since 5.5.0
* This is the last release of 5.x, all future development will be on the final merged 6.x line. * 30% performance increase
* Fix handling of object stack, resulting in greatly reduced memory usage
* Code cleanups
### Changes since 5.4.0
* 2x performance increase
* Significant code cleanups
* Throw exception if user attempts to call function on null object
* Allow user defined type conversions
* Fix object lifetime for nested function calls made at the global scope
* Fix returning of boolean values from function calls
### Changes since 5.3.1
* Decreased compile time and build size
* Make "reflection" module built in (losing some of the time / build size gains)
* Add new "class" syntax for ChaiScript defined methods and attributes see: [unittests/class.chai](unittests/class.chai) for examples
* Minor performance enhancements
* major to_string performance enhancements
* Provide API for retrieving registered type name #124
* Added strong reference to container to range object #132
### Changes since 5.3.0
* Add automatic conversion of arithmetic return types, following the same
rules as conversion of arithmetic types when passing parameters
* Add automatic casting up the inheritence hierarchy when possible.
* Enable travis.ci testing
* Allow users to add globals from within script
* Various static analysis fixes
* Code modernization to C++11
* Unofficial support for Haiku added
* Fix #121 - Inability to compile on cygwin
* Formatting fixes and spelling corrections
* Apply "include what you use" https://code.google.com/p/include-what-you-use/
* Apply clang-modernize
* Various threading fixes
* Performance improvements
### Changes since 5.2.0 ### Changes since 5.2.0
* Official support for MSVC with C++11. All major platforms and compilers are now support for C++11 release * Official support for MSVC with C++11. All major platforms and compilers are now support for C++11 release
### Changes since 4.2.0
* Enhanced unit tests * Enhanced unit tests
* Add `continue` statement, fix various use cases for `for` loops * Add `continue` statement, fix various use cases for `for` loops
* Fix use of suffixed numbers in vector initialization * Fix use of suffixed numbers in vector initialization

View File

@@ -13,12 +13,12 @@
void log(const std::string &msg) void log(const std::string &msg)
{ {
std::cout << "[" << time(nullptr) << "] " << msg << std::endl; std::cout << "[" << time(nullptr) << "] " << msg << '\n';
} }
void log(const std::string &module, const std::string &msg) void log(const std::string &module, const std::string &msg)
{ {
std::cout << "[" << time(nullptr) << "] <" << module << "> " << msg << std::endl; std::cout << "[" << time(nullptr) << "] <" << module << "> " << msg << '\n';
} }
void bound_log(const std::string &msg) void bound_log(const std::string &msg)
@@ -28,12 +28,12 @@ void bound_log(const std::string &msg)
void hello_world(const chaiscript::Boxed_Value & /*o*/) void hello_world(const chaiscript::Boxed_Value & /*o*/)
{ {
std::cout << "Hello World" << std::endl; std::cout << "Hello World\n";
} }
void hello_constructor(const chaiscript::Boxed_Value & /*o*/) void hello_constructor(const chaiscript::Boxed_Value & /*o*/)
{ {
std::cout << "Hello Constructor" << std::endl; std::cout << "Hello Constructor\n";
} }
@@ -62,7 +62,7 @@ struct System
void take_shared_ptr(const std::shared_ptr<const std::string> &p) void take_shared_ptr(const std::shared_ptr<const std::string> &p)
{ {
std::cout << *p << std::endl; std::cout << *p << '\n';
} }
int main(int /*argc*/, char * /*argv*/[]) { int main(int /*argc*/, char * /*argv*/[]) {
@@ -122,7 +122,7 @@ int main(int /*argc*/, char * /*argv*/[]) {
//the templated version of eval: //the templated version of eval:
int i = chai.eval<int>("5+5"); int i = chai.eval<int>("5+5");
std::cout << "5+5: " << i << std::endl; std::cout << "5+5: " << i << '\n';
//Add a new variable //Add a new variable
chai("var scripti = 15"); chai("var scripti = 15");
@@ -130,14 +130,14 @@ int main(int /*argc*/, char * /*argv*/[]) {
//We can even get a handle to the variables in the system //We can even get a handle to the variables in the system
int &scripti = chai.eval<int &>("scripti"); int &scripti = chai.eval<int &>("scripti");
std::cout << "scripti: " << scripti << std::endl; std::cout << "scripti: " << scripti << '\n';
scripti *= 2; scripti *= 2;
std::cout << "scripti (updated): " << scripti << std::endl; std::cout << "scripti (updated): " << scripti << '\n';
chai("print(\"Scripti from chai: \" + to_string(scripti))"); chai("print(\"Scripti from chai: \" + to_string(scripti))");
//To do: Add examples of handling Boxed_Values directly when needed //To do: Add examples of handling Boxed_Values directly when needed
//Creating a functor on the stack and using it immediatly //Creating a functor on the stack and using it immediately
int x = chai.eval<std::function<int (int, int)> >("fun (x, y) { return x + y; }")(5, 6); int x = chai.eval<std::function<int (int, int)> >("fun (x, y) { return x + y; }")(5, 6);
std::stringstream ss; std::stringstream ss;

View File

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

View File

@@ -1,10 +1,10 @@
//functions of zero params don't need them: //functions of zero params don't need them:
def meet { def meet {
print("Hello") print("Hello")
} }
def greet(x) { def greet(x) {
print("Hello, " + x.to_string()) print("Hello, " + x.to_string())
} }
//but you need parens for invocation: //but you need parens for invocation:

View File

@@ -0,0 +1,4 @@
for (var i = 0; i < 1000; ++i) {
puts(helloWorld("Bob12345"))
}

View File

@@ -0,0 +1,407 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#include <iostream>
#include <list>
#include <regex>
#define _CRT_SECURE_NO_WARNINGS
#include <chaiscript/chaiscript.hpp>
#include <chaiscript/chaiscript_stdlib.hpp>
#ifdef READLINE_AVAILABLE
#include <readline/readline.h>
#include <readline/history.h>
#else
char *mystrdup(const char *s) {
size_t len = strlen(s); // Space for length plus nul
char *d = static_cast<char*>(malloc(len + 1));
if (d == nullptr) return nullptr; // No memory
#ifdef CHAISCRIPT_MSVC
strcpy_s(d, len + 1, s); // Copy the characters
#else
strncpy(d, s, len); // Copy the characters
#endif
d[len] = '\0';
return d; // Return the new string
}
char* readline(const char* p)
{
std::string retval;
std::cout << p;
std::getline(std::cin, retval);
return std::cin.eof() ? nullptr : mystrdup(retval.c_str());
}
void add_history(const char*){}
void using_history(){}
#endif
void *cast_module_symbol(std::vector<std::string>(*t_path)())
{
union cast_union
{
std::vector<std::string>(*in_ptr)();
void *out_ptr;
};
cast_union c;
c.in_ptr = t_path;
return c.out_ptr;
}
std::vector<std::string> default_search_paths()
{
std::vector<std::string> paths;
#ifdef CHAISCRIPT_WINDOWS // force no unicode
CHAR path[4096];
int size = GetModuleFileNameA(0, path, sizeof(path) - 1);
std::string exepath(path, size);
size_t lastslash = exepath.rfind('\\');
size_t secondtolastslash = exepath.rfind('\\', lastslash - 1);
if (lastslash != std::string::npos)
{
paths.push_back(exepath.substr(0, lastslash));
}
if (secondtolastslash != std::string::npos)
{
return{ exepath.substr(0, secondtolastslash) + "\\lib\\chaiscript\\" };
}
#else
std::string exepath;
std::vector<char> buf(2048);
ssize_t size = -1;
if ((size = readlink("/proc/self/exe", &buf.front(), buf.size())) != -1)
{
exepath = std::string(&buf.front(), size);
}
if (exepath.empty())
{
if ((size = readlink("/proc/curproc/file", &buf.front(), buf.size())) != -1)
{
exepath = std::string(&buf.front(), size);
}
}
if (exepath.empty())
{
if ((size = readlink("/proc/self/path/a.out", &buf.front(), buf.size())) != -1)
{
exepath = std::string(&buf.front(), size);
}
}
if (exepath.empty())
{
Dl_info rInfo;
memset(&rInfo, 0, sizeof(rInfo));
if (!dladdr(cast_module_symbol(&default_search_paths), &rInfo) || !rInfo.dli_fname) {
return paths;
}
exepath = std::string(rInfo.dli_fname);
}
size_t lastslash = exepath.rfind('/');
size_t secondtolastslash = exepath.rfind('/', lastslash - 1);
if (lastslash != std::string::npos)
{
paths.push_back(exepath.substr(0, lastslash));
}
if (secondtolastslash != std::string::npos)
{
paths.push_back(exepath.substr(0, secondtolastslash) + "/lib/chaiscript/");
}
#endif
return paths;
}
void help(int n) {
if (n >= 0) {
std::cout << "ChaiScript evaluator. To evaluate an expression, type it and press <enter>." << std::endl;
std::cout << "Additionally, you can inspect the runtime system using:" << std::endl;
std::cout << " dump_system() - outputs all functions registered to the system" << std::endl;
std::cout << " dump_object(x) - dumps information about the given symbol" << std::endl;
}
else {
std::cout << "usage : chai [option]+" << std::endl;
std::cout << "option:" << std::endl;
std::cout << " -h | --help" << std::endl;
std::cout << " -i | --interactive" << std::endl;
std::cout << " -c | --command cmd" << std::endl;
std::cout << " -v | --version" << std::endl;
std::cout << " - --stdin" << std::endl;
std::cout << " filepath" << std::endl;
}
}
void version(int){
std::cout << "chai: compiled " << __TIME__ << " " << __DATE__ << std::endl;
}
std::string helloWorld(const std::string &t_name)
{
return "Hello " + t_name + "!";
}
bool throws_exception(const std::function<void()> &f)
{
try {
f();
}
catch (...) {
return true;
}
return false;
}
chaiscript::exception::eval_error get_eval_error(const std::function<void()> &f)
{
try {
f();
}
catch (const chaiscript::exception::eval_error &e) {
return e;
}
throw std::runtime_error("no exception throw");
}
std::string get_next_command() {
std::string retval("quit");
if (!std::cin.eof()) {
char *input_raw = readline("eval> ");
if (input_raw) {
add_history(input_raw);
std::string val(input_raw);
size_t pos = val.find_first_not_of("\t \n");
if (pos != std::string::npos)
{
val.erase(0, pos);
}
pos = val.find_last_not_of("\t \n");
if (pos != std::string::npos)
{
val.erase(pos + 1, std::string::npos);
}
retval = val;
::free(input_raw);
}
}
if (retval == "quit"
|| retval == "exit"
|| retval == "help"
|| retval == "version")
{
retval += "(0)";
}
return retval;
}
// We have to wrap exit with our own because Clang has a hard time with
// function pointers to functions with special attributes (system exit being marked NORETURN)
void myexit(int return_val) {
exit(return_val);
}
void interactive(chaiscript::ChaiScript& chai)
{
using_history();
for (;;) {
std::string input = get_next_command();
try {
// evaluate input
chaiscript::Boxed_Value val = chai.eval(input);
//Then, we try to print the result of the evaluation to the user
if (!val.get_type_info().bare_equal(chaiscript::user_type<void>())) {
try {
std::cout << chai.eval<std::function<std::string(const chaiscript::Boxed_Value &bv)> >("to_string")(val) << std::endl;
}
catch (...) {} //If we can't, do nothing
}
}
catch (const chaiscript::exception::eval_error &ee) {
std::cout << ee.what();
if (ee.call_stack.size() > 0) {
std::cout << "during evaluation at (" << ee.call_stack[0]->start.line << ", " << ee.call_stack[0]->start.column << ")";
}
std::cout << std::endl;
}
catch (const std::exception &e) {
std::cout << e.what();
std::cout << std::endl;
}
}
}
int main(int argc, char *argv[])
{
// Disable deprecation warning for getenv call.
#ifdef CHAISCRIPT_MSVC
#pragma warning(push)
#pragma warning(disable : 4996)
#endif
const char *usepath = getenv("CHAI_USE_PATH");
const char *modulepath = getenv("CHAI_MODULE_PATH");
#ifdef CHAISCRIPT_MSVC
#pragma warning(pop)
#endif
std::vector<std::string> usepaths;
usepaths.push_back("");
if (usepath)
{
usepaths.push_back(usepath);
}
std::vector<std::string> modulepaths;
std::vector<std::string> searchpaths = default_search_paths();
modulepaths.insert(modulepaths.end(), searchpaths.begin(), searchpaths.end());
modulepaths.push_back("");
if (modulepath)
{
modulepaths.push_back(modulepath);
}
//chaiscript::ChaiScript chai(modulepaths, usepaths);
chaiscript::ChaiScript chai(chaiscript::Std_Lib::library(), usepaths);
chai.add(chaiscript::fun(&myexit), "exit");
chai.add(chaiscript::fun(&myexit), "quit");
chai.add(chaiscript::fun(&help), "help");
chai.add(chaiscript::fun(&version), "version");
chai.add(chaiscript::fun(&throws_exception), "throws_exception");
chai.add(chaiscript::fun(&get_eval_error), "get_eval_error");
chai.add(chaiscript::fun(&helloWorld), "helloWorld");
clock_t begin = clock();
for (int i = 0; i < 1000; i++)
{
std::string str = helloWorld("Bob12345");
fwrite(str.c_str(), 1, str.size(), stdout);
}
clock_t end = clock();
double elapsed_secs = double(end - begin) / CLOCKS_PER_SEC;
//begin = clock();
////for (int i = 0; i < 1000; i++)
////{
//// chai.eval("puts(helloWorld(\"Bob12345\"));");
////}
//chai.eval_file("E:\\C++\\ChaiScript - 5.4.0\\samples\forx.chai");
//end = clock();
//elapsed_secs = double(end - begin) / CLOCKS_PER_SEC;
//printf("**MyProgram::time= %lf\n", elapsed_secs);
for (int i = 0; i < argc; ++i) {
if (i == 0 && argc > 1) {
++i;
}
std::string arg(i ? argv[i] : "--interactive");
enum {
eInteractive
, eCommand
, eFile
} mode = eCommand;
if (arg == "-c" || arg == "--command") {
if ((i + 1) >= argc) {
std::cout << "insufficient input following " << arg << std::endl;
return EXIT_FAILURE;
}
else {
arg = argv[++i];
}
}
else if (arg == "-" || arg == "--stdin") {
arg = "";
std::string line;
while (std::getline(std::cin, line)) {
arg += line + '\n';
}
}
else if (arg == "-v" || arg == "--version") {
arg = "version(0)";
}
else if (arg == "-h" || arg == "--help") {
arg = "help(-1)";
}
else if (arg == "-i" || arg == "--interactive") {
mode = eInteractive;
}
else if (arg.find('-') == 0) {
std::cout << "unrecognised argument " << arg << std::endl;
return EXIT_FAILURE;
}
else {
mode = eFile;
}
chaiscript::Boxed_Value val;
try {
switch (mode) {
case eInteractive: interactive(chai); break;
case eCommand: val = chai.eval(arg); break;
case eFile: {
begin = clock();
val = chai.eval_file(arg);
end = clock();
double elapsed_secs1 = double(end - begin) / CLOCKS_PER_SEC;
printf("**C++::time= %.10f\n", elapsed_secs);
printf("**ChaiScript::time= %.10f\n", elapsed_secs1);
break;
}
default: std::cout << "Unrecognized execution mode" << std::endl; return EXIT_FAILURE;
}
}
catch (const chaiscript::exception::eval_error &ee) {
std::cout << ee.pretty_print();
std::cout << std::endl;
return EXIT_FAILURE;
}
catch (std::exception &e) {
std::cout << e.what() << std::endl;
return EXIT_FAILURE;
}
}
return EXIT_SUCCESS;
}

View File

@@ -1,10 +1,10 @@
var i = 0 var i = 0
if (i == 0) { if (i == 0) {
print("i is 0") print("i is 0")
} }
else if (i == 1) { else if (i == 1) {
print("i is 1") print("i is 1")
} }
else { else {
print("i is not 0 or 1") print("i is not 0 or 1")
} }

134
samples/inheritance.cpp Normal file
View File

@@ -0,0 +1,134 @@
#include <chaiscript/chaiscript.hpp>
#include <chaiscript/chaiscript_stdlib.hpp>
class BaseClass
{
public:
BaseClass()
{
}
virtual ~BaseClass() {}
virtual std::string doSomething(float, double) const = 0;
void setValue(const std::string &t_val) {
if (validateValue(t_val))
{
m_value = t_val;
}
}
std::string getValue() const {
return m_value;
}
protected:
virtual bool validateValue(const std::string &t_val) = 0;
private:
std::string m_value;
};
class ChaiScriptDerived : public BaseClass
{
public:
ChaiScriptDerived(const std::vector<chaiscript::Boxed_Value> &t_funcs)
{
// using the range-checked .at() methods to give us an exception
// instead of a crash if the user passed in too-few params
tie(t_funcs.at(0), m_doSomethingImpl);
tie(t_funcs.at(1), m_validateValueImpl);
}
std::string doSomething(float f, double d) const CHAISCRIPT_OVERRIDE
{
assert(m_doSomethingImpl);
return m_doSomethingImpl(*this, f, d);
}
protected:
bool validateValue(const std::string &t_val) CHAISCRIPT_OVERRIDE
{
assert(m_validateValueImpl);
return m_validateValueImpl(*this, t_val);
}
private:
template<typename Param>
void tie(const chaiscript::Boxed_Value &t_func, Param &t_param)
{
t_param = chaiscript::boxed_cast<Param>(t_func);
}
std::function<std::string (const ChaiScriptDerived&, float, double)> m_doSomethingImpl;
std::function<bool (ChaiScriptDerived&, const std::string &t_val)> m_validateValueImpl;
};
int main()
{
chaiscript::ChaiScript chai(chaiscript::Std_Lib::library());
chai.add(chaiscript::fun(&BaseClass::doSomething), "doSomething");
chai.add(chaiscript::fun(&BaseClass::setValue), "setValue");
chai.add(chaiscript::fun(&BaseClass::getValue), "getValue");
chai.add(chaiscript::constructor<ChaiScriptDerived (const std::vector<chaiscript::Boxed_Value> &)>(), "ChaiScriptDerived");
chai.add(chaiscript::base_class<BaseClass, ChaiScriptDerived>());
chai.add(chaiscript::user_type<BaseClass>(), "BaseClass");
chai.add(chaiscript::user_type<ChaiScriptDerived>(), "ChaiScriptDerived");
std::string script = R""(
def MakeDerived() {
return ChaiScriptDerived(
// create a dynamically created array and pass it in to the constructor
[
fun(this, f, d) {
// see here that we are calling back into the 'this' pointer
return "${this.getValue()}${f * d}";
},
fun(this, new_val) {
if (new_val.size() < 5) {
true;
} else {
print("String ${new_val} is too long");
false;
}
}
]
);
}
var myderived := MakeDerived(); // avoid a copy by using reference assignment :=
)"";
chai.eval(script);
BaseClass &myderived = chai.eval<ChaiScriptDerived&>("myderived");
// at this point in the code myderived is both a ChaiScript variable and a C++ variable. In both cases
// it is a derivation of BaseClass, and the implementation is provided via ChaiScript functors
// assigned in the MakeDerived() factory function
//
// Notice that our validateValue() function has a requirement that the new string be < 5 characters long
myderived.setValue("1234");
assert(myderived.getValue() == "1234");
// chaiscript defined function will print out an error message and refuse to allow the setting
myderived.setValue("12345");
assert(myderived.getValue() == "1234");
chai.eval("myderived.setValue(\"new\")"); // set the value via chaiscript
assert(myderived.getValue() == "new");
// call the other derived method via chaiscript and return the value to c++ land:
std::string retval = chai.eval<std::string>("myderived.doSomething(2,4.3)");
assert(retval == "new8.6");
// The whole process is fully orthogonal
}

View File

@@ -1,20 +1,20 @@
for (var i = 0; i < 10; ++i) { for (var i = 0; i < 10; ++i) {
print("i: " + i.to_string()) print("i: " + i.to_string())
if (i == 5) { if (i == 5) {
break break
} }
} }
var j = 0 var j = 0
while (true) { while (true) {
while (true) { while (true) {
++j; ++j;
if (j == 5) { if (j == 5) {
break break
} }
} }
break break
} }
print("j: " + j.to_string()) print("j: " + j.to_string())

View File

@@ -24,7 +24,7 @@ std::string get_next_command() {
#endif #endif
} }
void fuction(void) void function(void)
{ {
// do nothing // do nothing
} }
@@ -35,28 +35,28 @@ class test
chaiscript::ChaiScript::State backupState; chaiscript::ChaiScript::State backupState;
public: public:
test() test()
: chai(chaiscript::Std_Lib::library()) : chai(chaiscript::Std_Lib::library())
{ {
backupState = chai.get_state(); backupState = chai.get_state();
} }
~test(){} ~test(){}
void ResetState() void ResetState()
{ {
chai.set_state(backupState); chai.set_state(backupState);
chai.add(chaiscript::fun(&fuction),"Whatever()"); chai.add(chaiscript::fun(&function),"Whatever()");
} }
void RunFile(std::string sFile) void RunFile(std::string sFile)
{ {
try { try {
chaiscript::Boxed_Value val = chai.eval_file(sFile); chaiscript::Boxed_Value val = chai.eval_file(sFile);
}
catch (std::exception &e) {
std::cout << e.what() << std::endl;
}
} }
catch (std::exception &e) {
std::cout << e.what() << '\n';
}
}
}; };
@@ -70,12 +70,12 @@ int main(int /*argc*/, char * /*argv*/[]) {
std::string command = ""; std::string command = "";
// //
// this loop increases memoryusage, if RunFile is not called (just hittin enter) // this loop increases memory usage, if RunFile is not called (just hitting enter)
// as soon RunFile gets called, memory will be freed. // as soon RunFile gets called, memory will be freed.
// //
// scenario1 - RunFile gets called every Loop: memoryusage does not change // scenario1 - RunFile gets called every Loop: memory usage does not change
// scenario2 - RunFile gets never called (just hitting enter): memoryusage increases every loop // scenario2 - RunFile gets never called (just hitting enter): memory usage increases every loop
// scenario3 - RunFile gets in changing intervals: memoryusage goes up and down, but never as // scenario3 - RunFile gets in changing intervals: memory usage goes up and down, but never as
// low as in case 1 scenario3 : // low as in case 1 scenario3 :
while(command != "quit") while(command != "quit")

View File

@@ -2,7 +2,7 @@ var x = -(1 + 2 - 3 * 4 / 2)
print("Answer: " + x.to_string()) print("Answer: " + x.to_string())
if (x >= 2 && x <= 4) { if (x >= 2 && x <= 4) {
print("x is between 2 and 4") print("x is between 2 and 4")
} }

View File

@@ -6,10 +6,10 @@
*/ */
var x = 4 var x = 4
def do_it() { def do_it() {
var x = 1 var x = 1
print(x) print(x)
var y = fun(x) { x + 1 } var y = fun(x) { x + 1 }
print(y(9)) print(y(9))
} }
do_it() do_it()
print(x) print(x)

View File

@@ -11,6 +11,6 @@ var size = vec.size()
print("Vector Size: " + size.to_string()); print("Vector Size: " + size.to_string());
while (i < size) { while (i < size) {
print(i.to_string() + ": " + to_string(vec[i])) print(i.to_string() + ": " + to_string(vec[i]))
i = i + 1 i = i + 1
} }

View File

@@ -1,5 +1,5 @@
var i = 0 var i = 0
while (i < 10) { while (i < 10) {
print("i: " + i.to_string()) print("i: " + i.to_string())
i = i + 1 i = i + 1
} }

View File

@@ -17,14 +17,15 @@
#else #else
char *mystrdup (const char *s) { char *mystrdup (const char *s) {
size_t len = strlen(s) + 1; // Space for length plus nul size_t len = strlen(s); // Space for length plus nul
char *d = static_cast<char*>(malloc (len)); char *d = static_cast<char*>(malloc (len+1));
if (d == nullptr) return nullptr; // No memory if (d == nullptr) return nullptr; // No memory
#ifdef CHAISCRIPT_MSVC #ifdef CHAISCRIPT_MSVC
strcpy_s(d, len, s); // Copy the characters strcpy_s(d, len, s); // Copy the characters
#else #else
strcpy(d,s); // Copy the characters strncpy(d,s,len); // Copy the characters
#endif #endif
d[len] = '\0';
return d; // Return the new string return d; // Return the new string
} }
@@ -33,7 +34,7 @@ char* readline(const char* p)
std::string retval; std::string retval;
std::cout << p ; std::cout << p ;
std::getline(std::cin, retval); std::getline(std::cin, retval);
return std::cin.eof() ? NULL : mystrdup(retval.c_str()); return std::cin.eof() ? nullptr : mystrdup(retval.c_str());
} }
@@ -135,24 +136,24 @@ std::vector<std::string> default_search_paths()
void help(int n) { void help(int n) {
if ( n >= 0 ) { if ( n >= 0 ) {
std::cout << "ChaiScript evaluator. To evaluate an expression, type it and press <enter>." << std::endl; std::cout << "ChaiScript evaluator. To evaluate an expression, type it and press <enter>.\n";
std::cout << "Additionally, you can inspect the runtime system using:" << std::endl; std::cout << "Additionally, you can inspect the runtime system using:\n";
std::cout << " dump_system() - outputs all functions registered to the system" << std::endl; std::cout << " dump_system() - outputs all functions registered to the system\n";
std::cout << " dump_object(x) - dumps information about the given symbol" << std::endl; std::cout << " dump_object(x) - dumps information about the given symbol\n";
} else { } else {
std::cout << "usage : chai [option]+" << std::endl; std::cout << "usage : chai [option]+\n";
std::cout << "option:" << std::endl; std::cout << "option:" << '\n';
std::cout << " -h | --help" << std::endl; std::cout << " -h | --help" << '\n';
std::cout << " -i | --interactive" << std::endl; std::cout << " -i | --interactive" << '\n';
std::cout << " -c | --command cmd" << std::endl; std::cout << " -c | --command cmd" << '\n';
std::cout << " -v | --version" << std::endl; std::cout << " -v | --version" << '\n';
std::cout << " - --stdin" << std::endl; std::cout << " - --stdin" << '\n';
std::cout << " filepath" << std::endl; std::cout << " filepath" << '\n';
} }
} }
void version(int){ void version(int){
std::cout << "chai: compiled " << __TIME__ << " " << __DATE__ << std::endl; std::cout << "chai: compiled " << __TIME__ << " " << __DATE__ << '\n';
} }
bool throws_exception(const std::function<void ()> &f) bool throws_exception(const std::function<void ()> &f)
@@ -230,7 +231,7 @@ void interactive(chaiscript::ChaiScript& chai)
//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().bare_equal(chaiscript::user_type<void>())) { if (!val.get_type_info().bare_equal(chaiscript::user_type<void>())) {
try { try {
std::cout << chai.eval<std::function<std::string (const chaiscript::Boxed_Value &bv)> >("to_string")(val) << std::endl; std::cout << chai.eval<std::function<std::string (const chaiscript::Boxed_Value &bv)> >("to_string")(val) << '\n';
} }
catch (...) {} //If we can't, do nothing catch (...) {} //If we can't, do nothing
} }
@@ -240,11 +241,11 @@ void interactive(chaiscript::ChaiScript& chai)
if (ee.call_stack.size() > 0) { if (ee.call_stack.size() > 0) {
std::cout << "during evaluation at (" << ee.call_stack[0]->start.line << ", " << ee.call_stack[0]->start.column << ")"; std::cout << "during evaluation at (" << ee.call_stack[0]->start.line << ", " << ee.call_stack[0]->start.column << ")";
} }
std::cout << std::endl; std::cout << '\n';
} }
catch (const std::exception &e) { catch (const std::exception &e) {
std::cout << e.what(); std::cout << e.what();
std::cout << std::endl; std::cout << '\n';
} }
} }
} }
@@ -304,7 +305,7 @@ int main(int argc, char *argv[])
if ( arg == "-c" || arg == "--command" ) { if ( arg == "-c" || arg == "--command" ) {
if ( (i+1) >= argc ) { if ( (i+1) >= argc ) {
std::cout << "insufficient input following " << arg << std::endl; std::cout << "insufficient input following " << arg << '\n';
return EXIT_FAILURE; return EXIT_FAILURE;
} else { } else {
arg = argv[++i]; arg = argv[++i];
@@ -322,7 +323,7 @@ int main(int argc, char *argv[])
} else if ( arg == "-i" || arg == "--interactive" ) { } else if ( arg == "-i" || arg == "--interactive" ) {
mode = eInteractive ; mode = eInteractive ;
} else if ( arg.find('-') == 0 ) { } else if ( arg.find('-') == 0 ) {
std::cout << "unrecognised argument " << arg << std::endl; std::cout << "unrecognised argument " << arg << '\n';
return EXIT_FAILURE; return EXIT_FAILURE;
} else { } else {
mode = eFile; mode = eFile;
@@ -334,16 +335,16 @@ int main(int argc, char *argv[])
case eInteractive : interactive(chai); break; case eInteractive : interactive(chai); break;
case eCommand : val = chai.eval(arg); break; case eCommand : val = chai.eval(arg); break;
case eFile : val = chai.eval_file(arg); break; case eFile : val = chai.eval_file(arg); break;
default : std::cout << "Unrecognized execution mode" << std::endl; return EXIT_FAILURE; default : std::cout << "Unrecognized execution mode\n"; return EXIT_FAILURE;
} }
} }
catch (const chaiscript::exception::eval_error &ee) { catch (const chaiscript::exception::eval_error &ee) {
std::cout << ee.pretty_print(); std::cout << ee.pretty_print();
std::cout << std::endl; std::cout << '\n';
return EXIT_FAILURE; return EXIT_FAILURE;
} }
catch (std::exception &e) { catch (std::exception &e) {
std::cout << e.what() << std::endl; std::cout << e.what() << '\n';
return EXIT_FAILURE; return EXIT_FAILURE;
} }
} }

View File

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

View File

@@ -2,6 +2,8 @@
#include <chaiscript/chaiscript.hpp> #include <chaiscript/chaiscript.hpp>
#include <string> #include <string>
class TestBaseType class TestBaseType
{ {
public: public:
@@ -11,6 +13,8 @@ class TestBaseType
virtual ~TestBaseType() {} virtual ~TestBaseType() {}
virtual int func() { return 0; } virtual int func() { return 0; }
int base_only_func() { return -9; }
const TestBaseType &constMe() const { return *this; } const TestBaseType &constMe() const { return *this; }
int val; int val;
@@ -20,6 +24,30 @@ class TestBaseType
TestBaseType &operator=(const TestBaseType &); TestBaseType &operator=(const TestBaseType &);
}; };
class Type2
{
public:
Type2(TestBaseType t_bt)
: m_bt(std::move(t_bt)),
m_str("Hello World")
{
}
int get_val() const
{
return m_bt.val;
}
const char *get_str() const
{
return m_str.c_str();
}
private:
TestBaseType m_bt;
std::string m_str;
};
enum TestEnum enum TestEnum
{ {
TestValue1 = 1 TestValue1 = 1
@@ -34,12 +62,34 @@ class TestDerivedType : public TestBaseType
{ {
public: public:
virtual ~TestDerivedType() {} virtual ~TestDerivedType() {}
virtual int func() { return 1; } virtual int func() CHAISCRIPT_OVERRIDE { return 1; }
int derived_only_func() { return 19; }
private: private:
TestDerivedType &operator=(const TestDerivedType &); TestDerivedType &operator=(const TestDerivedType &);
}; };
class TestMoreDerivedType : public TestDerivedType
{
public:
virtual ~TestMoreDerivedType() {}
};
std::shared_ptr<TestBaseType> derived_type_factory()
{
return std::make_shared<TestDerivedType>();
}
std::shared_ptr<TestBaseType> more_derived_type_factory()
{
return std::make_shared<TestMoreDerivedType>();
}
std::shared_ptr<TestBaseType> null_factory()
{
return std::shared_ptr<TestBaseType>();
}
std::string hello_world() std::string hello_world()
{ {
return "Hello World"; return "Hello World";
@@ -70,6 +120,8 @@ CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_test_mo
m->add(chaiscript::user_type<TestBaseType>(), "TestBaseType"); m->add(chaiscript::user_type<TestBaseType>(), "TestBaseType");
m->add(chaiscript::user_type<TestDerivedType>(), "TestDerivedType"); m->add(chaiscript::user_type<TestDerivedType>(), "TestDerivedType");
m->add(chaiscript::user_type<TestMoreDerivedType>(), "TestMoreDerivedType");
m->add(chaiscript::user_type<Type2>(), "Type2");
m->add(chaiscript::constructor<TestBaseType ()>(), "TestBaseType"); m->add(chaiscript::constructor<TestBaseType ()>(), "TestBaseType");
// m->add(chaiscript::constructor<TestBaseType (int)>(), "TestBaseType"); // m->add(chaiscript::constructor<TestBaseType (int)>(), "TestBaseType");
@@ -79,14 +131,30 @@ CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_test_mo
m->add(chaiscript::constructor<TestDerivedType ()>(), "TestDerivedType"); m->add(chaiscript::constructor<TestDerivedType ()>(), "TestDerivedType");
m->add(chaiscript::constructor<TestDerivedType (const TestDerivedType &)>(), "TestDerivedType"); m->add(chaiscript::constructor<TestDerivedType (const TestDerivedType &)>(), "TestDerivedType");
m->add(chaiscript::constructor<TestMoreDerivedType ()>(), "TestMoreDerivedType");
m->add(chaiscript::constructor<TestMoreDerivedType (const TestMoreDerivedType &)>(), "TestMoreDerivedType");
/// \todo automatic chaining of base classes?
m->add(chaiscript::base_class<TestBaseType, TestDerivedType>()); m->add(chaiscript::base_class<TestBaseType, TestDerivedType>());
m->add(chaiscript::base_class<TestBaseType, TestMoreDerivedType>());
m->add(chaiscript::base_class<TestDerivedType, TestMoreDerivedType>());
m->add(chaiscript::fun(&TestDerivedType::derived_only_func), "derived_only_func");
m->add(chaiscript::fun(&derived_type_factory), "derived_type_factory");
m->add(chaiscript::fun(&more_derived_type_factory), "more_derived_type_factory");
m->add(chaiscript::fun(&null_factory), "null_factory");
m->add(chaiscript::fun(&TestDerivedType::func), "func");
m->add(chaiscript::fun(&TestBaseType::func), "func"); m->add(chaiscript::fun(&TestBaseType::func), "func");
m->add(chaiscript::fun(&TestBaseType::val), "val"); m->add(chaiscript::fun(&TestBaseType::val), "val");
m->add(chaiscript::fun(&TestBaseType::const_val), "const_val"); m->add(chaiscript::fun(&TestBaseType::const_val), "const_val");
m->add(chaiscript::fun(&TestBaseType::base_only_func), "base_only_func");
m->add(chaiscript::fun(&get_new_int), "get_new_int"); m->add(chaiscript::fun(&get_new_int), "get_new_int");
m->add_global_const(chaiscript::const_var(TestValue1), "TestValue1"); m->add_global_const(chaiscript::const_var(TestValue1), "TestValue1");
m->add(chaiscript::user_type<TestEnum>(), "TestEnum"); m->add(chaiscript::user_type<TestEnum>(), "TestEnum");
@@ -94,6 +162,12 @@ CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_test_mo
m->add(chaiscript::fun(&to_int), "to_int"); m->add(chaiscript::fun(&to_int), "to_int");
m->add(chaiscript::fun(&TestBaseType::constMe), "constMe"); m->add(chaiscript::fun(&TestBaseType::constMe), "constMe");
m->add(chaiscript::type_conversion<TestBaseType, Type2>([](const TestBaseType &t_bt) { return Type2(t_bt); }));
m->add(chaiscript::fun(&Type2::get_val), "get_val");
m->add(chaiscript::fun(&Type2::get_str), "get_str");
m->add(chaiscript::type_conversion<const char *, std::string>());
m->add(chaiscript::constructor<Type2 (const TestBaseType &)>(), "Type2");
return m; return m;
} }

View File

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

View File

@@ -1,4 +1,3 @@
load_module("reflection")
def deep() def deep()
{ {

View File

@@ -1,17 +1,17 @@
def bob(x, y, z) { def bob(x, y, z) {
x + y + z x + y + z
} }
def bob(x, y) { def bob(x, y) {
x - y x - y
} }
def bob(x) { def bob(x) {
-x -x
} }
def bob() { def bob() {
10 10
} }
assert_equal(10, bob()) assert_equal(10, bob())

View File

@@ -1,4 +1,3 @@
load_module("reflection")
var parser := ChaiScript_Parser() var parser := ChaiScript_Parser()
var parse_success = parser.parse("3 + 4", "INPUT") var parse_success = parser.parse("3 + 4", "INPUT")
var a := parser.ast() var a := parser.ast()

View File

@@ -1,5 +1,5 @@
def sam() { def sam() {
return 5 return 5
} }
assert_equal(5, sam()) assert_equal(5, sam())

View File

@@ -1,4 +1,4 @@
def greet { def greet {
return("hello") return("hello")
} }

View File

@@ -18,6 +18,11 @@ void f3(double)
{ {
} }
void f_func_return(const std::function<unsigned int (unsigned long)> &f)
{
// test the ability to return an unsigned with auto conversion
f(4);
}
int main() int main()
{ {
@@ -29,6 +34,8 @@ int main()
chai.add(chaiscript::fun(&f1), "f3"); chai.add(chaiscript::fun(&f1), "f3");
chai.add(chaiscript::fun(&f4), "f3"); chai.add(chaiscript::fun(&f4), "f3");
chai.add(chaiscript::fun(&f_func_return), "func_return");
// no overloads // no overloads
chai.eval("f1(0)"); chai.eval("f1(0)");
chai.eval("f1(0l)"); chai.eval("f1(0l)");
@@ -46,7 +53,12 @@ int main()
// 1 non-arithmetic overload // 1 non-arithmetic overload
chai.eval("f2(1.0)"); chai.eval("f2(1.0)");
// this is the one call we expect to fail // various options for returning with conversions from chaiscript
chai.eval("func_return(fun(x) { return 5u; })");
chai.eval("func_return(fun(x) { return 5; })");
chai.eval("func_return(fun(x) { return 5.0f; })");
// this is the one call we expect to fail, ambiguous overloads
try { try {
chai.eval("f2(1.0l)"); chai.eval("f2(1.0l)");
} catch (const std::exception &) { } catch (const std::exception &) {

View File

@@ -15,16 +15,16 @@ bool run_test_type_conversion(const Boxed_Value &bv, bool expectedpass)
use(ret); use(ret);
} catch (const chaiscript::exception::bad_boxed_cast &/*e*/) { } catch (const chaiscript::exception::bad_boxed_cast &/*e*/) {
if (expectedpass) { if (expectedpass) {
// std::cerr << "Failure in run_test_type_conversion: " << e.what() << std::endl; // std::cerr << "Failure in run_test_type_conversion: " << e.what() << '\n';
return false; return false;
} else { } else {
return true; return true;
} }
} catch (const std::exception &e) { } catch (const std::exception &e) {
std::cerr << "Unexpected standard exception when attempting cast_conversion: " << e.what() << std::endl; std::cerr << "Unexpected standard exception when attempting cast_conversion: " << e.what() << '\n';
return false; return false;
} catch (...) { } catch (...) {
std::cerr << "Unexpected unknown exception when attempting cast_conversion." << std::endl; std::cerr << "Unexpected unknown exception when attempting cast_conversion.\n";
return false; return false;
} }
@@ -44,10 +44,10 @@ bool test_type_conversion(const Boxed_Value &bv, bool expectedpass)
if (!ret) if (!ret)
{ {
std::cerr << "Error with type conversion test. From: " std::cerr << "Error with type conversion test. From: "
<< (bv.is_const()?(std::string("const ")):(std::string())) << bv.get_type_info().name() << (bv.is_const()?(std::string("const ")):(std::string())) << bv.get_type_info().name()
<< " To: " << " To: "
<< (std::is_const<To>::value?(std::string("const ")):(std::string())) << typeid(To).name() << (std::is_const<To>::value?(std::string("const ")):(std::string())) << typeid(To).name()
<< " test was expected to " << ((expectedpass)?(std::string("succeed")):(std::string("fail"))) << " but did not" << std::endl; << " test was expected to " << ((expectedpass)?(std::string("succeed")):(std::string("fail"))) << " but did not\n";
} }
return ret; return ret;
@@ -264,21 +264,21 @@ bool pointer_test(const T& default_value, const T& new_value)
if (p != (*result) ) { if (p != (*result) ) {
std::cerr << "Pointer passed in different than one returned" << std::endl; std::cerr << "Pointer passed in different than one returned\n";
return false; return false;
} }
if (*p != *(*result) ) { if (*p != *(*result) ) {
std::cerr << "Somehow dereferenced pointer values are not the same?" << std::endl; std::cerr << "Somehow dereferenced pointer values are not the same?\n";
return false; return false;
} }
return true; return true;
} catch (const exception::bad_boxed_cast &) { } catch (const exception::bad_boxed_cast &) {
std::cerr << "Bad boxed cast performing ** to ** test" << std::endl; std::cerr << "Bad boxed cast performing ** to ** test\n";
return false; return false;
} catch (...) { } catch (...) {
std::cerr << "Unknown exception performing ** to ** test" << std::endl; std::cerr << "Unknown exception performing ** to ** test\n";
return false; return false;
} }

View File

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

View File

@@ -3,7 +3,7 @@
extern "C" extern "C"
{ {
int dosomething(int i) int do_something(int i)
{ {
return i % 2; return i % 2;
} }
@@ -13,8 +13,8 @@ int main()
{ {
chaiscript::ChaiScript chai; chaiscript::ChaiScript chai;
chai.add(chaiscript::fun(&dosomething), "dosomething"); chai.add(chaiscript::fun(&do_something), "do_something");
return chai.eval<int>("dosomething(101)") == 101 % 2?EXIT_SUCCESS:EXIT_FAILURE; return chai.eval<int>("do_something(101)") == 101 % 2?EXIT_SUCCESS:EXIT_FAILURE;
} }

27
unittests/class.chai Normal file
View File

@@ -0,0 +1,27 @@
class Vector3
{
// you can use attr, auto or var in this context
attr x
auto y
var z
def Vector3(x,y,z)
{
this.x = x
this.y = y
this.z = z
}
def doSomething(mult)
{
return this.x * this.y * this.z * mult
}
}
auto v = Vector3(1,2,3)
assert_equal(1, v.x)
assert_equal(v.doSomething(2), 12)

View File

@@ -8,7 +8,7 @@ void assert_equal(const LHS &lhs, const RHS &rhs)
{ {
return; return;
} else { } else {
std::cout << "Got: " << lhs << " expected " << rhs << std::endl; std::cout << "Got: " << lhs << " expected " << rhs << '\n';
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
} }

View File

@@ -16,7 +16,7 @@ int test_generic()
} }
} }
std::cout << "test_generic failed" << std::endl; std::cout << "test_generic failed\n";
return EXIT_FAILURE; return EXIT_FAILURE;
} }
@@ -33,7 +33,7 @@ int test_1()
} }
} }
std::cout << "test_1 failed" << std::endl; std::cout << "test_1 failed\n";
return EXIT_FAILURE; return EXIT_FAILURE;
} }
@@ -50,7 +50,7 @@ int test_2()
} }
} }
std::cout << "test_2 failed" << std::endl; std::cout << "test_2 failed\n";
return EXIT_FAILURE; return EXIT_FAILURE;
} }
@@ -61,22 +61,22 @@ int test_5()
try { try {
chai.eval("throw(runtime_error(\"error\"))", chaiscript::exception_specification<int, double, float, const std::string &, const std::exception &>()); chai.eval("throw(runtime_error(\"error\"))", chaiscript::exception_specification<int, double, float, const std::string &, const std::exception &>());
} catch (const double) { } catch (const double) {
std::cout << "test_5 failed with double" << std::endl; std::cout << "test_5 failed with double\n";
return EXIT_FAILURE; return EXIT_FAILURE;
} catch (int) { } catch (int) {
std::cout << "test_5 failed with int" << std::endl; std::cout << "test_5 failed with int\n";
return EXIT_FAILURE; return EXIT_FAILURE;
} catch (float) { } catch (float) {
std::cout << "test_5 failed with float" << std::endl; std::cout << "test_5 failed with float\n";
return EXIT_FAILURE; return EXIT_FAILURE;
} catch (const std::string &) { } catch (const std::string &) {
std::cout << "test_5 failed with string" << std::endl; std::cout << "test_5 failed with string\n";
return EXIT_FAILURE; return EXIT_FAILURE;
} catch (const std::exception &) { } catch (const std::exception &) {
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
std::cout << "test_5 failed" << std::endl; std::cout << "test_5 failed\n";
return EXIT_FAILURE; return EXIT_FAILURE;
} }
@@ -87,22 +87,22 @@ int test_unhandled()
try { try {
chai.eval("throw(\"error\")", chaiscript::exception_specification<int, double, float, const std::exception &>()); chai.eval("throw(\"error\")", chaiscript::exception_specification<int, double, float, const std::exception &>());
} catch (double) { } catch (double) {
std::cout << "test_unhandled failed with double" << std::endl; std::cout << "test_unhandled failed with double\n";
return EXIT_FAILURE; return EXIT_FAILURE;
} catch (int) { } catch (int) {
std::cout << "test_unhandled failed with int" << std::endl; std::cout << "test_unhandled failed with int\n";
return EXIT_FAILURE; return EXIT_FAILURE;
} catch (float) { } catch (float) {
std::cout << "test_unhandled failed with float" << std::endl; std::cout << "test_unhandled failed with float\n";
return EXIT_FAILURE; return EXIT_FAILURE;
} catch (const std::exception &) { } catch (const std::exception &) {
std::cout << "test_unhandled failed with std::exception" << std::endl; std::cout << "test_unhandled failed with std::exception\n";
return EXIT_FAILURE; return EXIT_FAILURE;
} catch (const chaiscript::Boxed_Value &) { } catch (const chaiscript::Boxed_Value &) {
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
std::cout << "test_unhandled failed" << std::endl; std::cout << "test_unhandled failed\n";
return EXIT_FAILURE; return EXIT_FAILURE;
} }

View File

@@ -1,4 +1,3 @@
load_module("reflection")
def deep() def deep()
{ {

View File

@@ -19,7 +19,7 @@ int main()
// Dot notation // Dot notation
try { try {
// non-existant function // non-existent function
chai.eval("\"test\".test_one()"); chai.eval("\"test\".test_one()");
eval_error = false; eval_error = false;
} catch (const chaiscript::exception::eval_error &) { } catch (const chaiscript::exception::eval_error &) {
@@ -51,7 +51,7 @@ int main()
// regular notation // regular notation
try { try {
// non-existant function // non-existent function
chai.eval("test_one(\"test\")"); chai.eval("test_one(\"test\")");
eval_error = false; eval_error = false;
} catch (const chaiscript::exception::eval_error &) { } catch (const chaiscript::exception::eval_error &) {

View File

@@ -0,0 +1,10 @@
var i = 5
add_global(i, "j")
def myFun()
{
assert_equal(j, 5)
}
myFun();

View File

@@ -15,3 +15,26 @@ assert_equal(15, t.const_val);
t.val = 23; t.val = 23;
assert_equal(23, t.val) assert_equal(23, t.val)
// test_derived_factory returns a TestDerivedType contained
// in a shared_ptr<TestBaseType>. This is testing our ability
// to detect that and do the down casting for the user automatically
// at runtime
assert_equal(t.derived_only_func(), 19);
var d := derived_type_factory();
assert_equal(d.derived_only_func(), 19);
var t2 = TestMoreDerivedType();
assert_equal(t2.derived_only_func(), 19);
assert_equal(t2.base_only_func(), -9);
var md := more_derived_type_factory();
assert_equal(md.derived_only_func(), 19);
assert_equal(md.base_only_func(), -9);
assert_equal(md.func(), 1);
assert_equal(t2.func(), 1);
assert_equal(d.func(), 1);

View File

@@ -7,7 +7,7 @@ bool test_literal(T val, const std::string &str)
{ {
chaiscript::ChaiScript chai; chaiscript::ChaiScript chai;
T val2 = chai.eval<T>(str); T val2 = chai.eval<T>(str);
std::cout << "Comparing : " << val << " " << val2 << std::endl; std::cout << "Comparing : " << val << " " << val2 << '\n';
return val == val2; return val == val2;
} }

View File

@@ -1,17 +1,17 @@
def bob(x, y, z) { def bob(x, y, z) {
x + y + z x + y + z
} }
def bob(x, y) { def bob(x, y) {
x - y x - y
} }
def bob(x) { def bob(x) {
-x -x
} }
def bob() { def bob() {
10 10
} }
assert_equal(10, bob()) assert_equal(10, bob())

View File

@@ -35,7 +35,7 @@ int main()
{ {
// Disable deprecation warning for getenv call. // Disable deprecation warning for getenv call.
#ifdef CHAISCRIPT_MSVC #ifdef CHAISCRIPT_MSVC
#ifdef max // Why microsoft? why? #ifdef max // Why Microsoft? why?
#undef max #undef max
#endif #endif
#pragma warning(push) #pragma warning(push)

View File

@@ -0,0 +1,13 @@
load_module("test_module")
auto o := null_factory();
try {
o.func();
} catch (e) {
exit(0);
}
assert_true(false);

View File

@@ -0,0 +1,69 @@
#include <chaiscript/chaiscript.hpp>
#include <chaiscript/chaiscript_stdlib.hpp>
template<typename T>
struct Vector2
{
Vector2() : x(0), y(0) {};
Vector2(T px, T py) : x(px), y(py) {};
Vector2(const Vector2& cp) : x(cp.x), y(cp.y) {};
Vector2& operator+=(const Vector2& vec_r)
{
x += vec_r.x;
y += vec_r.y;
return *this;
}
Vector2 operator+(const Vector2& vec_r)
{
return Vector2(*this += vec_r);
}
void operator=(const Vector2& ver_r)
{
x = ver_r.x;
y = ver_r.y;
}
T x;
T y;
};
Vector2<float> GetValue()
{
return Vector2<float>(10,15);
}
int main()
{
chaiscript::ChaiScript _script(chaiscript::Std_Lib::library());
//Registering stuff
_script.add(chaiscript::user_type<Vector2<float>>(), "Vector2f");
_script.add(chaiscript::constructor<Vector2<float> ()>(), "Vector2f");
_script.add(chaiscript::constructor<Vector2<float> (float, float)>(), "Vector2f");
_script.add(chaiscript::constructor<Vector2<float> (const Vector2<float>&)>(), "Vector2f");
_script.add(chaiscript::fun(&Vector2<float>::x), "x");
_script.add(chaiscript::fun(&Vector2<float>::y), "y");
_script.add(chaiscript::fun(&Vector2<float>::operator +), "+");
_script.add(chaiscript::fun(&Vector2<float>::operator +=), "+=");
_script.add(chaiscript::fun(&Vector2<float>::operator =), "=");
_script.add(chaiscript::fun(&GetValue), "getValue");
_script.eval(R"(
var test = 0.0
var test2 = Vector2f(10,10)
test = getValue().x
print(test)
print(test2.x)
)");
if (_script.eval<std::string>("to_string(test)") != "10") { return EXIT_FAILURE; }
if (_script.eval<std::string>("to_string(test2.x)") != "10") { return EXIT_FAILURE; }
//_script.eval_file("object_lifetime_test2.inc");
}

View File

@@ -1,4 +1,3 @@
load_module("reflection")
try { try {
eval("def `+`(x, y) \n { \n print(i); \n } \n \n var i = 10; \n \"1\" + 1;\n") eval("def `+`(x, y) \n { \n print(i); \n } \n \n var i = 10; \n \"1\" + 1;\n")

View File

@@ -2,3 +2,9 @@ auto x = [1, 2, 3, 4]
auto r = range(x) auto r = range(x)
r.pop_front() r.pop_front()
assert_equal(2, r.front()); assert_equal(2, r.front());
// test with temporary vector for range
auto q = range([1, 2, 3, 4])
q.pop_front()
assert_equal(2, q.front());

View File

@@ -1,4 +1,3 @@
load_module("reflection")
auto& parser = ChaiScript_Parser() auto& parser = ChaiScript_Parser()
auto parse_success = parser.parse("3 + 4", "INPUT") auto parse_success = parser.parse("3 + 4", "INPUT")
auto& a = parser.ast() auto& a = parser.ast()

View File

@@ -1,5 +1,5 @@
def sam() { def sam() {
return 5 return 5
} }
assert_equal(5, sam()) assert_equal(5, sam())

View File

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

View File

@@ -2,6 +2,7 @@
#include <chaiscript/chaiscript_defines.hpp> #include <chaiscript/chaiscript_defines.hpp>
#include <chaiscript/dispatchkit/type_info.hpp> #include <chaiscript/dispatchkit/type_info.hpp>
#include <iostream>
#include <cstdlib> #include <cstdlib>
void test_type(const chaiscript::Type_Info &ti, bool t_is_const, bool t_is_pointer, bool t_is_reference, bool t_is_void, void test_type(const chaiscript::Type_Info &ti, bool t_is_const, bool t_is_pointer, bool t_is_reference, bool t_is_void,
@@ -30,5 +31,7 @@ int main()
test_type(chaiscript::user_type<const int *>(), true, true, false, false, false); test_type(chaiscript::user_type<const int *>(), true, true, false, false, false);
test_type(chaiscript::Type_Info(), false, false, false, false, true); test_type(chaiscript::Type_Info(), false, false, false, false, true);
std::cout << "Size of Type_Info " << sizeof(chaiscript::Type_Info) << '\n';
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }

View File

@@ -0,0 +1,22 @@
// Tests to make sure that the order in which function dispatches occur is correct
#include <chaiscript/chaiscript.hpp>
#include <cstdlib>
class MyClass
{
};
int main()
{
chaiscript::ChaiScript chai;
auto type = chaiscript::user_type<MyClass>();
chai.add(type, "MyClass");
if (chai.get_type_name(type) == "MyClass" && chai.get_type_name<MyClass>() == "MyClass")
{
return EXIT_SUCCESS;
} else {
return EXIT_FAILURE;
}
}

View File

@@ -1,4 +1,4 @@
def greet { def greet {
return("hello") return("hello")
} }

View File

@@ -0,0 +1,11 @@
add_type_conversion(type("string"), type("Type_Info"), fun(s) { return type(s); });
// This looks simple, but it takes the string "string" and using the registered
// conversion above, automatically converts that into a Type_Info object, which then
// allows the Type_Info.name() function to be called
assert_equal("string".name(), "string");

View File

@@ -0,0 +1,27 @@
load_module("test_module")
auto t := TestBaseType();
// This uses the TestBaseType to Type2 user type
// conversion which was added in the module and then calls
// "get_val()" which exists on the Type2 type
//assert_equal(t.get_val(), 10);
//print("Made it past test 1");
var t2 := Type2(t);
var str = string(get_str(t2));
assert_equal("Hello World", str);
print("Made it past test 2");
assert_equal(11, size(get_str(t2)));
print("Made it past test 3");
assert_equal(11, t2.get_str().size());
print("Made it past test 4");
assert_equal(11, t.get_str().size());
print("Made it past test 5");