Compare commits
341 Commits
v5.7.0
...
release-5.
Author | SHA1 | Date | |
---|---|---|---|
![]() |
2c99e6cd32 | ||
![]() |
a38b254a98 | ||
![]() |
77231461ca | ||
![]() |
0d4a99af82 | ||
![]() |
9f30d84f39 | ||
![]() |
508729ec77 | ||
![]() |
ab07872857 | ||
![]() |
23c13e6570 | ||
![]() |
7339ff2c2f | ||
![]() |
665125665a | ||
![]() |
d1c7645a4e | ||
![]() |
58faea1cf2 | ||
![]() |
8b7fe33bf1 | ||
![]() |
21495ebb40 | ||
![]() |
bec1b91b7b | ||
![]() |
4b81a24a0a | ||
![]() |
cefb4d3c78 | ||
![]() |
41c1c490c8 | ||
![]() |
1e62eb4e12 | ||
![]() |
c07c2a9cc2 | ||
![]() |
46c45e8fc7 | ||
![]() |
91a3ae1f14 | ||
![]() |
328aef10d7 | ||
![]() |
71c67bc763 | ||
![]() |
539ee3c84f | ||
![]() |
594958ea8b | ||
![]() |
83b966df47 | ||
![]() |
c24004c70e | ||
![]() |
a0ee8d1137 | ||
![]() |
765e6ed8df | ||
![]() |
0cb4c18638 | ||
![]() |
ad7e2138d9 | ||
![]() |
0eee23109e | ||
![]() |
b663654a6d | ||
![]() |
2a8c248167 | ||
![]() |
457367ea7b | ||
![]() |
8feff5bc76 | ||
![]() |
a6dcbb1f1c | ||
![]() |
d4f02b5e67 | ||
![]() |
645377e191 | ||
![]() |
5a03c88ee3 | ||
![]() |
abc30ba573 | ||
![]() |
f36b1fc5eb | ||
![]() |
feb7775d21 | ||
![]() |
8d50160cd9 | ||
![]() |
871ad10e0e | ||
![]() |
c0664d778c | ||
![]() |
6c483bd6f6 | ||
![]() |
7f8a6f24f9 | ||
![]() |
07fa8010e4 | ||
![]() |
e024b99b36 | ||
![]() |
ed65ad72d0 | ||
![]() |
bc0eaa5d15 | ||
![]() |
e0827634bb | ||
![]() |
08ba646200 | ||
![]() |
caf0a8b5d1 | ||
![]() |
357df5c8ec | ||
![]() |
d0630d5edd | ||
![]() |
c562d0d78b | ||
![]() |
bff30278e1 | ||
![]() |
b104b26f11 | ||
![]() |
03ef44f415 | ||
![]() |
1a06e53c58 | ||
![]() |
c438a388d7 | ||
![]() |
7923c3e0c7 | ||
![]() |
872f16e45a | ||
![]() |
7688c14d43 | ||
![]() |
bde2a45384 | ||
![]() |
7f4ef8d8fd | ||
![]() |
0dab950ebf | ||
![]() |
485482b2be | ||
![]() |
b2ae317877 | ||
![]() |
5b1b1dbcb4 | ||
![]() |
7222390c96 | ||
![]() |
b33f0a08bc | ||
![]() |
140a90f72a | ||
![]() |
f697384028 | ||
![]() |
dfd04c8291 | ||
![]() |
209d6ed2e4 | ||
![]() |
d8fa6061a2 | ||
![]() |
651eed8d7a | ||
![]() |
af1eba1b0e | ||
![]() |
f82f6c2068 | ||
![]() |
fcca453223 | ||
![]() |
7ed5c18a86 | ||
![]() |
c067575ac4 | ||
![]() |
52c96de6a8 | ||
![]() |
907e6d74e0 | ||
![]() |
12cbbd2097 | ||
![]() |
4aa370fbfd | ||
![]() |
3587c3e165 | ||
![]() |
acc4345b65 | ||
![]() |
43def57852 | ||
![]() |
561b47e463 | ||
![]() |
9885534b5b | ||
![]() |
ad3f111e13 | ||
![]() |
452f71b51f | ||
![]() |
a97cb1530d | ||
![]() |
21048b9e65 | ||
![]() |
d73e715997 | ||
![]() |
353a077c6b | ||
![]() |
373a3688c9 | ||
![]() |
208107fd7e | ||
![]() |
e19a8e31ea | ||
![]() |
b55eff95cf | ||
![]() |
b6287a194c | ||
![]() |
888d897a3e | ||
![]() |
e32714c456 | ||
![]() |
e1c40f3e8f | ||
![]() |
d7489358f3 | ||
![]() |
316ba45e3c | ||
![]() |
f0796b51c8 | ||
![]() |
e638d450ed | ||
![]() |
e60eabbeb2 | ||
![]() |
c249bef27d | ||
![]() |
4e69e5a3d2 | ||
![]() |
49c89a3b88 | ||
![]() |
7507223c8b | ||
![]() |
681b7db727 | ||
![]() |
4826bddb5b | ||
![]() |
49436e5740 | ||
![]() |
202204a82a | ||
![]() |
34c6b17215 | ||
![]() |
6fe7f5ce98 | ||
![]() |
d9f86a96f0 | ||
![]() |
da1511a092 | ||
![]() |
8bd7ccfa9f | ||
![]() |
0806df11d2 | ||
![]() |
40b1549b3b | ||
![]() |
c9a5bf6f83 | ||
![]() |
8496a86043 | ||
![]() |
bc388e59da | ||
![]() |
09748275db | ||
![]() |
eec0299cbc | ||
![]() |
19ecfdfec5 | ||
![]() |
7ba7b81a5c | ||
![]() |
882cbf2dfb | ||
![]() |
38b98c55cc | ||
![]() |
3a675bf379 | ||
![]() |
985b62705f | ||
![]() |
5aecb7f17b | ||
![]() |
ad69bf7d38 | ||
![]() |
84554ed0a5 | ||
![]() |
36765df3c0 | ||
![]() |
b11ebf9e8f | ||
![]() |
84e2d449b9 | ||
![]() |
3e62a99f82 | ||
![]() |
64dd349e32 | ||
![]() |
1add4c4b0f | ||
![]() |
14b3870efb | ||
![]() |
d2cf12f948 | ||
![]() |
e221ceaa4c | ||
![]() |
beedf13d01 | ||
![]() |
9d18360333 | ||
![]() |
18e5ee0ba2 | ||
![]() |
41e9027d9a | ||
![]() |
8d9dc2b0a3 | ||
![]() |
6a4647af43 | ||
![]() |
5a651e2b8a | ||
![]() |
d9fa5605ac | ||
![]() |
3a8cb581cc | ||
![]() |
b434d26a5d | ||
![]() |
ba30d4f483 | ||
![]() |
b4ffcd594d | ||
![]() |
ca35128503 | ||
![]() |
681f18ee62 | ||
![]() |
e62a38b39f | ||
![]() |
85ac1052dd | ||
![]() |
8024edeadf | ||
![]() |
f9f1d5807a | ||
![]() |
14227475b2 | ||
![]() |
e1a80fb5ce | ||
![]() |
aabe53c934 | ||
![]() |
f3dbb7ed87 | ||
![]() |
52e11bf001 | ||
![]() |
f06e5cdcd6 | ||
![]() |
15eb78bd8f | ||
![]() |
9f362608b7 | ||
![]() |
e21c8f87b4 | ||
![]() |
0a143d1cd3 | ||
![]() |
08935beaf3 | ||
![]() |
c9625b09b0 | ||
![]() |
800c7fb37b | ||
![]() |
179eaefafe | ||
![]() |
28f5a74e98 | ||
![]() |
781d62d3a5 | ||
![]() |
8ed2158709 | ||
![]() |
8f98e16e5e | ||
![]() |
3a595ef912 | ||
![]() |
5aa0bfcea4 | ||
![]() |
04e2256c92 | ||
![]() |
38ba00e55c | ||
![]() |
8931346230 | ||
![]() |
8bdd2deb19 | ||
![]() |
535055eff8 | ||
![]() |
913d2fd20f | ||
![]() |
0c4951d742 | ||
![]() |
9d17b18f26 | ||
![]() |
31b3195c17 | ||
![]() |
0d4e4090a0 | ||
![]() |
b946af42cc | ||
![]() |
22339d10db | ||
![]() |
b3d2350f33 | ||
![]() |
3cae2aed1d | ||
![]() |
c6f262c675 | ||
![]() |
8239206ec5 | ||
![]() |
a2ff672b34 | ||
![]() |
9a0a12d230 | ||
![]() |
7d3c23fc22 | ||
![]() |
63ab117e7d | ||
![]() |
93e7eb3fe5 | ||
![]() |
419c2d72a8 | ||
![]() |
e1c382211a | ||
![]() |
6a7a934e3e | ||
![]() |
1f72afc8f5 | ||
![]() |
2fbc377119 | ||
![]() |
563999f3b8 | ||
![]() |
1ea608babe | ||
![]() |
51355343f1 | ||
![]() |
fe33a6aacb | ||
![]() |
e117f50db0 | ||
![]() |
37120f486f | ||
![]() |
484ff7a98b | ||
![]() |
496f5aff7a | ||
![]() |
b270a198dc | ||
![]() |
9e93d61236 | ||
![]() |
72aedca39c | ||
![]() |
748c18f465 | ||
![]() |
b9875e2844 | ||
![]() |
902f48cd4c | ||
![]() |
1526ac96c1 | ||
![]() |
e339055e0b | ||
![]() |
4890b47460 | ||
![]() |
b53432cf28 | ||
![]() |
a112d97141 | ||
![]() |
83281bff52 | ||
![]() |
05bec3b4a8 | ||
![]() |
cd2fb1ec66 | ||
![]() |
ec33cf2709 | ||
![]() |
c7689f18ec | ||
![]() |
3eb7700912 | ||
![]() |
c4633436ba | ||
![]() |
2870874d91 | ||
![]() |
a147278a7e | ||
![]() |
a2577b983c | ||
![]() |
646563eb3f | ||
![]() |
f9860216c9 | ||
![]() |
b7eb469ac1 | ||
![]() |
bcf573cf26 | ||
![]() |
1bf4170d8f | ||
![]() |
6d632f6aa4 | ||
![]() |
835b5a90af | ||
![]() |
9e743e3147 | ||
![]() |
7adbc11869 | ||
![]() |
2442e9ae20 | ||
![]() |
0dcac05f2f | ||
![]() |
60a497b0a6 | ||
![]() |
11b372f526 | ||
![]() |
3d36ea6199 | ||
![]() |
cebeebdb7a | ||
![]() |
e5ccec0e89 | ||
![]() |
62ca26c36c | ||
![]() |
68fa049d6c | ||
![]() |
88ab00679f | ||
![]() |
86482b0103 | ||
![]() |
f9e0193353 | ||
![]() |
ba492308f4 | ||
![]() |
d4e22c2c2c | ||
![]() |
b95526951f | ||
![]() |
e4be97eb79 | ||
![]() |
59eecab0e8 | ||
![]() |
be159759ea | ||
![]() |
1e41e73af2 | ||
![]() |
78819fd3a8 | ||
![]() |
c6c2bcc023 | ||
![]() |
e759a0c544 | ||
![]() |
b163065b3c | ||
![]() |
ecafb4aad0 | ||
![]() |
38a83e3e56 | ||
![]() |
bacf546dff | ||
![]() |
85a6d85c1f | ||
![]() |
7522a19af5 | ||
![]() |
26a0034176 | ||
![]() |
cb5fbff1e6 | ||
![]() |
ff378abf84 | ||
![]() |
520f9bc0d2 | ||
![]() |
cf3db70d5d | ||
![]() |
7026229273 | ||
![]() |
da8fa77558 | ||
![]() |
9fe8150861 | ||
![]() |
d56e32e2c4 | ||
![]() |
7f871374fa | ||
![]() |
2848e16ea1 | ||
![]() |
916708ce29 | ||
![]() |
cff635fb65 | ||
![]() |
f6600c90e4 | ||
![]() |
3701477f7f | ||
![]() |
d13d080dee | ||
![]() |
61d5e2ad85 | ||
![]() |
023a3edf40 | ||
![]() |
4b577f1f2a | ||
![]() |
ac280a6971 | ||
![]() |
d2f855e3f9 | ||
![]() |
114e3939f6 | ||
![]() |
ee672f5132 | ||
![]() |
aa60cffe85 | ||
![]() |
bb0d100513 | ||
![]() |
70326a5dff | ||
![]() |
cfc67f619a | ||
![]() |
1a02903b99 | ||
![]() |
f274d6beb3 | ||
![]() |
a04fe9d5a5 | ||
![]() |
f54bd484e6 | ||
![]() |
8ed4e6fad8 | ||
![]() |
c9312c0b7a | ||
![]() |
bb2938307c | ||
![]() |
919c3f2b4a | ||
![]() |
e0234d942e | ||
![]() |
df724b5c33 | ||
![]() |
0b812942d4 | ||
![]() |
48933bc32c | ||
![]() |
630c618ae7 | ||
![]() |
03143a9f83 | ||
![]() |
33a929ef93 | ||
![]() |
e608d14a4f | ||
![]() |
e43b1b8d0d | ||
![]() |
c32af523c3 | ||
![]() |
37b73f0e3c | ||
![]() |
13381ffa43 | ||
![]() |
2129c5318b | ||
![]() |
515ee711ce | ||
![]() |
bc8a4c42fa | ||
![]() |
051f483d20 | ||
![]() |
da39b8403b | ||
![]() |
5fa44d5eef | ||
![]() |
dec88db26c | ||
![]() |
9da9012701 | ||
![]() |
f35c2fdb03 | ||
![]() |
bb74d06b18 | ||
![]() |
c21c21dfda | ||
![]() |
ef92b6619e |
@@ -2,7 +2,8 @@ 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
|
||||
cmake_extra_flags: -DUSE_LIBCXX:BOOL=OFF -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DRUN_PERFORMANCE_TESTS:BOOL=ON
|
||||
collect_performance_results: true
|
||||
- name: "clang"
|
||||
build_tag: "LibC++"
|
||||
version: "3.5"
|
||||
@@ -10,21 +11,32 @@ compilers:
|
||||
cmake_extra_flags: -DUSE_LIBCXX:BOOL=ON -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON
|
||||
- name: "clang"
|
||||
build_tag: AddressSanitizer
|
||||
version: "3.5"
|
||||
version: "3.6"
|
||||
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
|
||||
cmake_extra_flags: -DRUN_FUZZY_TESTS:BOOL=TRUE -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"
|
||||
version: "3.6"
|
||||
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
|
||||
build_tag: "NoThreads"
|
||||
cmake_extra_flags: -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DBUILD_TESTING:BOOL=ON -DRUN_PERFORMANCE_TESTS:BOOL=ON -DMULTITHREAD_SUPPORT_ENABLED:BOOL=OFF
|
||||
collect_performance_results: true
|
||||
- name: "gcc"
|
||||
version: "4.8"
|
||||
cmake_extra_flags: -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DBUILD_TESTING:BOOL=ON -DRUN_PERFORMANCE_TESTS:BOOL=ON
|
||||
collect_performance_results: true
|
||||
- name: "gcc"
|
||||
version: "4.6"
|
||||
skip_packaging: true
|
||||
cmake_extra_flags: -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON
|
||||
cmake_extra_flags: -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DRUN_PERFORMANCE_TESTS:BOOL=ON
|
||||
collect_performance_results: true
|
||||
- name: cppcheck
|
||||
compiler_extra_flags: --enable=all -I include --inline-suppr -Umax --suppress="*:cmake*" --suppress="*:unittests/catch.hpp" --force
|
||||
compiler_extra_flags: --enable=all -I include --inline-suppr -Umax --suppress="*:unittests/catch.hpp" --force --suppress="unusedFunction:*"
|
||||
- name: custom_check
|
||||
commands:
|
||||
- ./contrib/check_for_tabs.rb
|
||||
- ./contrib/check_for_todos.rb
|
||||
|
||||
|
@@ -2,8 +2,4 @@ compilers:
|
||||
- name: clang
|
||||
cmake_extra_flags: -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DCOMMIT_SHA=$COMMIT_SHA
|
||||
build_package_generator: TBZ2
|
||||
- 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
|
||||
|
||||
|
@@ -17,4 +17,11 @@ compilers:
|
||||
version: 12
|
||||
architecture: Win64
|
||||
cmake_extra_flags: -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DCOMMIT_SHA=%COMMIT_SHA%
|
||||
- name: Visual Studio
|
||||
version: 14
|
||||
build_type: Debug
|
||||
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
|
||||
|
||||
|
41
.github/CONTRIBUTING.md
vendored
Normal file
41
.github/CONTRIBUTING.md
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
# Contributing to ChaiScript
|
||||
|
||||
Thank you for contributing!
|
||||
|
||||
# Pull Requests
|
||||
|
||||
Please follow the existing style in the code you are patching.
|
||||
|
||||
- two space indent
|
||||
- no tabs EVER
|
||||
- match the existing indentation level
|
||||
|
||||
All ChaiScript commits are run through a large set of builds and analysis on all supported platforms. Those results are posted on the
|
||||
[build dashboard](http://chaiscript.com/ChaiScript-BuildResults/index.html). No PR will be accepted until all tests pass.
|
||||
|
||||
The build system has full integration with GitHub and you will be notified automatically if all tests have passed.
|
||||
|
||||
# Issues
|
||||
|
||||
Please do not post a "chaiscript is too slow", "chaiscript compiles too slowly", or "chaiscript needs more documentation" issue
|
||||
without first reading the following notes.
|
||||
|
||||
## ChaiScript is Too Slow
|
||||
|
||||
We are actively working on constently improving the runtime performance of ChaiScript. With the performance being
|
||||
[monitored with each commit](http://chaiscript.com/ChaiScript-BuildResults/performance.html).
|
||||
|
||||
If you feel you *must* post an issue about performance, please post a complete example that illustrates the exact case you
|
||||
feel should be better optimized.
|
||||
|
||||
Any issue request regarding performance without a complete example of the issue experienced will be closed.
|
||||
|
||||
## ChaiScript Compiles Too Slowly
|
||||
|
||||
This is also something we are actively working on. If you need highly optimized build times, please see [this discussion
|
||||
on the discourse site](http://discourse.chaiscript.com/t/slow-build-times/94).
|
||||
|
||||
## ChaiScript Needs More Documentation
|
||||
|
||||
If you have a question that is not addressed in the [cheatsheet](https://github.com/ChaiScript/ChaiScript/blob/develop/cheatsheet.md)
|
||||
please open an issue so we can get the Cheatsheet updated.
|
10
.github/ISSUE_TEMPLATE.md
vendored
Normal file
10
.github/ISSUE_TEMPLATE.md
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
* Compiler Used:
|
||||
* Operating System:
|
||||
* Architecture (ARM/x86/32bit/64bit/etc):
|
||||
|
||||
|
||||
### Expected Behavior
|
||||
|
||||
### Actual Behavior
|
||||
|
||||
### Minimal Example to Reproduce Behavior
|
8
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
8
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
Issue this pull request references: #
|
||||
|
||||
Changes proposed in this pull request
|
||||
|
||||
-
|
||||
-
|
||||
-
|
||||
|
45
.travis.yml
45
.travis.yml
@@ -2,24 +2,34 @@ language: cpp
|
||||
compiler:
|
||||
- gcc
|
||||
env:
|
||||
- GCC_VER=4.6
|
||||
- GCC_VER=4.8
|
||||
matrix:
|
||||
- GCC_VER="4.6"
|
||||
- GCC_VER="4.8"
|
||||
|
||||
global:
|
||||
- secure: eiaR6pXiiEpyB8+LLQ1NvZdl0Yylru1BLy9lMoHl+IpUNGGQGywmW/2WAn77rFfmR1OPA2qWQLfgPwgK0HxUA9HHlot9tre5QhiN2Lw8NOT8tCZ6tTm2+QntDBjBGJyal/knRvQkn/6qs6GxlXRerz4ArnnuPL1vESt3zwB0YtU=
|
||||
# The next declaration is the encrypted COVERITY_SCAN_TOKEN, created
|
||||
- secure: "LfolGjP8tWm3yAwthfu3yp8Zn40aueFae580UUR34gusG87cyglq2tQDtxdy+63gWEeNfArbv9n5rZv+bDW3ggHyPjuCKKc1PlZAy07lfXUXf1uz+SFhNvNoYTn3mQG3VZ08o116p4Le2p8yqu4bylJ8wckEq7PrTwvSGVQWTWM="
|
||||
|
||||
before_install:
|
||||
- export CXX="g++-$GCC_VER" CC="gcc-$GCC_VER" GCOV="gcov-$GCC_VER"
|
||||
- if [ "$GCC_VER" = "4.8" ]; then export COVERAGE=1 CPPCHECK=1; fi
|
||||
- if [ ${COVERAGE} = 1 ]; then export FUZZY_CMD="-D RUN_FUZZY_TESTS:BOOL=TRUE"; fi
|
||||
- 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
|
||||
- sudo apt-get install -qq g++-$GCC_VER
|
||||
|
||||
script:
|
||||
- cmake -D ENABLE_COVERAGE:BOOL=TRUE -D CMAKE_BUILD_TYPE:STRING=Debug .
|
||||
- make -j2
|
||||
- if [ ${COVERITY_SCAN_BRANCH} != 1 ]; then cmake -D ENABLE_COVERAGE:BOOL=TRUE -D CMAKE_BUILD_TYPE:STRING=Debug $FUZZY_CMD . ; fi
|
||||
- if [ ${COVERITY_SCAN_BRANCH} != 1 ]; then make -j2 ; fi
|
||||
- make test
|
||||
- mkdir gcov
|
||||
- find CMakeFiles/ -name "*.gc*" -exec mv {} gcov/ \;
|
||||
- $GCOV -d -o gcov gcov/*.gcda
|
||||
- coveralls -n -E ".*\.cpp"
|
||||
- if [ ${COVERAGE} = 1 ]; then bash <(curl -s https://raw.githubusercontent.com/codecov/codecov-bash/master/codecov) -x $GCOV -a "-s `pwd`" ; fi
|
||||
|
||||
after_script:
|
||||
- contrib/codeanalysis/runcppcheck.sh
|
||||
- if [ ${CPPCHECK} = 1 ]; then contrib/codeanalysis/runcppcheck.sh ; fi
|
||||
|
||||
|
||||
notifications:
|
||||
email:
|
||||
recipients:
|
||||
@@ -32,8 +42,15 @@ notifications:
|
||||
on_success: change # options: [always|never|change] default: always
|
||||
on_failure: always # options: [always|never|change] default: always
|
||||
on_start: false # default: false
|
||||
env:
|
||||
global:
|
||||
secure: eiaR6pXiiEpyB8+LLQ1NvZdl0Yylru1BLy9lMoHl+IpUNGGQGywmW/2WAn77rFfmR1OPA2qWQLfgPwgK0HxUA9HHlot9tre5QhiN2Lw8NOT8tCZ6tTm2+QntDBjBGJyal/knRvQkn/6qs6GxlXRerz4ArnnuPL1vESt3zwB0YtU=
|
||||
|
||||
addons:
|
||||
coverity_scan:
|
||||
project:
|
||||
name: "ChaiScript/ChaiScript"
|
||||
description: "Build submitted via Travis CI"
|
||||
notification_email: jason@emptycrate.com
|
||||
build_command_prepend: "cmake -D ENABLE_COVERAGE:BOOL=TRUE -D CMAKE_BUILD_TYPE:STRING=Debug . "
|
||||
build_command: "cmake --build . -- -j2"
|
||||
branch_pattern: coverity_scan
|
||||
|
||||
|
||||
|
128
CMakeLists.txt
128
CMakeLists.txt
@@ -18,7 +18,9 @@ option(MULTITHREAD_SUPPORT_ENABLED "Multithreaded Support Enabled" TRUE)
|
||||
|
||||
option(BUILD_MODULES "Build Extra Modules (stl)" TRUE)
|
||||
option(BUILD_SAMPLES "Build Samples Folder" FALSE)
|
||||
option(RUN_FUZZY_TESTS "Run tests generated by AFL" FALSE)
|
||||
option(USE_STD_MAKE_SHARED "Use std::make_shared instead of chaiscript::make_shared" FALSE)
|
||||
option(RUN_PERFORMANCE_TESTS "Run Performance Tests" FALSE)
|
||||
|
||||
mark_as_advanced(USE_STD_MAKE_SHARED)
|
||||
|
||||
@@ -67,6 +69,13 @@ if(CMAKE_COMPILER_IS_GNUCC OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
|
||||
set(LINKER_FLAGS "${LINKER_FLAGS} -flto")
|
||||
endif()
|
||||
|
||||
option(GPROF_OUTPUT "Generate profile data" FALSE)
|
||||
if (GPROF_OUTPUT)
|
||||
add_definitions(-pg)
|
||||
set(LINKER_FLAGS "${LINKER_FLAGS} -pg")
|
||||
endif()
|
||||
|
||||
|
||||
option(PROFILE_GENERATE "Generate profile data" FALSE)
|
||||
if (PROFILE_GENERATE)
|
||||
add_definitions(-fprofile-generate)
|
||||
@@ -93,8 +102,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_VERSION_MAJOR 5)
|
||||
set(CPACK_PACKAGE_VERSION_MINOR 7)
|
||||
set(CPACK_PACKAGE_VERSION_PATCH 0)
|
||||
set(CPACK_PACKAGE_VERSION_MINOR 8)
|
||||
set(CPACK_PACKAGE_VERSION_PATCH 6)
|
||||
|
||||
set(CPACK_PACKAGE_EXECUTABLES "chai;ChaiScript Eval")
|
||||
set(CPACK_PACKAGE_VENDOR "ChaiScript.com")
|
||||
@@ -114,16 +123,12 @@ configure_file(Doxyfile.in ${CMAKE_BINARY_DIR}/Doxyfile)
|
||||
include(CTest)
|
||||
include(CPack)
|
||||
|
||||
include(cmake/CheckCXX11Features.cmake)
|
||||
|
||||
if(NOT MINGW)
|
||||
find_library(READLINE_LIBRARY NAMES readline PATH /usr/lib /usr/local/lib /opt/local/lib)
|
||||
endif()
|
||||
|
||||
if(HAS_CXX11_VARIADIC_TEMPLATES)
|
||||
message(STATUS "Variadic Template support detected")
|
||||
else()
|
||||
message(SEND_ERROR "The selected compiler does not support the C++11 feature Variadic Templates.")
|
||||
if (UNIX AND NOT APPLE)
|
||||
find_program(VALGRIND NAMES valgrind PATH /usr/bin /usr/local/bin)
|
||||
endif()
|
||||
|
||||
enable_testing()
|
||||
@@ -153,11 +158,14 @@ else()
|
||||
endif()
|
||||
|
||||
if(MSVC)
|
||||
add_definitions(/W4)
|
||||
add_definitions(/W4 /w14545 /w34242 /w34254 /w34287 /w44263 /w44265 /w44296 /w44311 /w44826 /we4289 /w14546 /w14547 /w14549 /w14555 /w14619 /w14905 /w14906 /w14928)
|
||||
|
||||
# VS2013 doesn't have magic statics
|
||||
if (MSVC_VERSION STREQUAL "1800")
|
||||
# VS2013 doesn't have magic statics
|
||||
add_definitions(/w44640)
|
||||
else()
|
||||
# enum warnings are too noisy on MSVC2013
|
||||
add_definitions(/w34062)
|
||||
endif()
|
||||
|
||||
add_definitions(/bigobj)
|
||||
@@ -170,10 +178,10 @@ if(MSVC)
|
||||
# how to workaround or fix the error. So I'm disabling it globally.
|
||||
add_definitions(/wd4503)
|
||||
else()
|
||||
add_definitions(-Wall -Wextra -Wshadow -Wnon-virtual-dtor -Wold-style-cast -Wcast-align -Wcast-qual -Wunused -Woverloaded-virtual -pedantic ${CPP11_FLAG})
|
||||
add_definitions(-Wall -Wextra -Wconversion -Wshadow -Wnon-virtual-dtor -Wold-style-cast -Wcast-align -Wcast-qual -Wunused -Woverloaded-virtual -pedantic ${CPP11_FLAG})
|
||||
|
||||
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
|
||||
add_definitions(-Weverything -Wno-c++98-compat -Wno-documentation -Wno-switch-enum -Wno-weak-vtables -Wno-sign-conversion -Wno-missing-prototypes -Wno-padded -Wno-missing-noreturn -Wno-exit-time-destructors)
|
||||
add_definitions(-Weverything -Wno-c++98-compat-pedantic -Wno-c++98-compat -Wno-documentation -Wno-switch-enum -Wno-weak-vtables -Wno-missing-prototypes -Wno-padded -Wno-missing-noreturn -Wno-exit-time-destructors -Wno-documentation-unknown-command)
|
||||
else()
|
||||
add_definitions(-Wnoexcept)
|
||||
endif()
|
||||
@@ -205,7 +213,7 @@ endif()
|
||||
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/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(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 include/chaiscript/utility/json.hpp include/chaiscript/utility/json_wrap.hpp)
|
||||
|
||||
set_source_files_properties(${Chai_INCLUDES} PROPERTIES HEADER_FILE_ONLY TRUE)
|
||||
|
||||
@@ -252,10 +260,14 @@ add_dependencies(chai chaiscript_stdlib-${CHAI_VERSION})
|
||||
if(BUILD_SAMPLES)
|
||||
add_executable(example samples/example.cpp)
|
||||
target_link_libraries(example ${LIBS})
|
||||
add_executable(test_num_exceptions samples/test_num_exceptions.cpp)
|
||||
target_link_libraries(test_num_exceptions ${LIBS})
|
||||
add_executable(memory_leak_test samples/memory_leak_test.cpp)
|
||||
target_link_libraries(memory_leak_test ${LIBS})
|
||||
add_executable(inheritance samples/inheritance.cpp)
|
||||
target_link_libraries(inheritance ${LIBS})
|
||||
add_executable(factory samples/factory.cpp)
|
||||
target_link_libraries(factory ${LIBS})
|
||||
add_executable(fun_call_performance samples/fun_call_performance.cpp)
|
||||
target_link_libraries(fun_call_performance ${LIBS})
|
||||
endif()
|
||||
@@ -269,9 +281,54 @@ if(BUILD_MODULES)
|
||||
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)
|
||||
|
||||
list(SORT UNIT_TESTS)
|
||||
|
||||
file(GLOB PERFORMANCE_TESTS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/performance_tests/ ${CMAKE_CURRENT_SOURCE_DIR}/performance_tests/*.chai)
|
||||
list(SORT PERFORMANCE_TESTS)
|
||||
|
||||
|
||||
if (RUN_FUZZY_TESTS)
|
||||
|
||||
file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/unittests")
|
||||
|
||||
execute_process(
|
||||
COMMAND ${CMAKE_COMMAND} -E tar xjf ${CMAKE_CURRENT_SOURCE_DIR}/unittests/fuzzy_tests-2015-07-16.tar.bz2
|
||||
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/unittests
|
||||
)
|
||||
|
||||
|
||||
file(GLOB FUZZY_CRASH_TESTS RELATIVE ${CMAKE_BINARY_DIR}/unittests/ ${CMAKE_BINARY_DIR}/unittests/fuzzy_tests/crashes/id*)
|
||||
list(SORT FUZZY_CRASH_TESTS)
|
||||
|
||||
file(GLOB FUZZY_EXCEPTION_TESTS RELATIVE ${CMAKE_BINARY_DIR}/unittests/ ${CMAKE_BINARY_DIR}/unittests/fuzzy_tests/exceptions/id*)
|
||||
list(SORT FUZZY_EXCEPTION_TESTS)
|
||||
|
||||
|
||||
foreach(filename ${FUZZY_CRASH_TESTS})
|
||||
message(STATUS "Adding test ${filename}")
|
||||
add_test(${filename} chai "-e" ${CMAKE_BINARY_DIR}/unittests/fuzzy_tests/crashes/unit_test.inc ${CMAKE_BINARY_DIR}/unittests/${filename})
|
||||
endforeach()
|
||||
|
||||
set_property(TEST ${FUZZY_CRASH_TESTS}
|
||||
PROPERTY ENVIRONMENT
|
||||
"CHAI_USE_PATH=${CMAKE_BINARY_DIR}/unittests/"
|
||||
"CHAI_MODULE_PATH=${CMAKE_CURRENT_BINARY_DIR}/"
|
||||
)
|
||||
|
||||
foreach(filename ${FUZZY_EXCEPTION_TESTS})
|
||||
message(STATUS "Adding test ${filename}")
|
||||
add_test(${filename} chai "--exception" ${CMAKE_BINARY_DIR}/unittests/fuzzy_tests/exceptions/unit_test.inc ${CMAKE_BINARY_DIR}/unittests/${filename})
|
||||
endforeach()
|
||||
|
||||
set_property(TEST ${FUZZY_EXCEPTION_TESTS}
|
||||
PROPERTY ENVIRONMENT
|
||||
"CHAI_USE_PATH=${CMAKE_CURRENT_SOURCE_DIR}/unittests/"
|
||||
"CHAI_MODULE_PATH=${CMAKE_CURRENT_BINARY_DIR}/"
|
||||
)
|
||||
|
||||
endif()
|
||||
|
||||
|
||||
if(BUILD_TESTING)
|
||||
|
||||
# Add catch tests macro
|
||||
@@ -293,8 +350,8 @@ if(BUILD_TESTING)
|
||||
string(REGEX MATCHALL "TEST_CASE\\([ ]*\"[^\"]+\"" found_tests ${contents})
|
||||
foreach(hit ${found_tests})
|
||||
string(REGEX REPLACE "TEST_CASE\\([ ]*(\"[^\"]+\").*" "\\1" test_name ${hit})
|
||||
add_test(${test_name} "${executable}" ${test_name})
|
||||
set_tests_properties(${test_name} PROPERTIES TIMEOUT 660 ENVIRONMENT "PATH=${NEWPATH}")
|
||||
add_test(compiled.${test_name} "${executable}" ${test_name})
|
||||
set_tests_properties(compiled.${test_name} PROPERTIES TIMEOUT 660 ENVIRONMENT "PATH=${NEWPATH}")
|
||||
endforeach()
|
||||
endif()
|
||||
endif()
|
||||
@@ -314,13 +371,46 @@ if(BUILD_TESTING)
|
||||
"CHAI_MODULE_PATH=${CMAKE_CURRENT_BINARY_DIR}/"
|
||||
)
|
||||
|
||||
add_test(version_check_2 chai --version )
|
||||
set_property(TEST version_check_2
|
||||
PROPERTY ENVIRONMENT
|
||||
"CHAI_MODULE_PATH=${CMAKE_CURRENT_BINARY_DIR}/"
|
||||
PROPERTY PASS_REGULAR_EXPRESSION "${CHAI_VERSION}"
|
||||
)
|
||||
|
||||
add_test(help chai --help )
|
||||
set_property(TEST help
|
||||
PROPERTY ENVIRONMENT
|
||||
"CHAI_MODULE_PATH=${CMAKE_CURRENT_BINARY_DIR}/"
|
||||
)
|
||||
|
||||
|
||||
set(TESTS "")
|
||||
|
||||
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})
|
||||
message(STATUS "Adding unit test ${filename}")
|
||||
add_test(unit.${filename} chai ${CMAKE_CURRENT_SOURCE_DIR}/unittests/unit_test.inc ${CMAKE_CURRENT_SOURCE_DIR}/unittests/${filename})
|
||||
list(APPEND TESTS unit.${filename})
|
||||
endforeach()
|
||||
|
||||
set_property(TEST ${UNIT_TESTS}
|
||||
if (RUN_PERFORMANCE_TESTS)
|
||||
foreach(filename ${PERFORMANCE_TESTS})
|
||||
message(STATUS "Adding performance test ${filename}")
|
||||
|
||||
add_test(NAME performance.${filename} COMMAND ${VALGRIND} --tool=callgrind --callgrind-out-file=callgrind.performance.${filename} $<TARGET_FILE:chai> ${CMAKE_CURRENT_SOURCE_DIR}/performance_tests/${filename})
|
||||
list(APPEND TESTS performance.${filename})
|
||||
endforeach()
|
||||
|
||||
add_executable(profile_cpp_calls_2 performance_tests/profile_cpp_calls_2.cpp)
|
||||
target_link_libraries(profile_cpp_calls_2 ${LIBS})
|
||||
add_test(NAME performance.profile_cpp_calls_2 COMMAND ${VALGRIND} --tool=callgrind --callgrind-out-file=callgrind.performance.profile_cpp_calls_2 $<TARGET_FILE:profile_cpp_calls_2>)
|
||||
|
||||
add_executable(profile_fun_wrappers performance_tests/profile_fun_wrappers.cpp)
|
||||
target_link_libraries(profile_fun_wrappers ${LIBS})
|
||||
add_test(NAME performance.profile_fun_wrappers COMMAND ${VALGRIND} --tool=callgrind --callgrind-out-file=callgrind.performance.profile_fun_wrappers $<TARGET_FILE:profile_fun_wrappers>)
|
||||
endif()
|
||||
|
||||
set_property(TEST ${TESTS}
|
||||
PROPERTY ENVIRONMENT
|
||||
"CHAI_USE_PATH=${CMAKE_CURRENT_SOURCE_DIR}/unittests/"
|
||||
"CHAI_MODULE_PATH=${CMAKE_CURRENT_BINARY_DIR}/"
|
||||
|
2
LICENSE
2
LICENSE
@@ -1,4 +1,4 @@
|
||||
Copyright 2009-2015 Jason Turner
|
||||
Copyright 2009-2016 Jason Turner
|
||||
Copyright 2009-2012 Jonathan Turner.
|
||||
|
||||
All Rights Reserved.
|
||||
|
16
appveyor.yml
Normal file
16
appveyor.yml
Normal file
@@ -0,0 +1,16 @@
|
||||
version: 5.7.2.{build}
|
||||
os: Visual Studio 2015
|
||||
environment:
|
||||
matrix:
|
||||
- {}
|
||||
build_script:
|
||||
- cmd: >-
|
||||
mkdir build
|
||||
|
||||
cd build
|
||||
|
||||
cmake c:\Projects\chaiscript -G "Visual Studio 14"
|
||||
|
||||
cmake --build . --config Debug
|
||||
test_script:
|
||||
- cmd: ctest -C Debug
|
147
cheatsheet.md
147
cheatsheet.md
@@ -1,3 +1,13 @@
|
||||
# ChaiScript Versioning
|
||||
|
||||
ChaiScript tries to follow the [Semantic Versioning](http://semver.org/) scheme. This basically means:
|
||||
|
||||
* Major Version Number: API changes / breaking changes
|
||||
* Minor Version Number: New Features
|
||||
* Patch Version Number: Minor changes / enhancements
|
||||
|
||||
|
||||
|
||||
# Initializing ChaiScript
|
||||
|
||||
```
|
||||
@@ -30,6 +40,19 @@ chai.add(chaiscript::fun<ReturnType (ParamType1, ParamType2)>(&function_with_ove
|
||||
```
|
||||
chai.add(chaiscript::fun(std::static_cast<ReturnType (*)(ParamType1, ParamType2)>(&function_with_overloads)), "function_name");
|
||||
```
|
||||
This overload technique is also used when exposing base member using derived type
|
||||
|
||||
```
|
||||
struct Base
|
||||
{
|
||||
int data;
|
||||
};
|
||||
|
||||
struct Derived : public Base
|
||||
{};
|
||||
|
||||
chai.add(chaiscript::fun(static_cast<int(Derived::*)>(&Derived::data)), "data");
|
||||
```
|
||||
|
||||
### Lambda
|
||||
|
||||
@@ -54,9 +77,56 @@ chai.add(chaiscript::constructor<MyType (const MyType &)>(), "MyType");
|
||||
It's not strictly necessary to add types, but it helps with many things. Cloning, better errors, etc.
|
||||
|
||||
```
|
||||
chai.add(chaiscript::user_type<MyClass>, "MyClass");
|
||||
chai.add(chaiscript::user_type<MyClass>(), "MyClass");
|
||||
```
|
||||
|
||||
## Adding Type Conversions
|
||||
|
||||
User defined type conversions are possible, defined in either script or in C++.
|
||||
|
||||
|
||||
### ChaiScript Defined Conversions
|
||||
|
||||
Function objects (including lambdas) can be used to add type conversions
|
||||
from inside of ChaiScript:
|
||||
|
||||
```
|
||||
add_type_conversion(type("string"), type("Type_Info"), fun(s) { return type(s); });
|
||||
```
|
||||
|
||||
### C++ Defined Conversions
|
||||
|
||||
Invoking a C++ type conversion possible with `static_cast`
|
||||
|
||||
```
|
||||
chai.add(chaiscript::type_conversion<T, bool>());
|
||||
```
|
||||
|
||||
Calling a user defined type conversion that takes a lambda
|
||||
|
||||
```
|
||||
chai.add(chaiscript::type_conversion<TestBaseType, Type2>([](const TestBaseType &t_bt) { /* return converted thing */ }));
|
||||
```
|
||||
|
||||
|
||||
### Helpers
|
||||
|
||||
A helper function exists for strongly typed and ChaiScript `Vector` function conversion definition:
|
||||
|
||||
```
|
||||
chai.add(chaiscript::vector_conversion<std::vector<int>>());
|
||||
```
|
||||
|
||||
A helper function also exists for strongly typed and ChaiScript `Map` function conversion definition:
|
||||
|
||||
```
|
||||
chai.add(chaiscript::map_conversion<std::map<std::string, int>>());
|
||||
```
|
||||
|
||||
|
||||
|
||||
This allows you to pass a ChaiScript function to a function requiring `std::vector<int>`
|
||||
|
||||
## Adding Objects
|
||||
|
||||
```
|
||||
@@ -65,8 +135,25 @@ chai.add(chaiscript::var(std::ref(somevar), "somevar"); // by reference, shared
|
||||
auto shareddouble = std::make_shared<double>(4.3);
|
||||
chai.add(chaiscript::var(shareddouble), "shareddouble"); // by shared_ptr, shared between c++ and chai
|
||||
chai.add(chaiscript::const_var(somevar), "somevar"); // copied in and made const
|
||||
chai.add_global_const(chaiscript::const_var(somevar), "somevar"); // global const. Throws if value is non-const
|
||||
chai.add_global(chaiscript::var(somevar), "somevar"); // global non-const
|
||||
chai.add_global_const(chaiscript::const_var(somevar), "somevar"); // global const. Throws if value is non-const, throws if object exists
|
||||
chai.add_global(chaiscript::var(somevar), "somevar"); // global non-const, throws if object exists
|
||||
chai.set_global(chaiscript::var(somevar), "somevar"); // global non-const, overwrites existing object
|
||||
```
|
||||
# Using STL
|
||||
ChaiScript recognize many types from STL, but you have to add specific instantiation yourself.
|
||||
|
||||
```
|
||||
typedef std::vector<std::pair<int, std::string>> data_list;
|
||||
data_list my_list{ make_pair(0, "Hello"), make_pair(1, "World") };
|
||||
chai.add(chaiscript::bootstrap::standard_library::vector_type<data_list>("DataList"));
|
||||
chai.add(chaiscript::bootstrap::standard_library::pair_type<data_list::value_type>("DataElement"));
|
||||
chai.add(chaiscript::var(&my_list), "data_list");
|
||||
chai.eval(R"_(
|
||||
for(var i=0; i<data_list.size(); ++i)
|
||||
{
|
||||
print(to_string(data_list[i].first) + " " + data_list[i].second)
|
||||
}
|
||||
)_");
|
||||
```
|
||||
|
||||
# Executing Script
|
||||
@@ -80,6 +167,8 @@ chai.eval(R"(print("Hello World"))");
|
||||
|
||||
## Unboxing Return Values
|
||||
|
||||
Returns values are of the type `Boxed_Value` which is meant to be opaque to the programmer. Use one of the unboxing methods to access the internal data.
|
||||
|
||||
### Prefered
|
||||
|
||||
```
|
||||
@@ -102,6 +191,28 @@ chaiscript::Boxed_Number(chai.eval("5.3 + 2.1")).get_as<int>(); // works with an
|
||||
static_cast<int>(chai.eval<double>("5.3+2.1")); // this version only works if we know that it's a double
|
||||
```
|
||||
|
||||
### Conversion Caveats
|
||||
|
||||
Conversion to `std::shared_ptr<T> &` is supported for function calls, but if you attempt to keep a reference to a `shared_ptr<>` you might invoke undefined behavior
|
||||
|
||||
```cpp
|
||||
// ok this is supported, you can register it with chaiscript engine
|
||||
void nullify_shared_ptr(std::shared_ptr<int> &t) {
|
||||
t == nullptr
|
||||
}
|
||||
```
|
||||
|
||||
```cpp
|
||||
int main()
|
||||
{
|
||||
// do some stuff and create a chaiscript instance
|
||||
std::shared_ptr<int> &ptr = chai.eval<std::shared_ptr<int> &>(somevalue);
|
||||
// DO NOT do this. Taking a non-const reference to a shared_ptr is not
|
||||
// supported and causes undefined behavior in the chaiscript engine
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## Sharing Values
|
||||
|
||||
```
|
||||
@@ -152,7 +263,7 @@ p(5, 6); // calls chaiscript's '+' function, returning 11
|
||||
```
|
||||
|
||||
```
|
||||
auto p = chai.eval<std::function<std::string (int, double)>>(fun(x,y) { to_string(x) + to_string(y); });
|
||||
auto p = chai.eval<std::function<std::string (int, double)>>("fun(x,y) { to_string(x) + to_string(y); }");
|
||||
p(3,4.2); // evaluates the lambda function, returning the string "34.2" to C++
|
||||
```
|
||||
|
||||
@@ -168,11 +279,13 @@ var k = 5; // initialized to 5 (integer)
|
||||
var l := k; // reference to k
|
||||
auto &m = k; // reference to k
|
||||
|
||||
GLOBAL g = 5; // creates a global variable. If global already exists, it is not re-added
|
||||
GLOBAL g = 2; // global 'g' now equals 2
|
||||
global g = 5; // creates a global variable. If global already exists, it is not re-added
|
||||
global g = 2; // global 'g' now equals 2
|
||||
|
||||
GLOBAL g2;
|
||||
if (g2.is_var_undef()) { g2 = 4; } // only initialize g2 once, if GLOBAL decl hit more than once
|
||||
global g2;
|
||||
if (g2.is_var_undef()) { g2 = 4; } // only initialize g2 once, if global decl hit more than once
|
||||
|
||||
GLOBAL g3; // all upper case version also accepted
|
||||
```
|
||||
|
||||
## Built in Types
|
||||
@@ -183,7 +296,7 @@ var m = ["a":1, "b":2]; // map of string:value pairs
|
||||
```
|
||||
|
||||
Floating point values default to `double` type and integers default to `int` type. All C++ suffixes
|
||||
such as `f`, `ll`, `u` as well as scientific notion is supported
|
||||
such as `f`, `ll`, `u` as well as scientific notation are supported
|
||||
|
||||
```
|
||||
1.0 // double
|
||||
@@ -201,6 +314,9 @@ on your platform.
|
||||
|
||||
## Functions
|
||||
|
||||
Note that any type of ChaiScript function can be passed freely to C++ and automatically
|
||||
converted into an `std::function` object.
|
||||
|
||||
### General
|
||||
|
||||
```
|
||||
@@ -298,6 +414,19 @@ o.f = fun(y) { print(this.x + y); }
|
||||
o.f(10); // prints 13
|
||||
```
|
||||
|
||||
### Option Explicit
|
||||
|
||||
If you want to disable dynamic parameter definitions, you can `set_explicit`.
|
||||
|
||||
```
|
||||
class My_Class {
|
||||
def My_Class() {
|
||||
this.set_explicit(true);
|
||||
this.x = 2; // this would fail with explicit set to true
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
## method_missing
|
||||
|
||||
A function of the signature `method_missing(object, name, param1, param2, param3)` will be called if an appropriate
|
||||
|
@@ -1,103 +0,0 @@
|
||||
# Checks for C++11 features
|
||||
# CXX11_FEATURE_LIST - a list containing all supported features
|
||||
# HAS_CXX11_AUTO - auto keyword
|
||||
# HAS_CXX11_NULLPTR - nullptr
|
||||
# HAS_CXX11_LAMBDA - lambdas
|
||||
# HAS_CXX11_STATIC_ASSERT - static_assert()
|
||||
# HAS_CXX11_RVALUE_REFERENCES - rvalue references
|
||||
# HAS_CXX11_DECLTYPE - decltype keyword
|
||||
# HAS_CXX11_CSTDINT_H - cstdint header
|
||||
# HAS_CXX11_LONG_LONG - long long signed & unsigned types
|
||||
# HAS_CXX11_VARIADIC_TEMPLATES - variadic templates
|
||||
# HAS_CXX11_CONSTEXPR - constexpr keyword
|
||||
# HAS_CXX11_SIZEOF_MEMBER - sizeof() non-static members
|
||||
# HAS_CXX11_FUNC - __func__ preprocessor constant
|
||||
#
|
||||
# Original script by Rolf Eike Beer
|
||||
# Modifications by Andreas Weis
|
||||
#
|
||||
CMAKE_MINIMUM_REQUIRED(VERSION 2.8.3)
|
||||
|
||||
SET(CHECK_CXX11_OLD_CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS})
|
||||
IF(CMAKE_COMPILER_IS_GNUCXX)
|
||||
SET(CMAKE_CXX_FLAGS "-std=c++0x")
|
||||
endif()
|
||||
|
||||
MACRO(CXX11_CHECK_FEATURE FEATURE_NAME FEATURE_NUMBER RESULT_VAR)
|
||||
IF (NOT DEFINED ${RESULT_VAR})
|
||||
SET(_bindir "${CMAKE_CURRENT_BINARY_DIR}/cxx11/cxx11_${FEATURE_NAME}")
|
||||
|
||||
IF (${FEATURE_NUMBER})
|
||||
SET(_SRCFILE_BASE ${CMAKE_CURRENT_LIST_DIR}/c++11-test-${FEATURE_NAME}-N${FEATURE_NUMBER})
|
||||
SET(_LOG_NAME "\"${FEATURE_NAME}\" (N${FEATURE_NUMBER})")
|
||||
ELSE (${FEATURE_NUMBER})
|
||||
SET(_SRCFILE_BASE ${CMAKE_CURRENT_LIST_DIR}/c++11-test-${FEATURE_NAME})
|
||||
SET(_LOG_NAME "\"${FEATURE_NAME}\"")
|
||||
ENDIF (${FEATURE_NUMBER})
|
||||
MESSAGE(STATUS "Checking C++11 support for ${_LOG_NAME}")
|
||||
|
||||
SET(_SRCFILE "${_SRCFILE_BASE}.cpp")
|
||||
SET(_SRCFILE_FAIL "${_SRCFILE_BASE}_fail.cpp")
|
||||
SET(_SRCFILE_FAIL_COMPILE "${_SRCFILE_BASE}_fail_compile.cpp")
|
||||
|
||||
IF (CROSS_COMPILING)
|
||||
try_compile(${RESULT_VAR} "${_bindir}" "${_SRCFILE}")
|
||||
IF (${RESULT_VAR} AND EXISTS ${_SRCFILE_FAIL})
|
||||
try_compile(${RESULT_VAR} "${_bindir}_fail" "${_SRCFILE_FAIL}")
|
||||
ENDIF (${RESULT_VAR} AND EXISTS ${_SRCFILE_FAIL})
|
||||
ELSE (CROSS_COMPILING)
|
||||
try_run(_RUN_RESULT_VAR _COMPILE_RESULT_VAR
|
||||
"${_bindir}" "${_SRCFILE}")
|
||||
IF (_COMPILE_RESULT_VAR AND NOT _RUN_RESULT_VAR)
|
||||
SET(${RESULT_VAR} TRUE)
|
||||
ELSE (_COMPILE_RESULT_VAR AND NOT _RUN_RESULT_VAR)
|
||||
SET(${RESULT_VAR} FALSE)
|
||||
ENDIF (_COMPILE_RESULT_VAR AND NOT _RUN_RESULT_VAR)
|
||||
IF (${RESULT_VAR} AND EXISTS ${_SRCFILE_FAIL})
|
||||
try_run(_RUN_RESULT_VAR _COMPILE_RESULT_VAR
|
||||
"${_bindir}_fail" "${_SRCFILE_FAIL}")
|
||||
IF (_COMPILE_RESULT_VAR AND _RUN_RESULT_VAR)
|
||||
SET(${RESULT_VAR} TRUE)
|
||||
ELSE (_COMPILE_RESULT_VAR AND _RUN_RESULT_VAR)
|
||||
SET(${RESULT_VAR} FALSE)
|
||||
ENDIF (_COMPILE_RESULT_VAR AND _RUN_RESULT_VAR)
|
||||
ENDIF (${RESULT_VAR} AND EXISTS ${_SRCFILE_FAIL})
|
||||
ENDIF (CROSS_COMPILING)
|
||||
IF (${RESULT_VAR} AND EXISTS ${_SRCFILE_FAIL_COMPILE})
|
||||
try_compile(_TMP_RESULT "${_bindir}_fail_compile" "${_SRCFILE_FAIL_COMPILE}")
|
||||
IF (_TMP_RESULT)
|
||||
SET(${RESULT_VAR} FALSE)
|
||||
ELSE (_TMP_RESULT)
|
||||
SET(${RESULT_VAR} TRUE)
|
||||
ENDIF (_TMP_RESULT)
|
||||
ENDIF (${RESULT_VAR} AND EXISTS ${_SRCFILE_FAIL_COMPILE})
|
||||
|
||||
IF (${RESULT_VAR})
|
||||
MESSAGE(STATUS "Checking C++11 support for ${_LOG_NAME} -- works")
|
||||
LIST(APPEND CXX11_FEATURE_LIST ${RESULT_VAR})
|
||||
ELSE (${RESULT_VAR})
|
||||
MESSAGE(STATUS "Checking C++11 support for ${_LOG_NAME} -- not supported")
|
||||
ENDIF (${RESULT_VAR})
|
||||
SET(${RESULT_VAR} ${${RESULT_VAR}} CACHE INTERNAL "C++11 support for ${_LOG_NAME}")
|
||||
ENDIF (NOT DEFINED ${RESULT_VAR})
|
||||
ENDMACRO(CXX11_CHECK_FEATURE)
|
||||
|
||||
CXX11_CHECK_FEATURE("auto" 2546 HAS_CXX11_AUTO)
|
||||
CXX11_CHECK_FEATURE("nullptr" 2431 HAS_CXX11_NULLPTR)
|
||||
CXX11_CHECK_FEATURE("lambda" 2927 HAS_CXX11_LAMBDA)
|
||||
CXX11_CHECK_FEATURE("static_assert" 1720 HAS_CXX11_STATIC_ASSERT)
|
||||
CXX11_CHECK_FEATURE("rvalue_references" 2118 HAS_CXX11_RVALUE_REFERENCES)
|
||||
CXX11_CHECK_FEATURE("decltype" 2343 HAS_CXX11_DECLTYPE)
|
||||
CXX11_CHECK_FEATURE("cstdint" "" HAS_CXX11_CSTDINT_H)
|
||||
CXX11_CHECK_FEATURE("long_long" 1811 HAS_CXX11_LONG_LONG)
|
||||
CXX11_CHECK_FEATURE("variadic_templates" 2555 HAS_CXX11_VARIADIC_TEMPLATES)
|
||||
CXX11_CHECK_FEATURE("constexpr" 2235 HAS_CXX11_CONSTEXPR)
|
||||
CXX11_CHECK_FEATURE("sizeof_member" 2253 HAS_CXX11_SIZEOF_MEMBER)
|
||||
CXX11_CHECK_FEATURE("__func__" 2340 HAS_CXX11_FUNC)
|
||||
|
||||
SET(CXX11_FEATURE_LIST ${CXX11_FEATURE_LIST} CACHE STRING "C++11 feature support list")
|
||||
MARK_AS_ADVANCED(FORCE CXX11_FEATURE_LIST)
|
||||
|
||||
SET(CMAKE_CXX_FLAGS ${CHECK_CXX11_OLD_CMAKE_CXX_FLAGS})
|
||||
UNSET(CHECK_CXX11_OLD_CMAKE_CXX_FLAGS)
|
||||
|
@@ -1,8 +0,0 @@
|
||||
#include <cstring>
|
||||
|
||||
int main()
|
||||
{
|
||||
if (!__func__) { return 1; }
|
||||
if(std::strlen(__func__) <= 0) { return 1; }
|
||||
return 0;
|
||||
}
|
@@ -1,12 +0,0 @@
|
||||
|
||||
int main()
|
||||
{
|
||||
auto i = 5;
|
||||
auto f = 3.14159f;
|
||||
auto d = 3.14159;
|
||||
bool ret = (
|
||||
(sizeof(f) < sizeof(d)) &&
|
||||
(sizeof(i) == sizeof(int))
|
||||
);
|
||||
return ret ? 0 : 1;
|
||||
}
|
@@ -1,19 +0,0 @@
|
||||
constexpr int square(int x)
|
||||
{
|
||||
return x*x;
|
||||
}
|
||||
|
||||
constexpr int the_answer()
|
||||
{
|
||||
return 42;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
int test_arr[square(3)];
|
||||
bool ret = (
|
||||
(square(the_answer()) == 1764) &&
|
||||
(sizeof(test_arr)/sizeof(test_arr[0]) == 9)
|
||||
);
|
||||
return ret ? 0 : 1;
|
||||
}
|
@@ -1,10 +0,0 @@
|
||||
#include <cstdint>
|
||||
int main()
|
||||
{
|
||||
bool test =
|
||||
(sizeof(int8_t) == 1) &&
|
||||
(sizeof(int16_t) == 2) &&
|
||||
(sizeof(int32_t) == 4) &&
|
||||
(sizeof(int64_t) == 8);
|
||||
return test ? 0 : 1;
|
||||
}
|
@@ -1,11 +0,0 @@
|
||||
|
||||
bool check_size(int i)
|
||||
{
|
||||
return sizeof(int) == sizeof(decltype(i));
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
bool ret = check_size(42);
|
||||
return ret ? 0 : 1;
|
||||
}
|
@@ -1,5 +0,0 @@
|
||||
int main()
|
||||
{
|
||||
int ret = 0;
|
||||
return ([&ret]() -> int { return ret; })();
|
||||
}
|
@@ -1,7 +0,0 @@
|
||||
int main(void)
|
||||
{
|
||||
long long l;
|
||||
unsigned long long ul;
|
||||
|
||||
return ((sizeof(l) >= 8) && (sizeof(ul) >= 8)) ? 0 : 1;
|
||||
}
|
@@ -1,5 +0,0 @@
|
||||
int main()
|
||||
{
|
||||
int* test = nullptr;
|
||||
return test ? 1 : 0;
|
||||
}
|
@@ -1,5 +0,0 @@
|
||||
int main()
|
||||
{
|
||||
int i = nullptr;
|
||||
return 1;
|
||||
}
|
@@ -1,15 +0,0 @@
|
||||
int foo(int& lvalue)
|
||||
{
|
||||
return 123;
|
||||
}
|
||||
|
||||
int foo(int&& rvalue)
|
||||
{
|
||||
return 321;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
int i = 42;
|
||||
return ((foo(i) == 123) && (foo(42) == 321)) ? 0 : 1;
|
||||
}
|
@@ -1,14 +0,0 @@
|
||||
struct foo {
|
||||
char bar;
|
||||
int baz;
|
||||
};
|
||||
|
||||
int main(void)
|
||||
{
|
||||
bool ret = (
|
||||
(sizeof(foo::bar) == 1) &&
|
||||
(sizeof(foo::baz) >= sizeof(foo::bar)) &&
|
||||
(sizeof(foo) >= sizeof(foo::bar)+sizeof(foo::baz))
|
||||
);
|
||||
return ret ? 0 : 1;
|
||||
}
|
@@ -1,5 +0,0 @@
|
||||
int main()
|
||||
{
|
||||
static_assert(0 < 1, "your ordering of integers is screwed");
|
||||
return 0;
|
||||
}
|
@@ -1,5 +0,0 @@
|
||||
int main()
|
||||
{
|
||||
static_assert(1 < 0, "this should fail");
|
||||
return 0;
|
||||
}
|
@@ -1,23 +0,0 @@
|
||||
int Accumulate()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
template<typename T, typename... Ts>
|
||||
int Accumulate(T v, Ts... vs)
|
||||
{
|
||||
return v + Accumulate(vs...);
|
||||
}
|
||||
|
||||
template<int... Is>
|
||||
int CountElements()
|
||||
{
|
||||
return sizeof...(Is);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
int acc = Accumulate(1, 2, 3, 4, -5);
|
||||
int count = CountElements<1,2,3,4,5>();
|
||||
return ((acc == 5) && (count == 5)) ? 0 : 1;
|
||||
}
|
11
contrib/check_for_tabs.rb
Executable file
11
contrib/check_for_tabs.rb
Executable file
@@ -0,0 +1,11 @@
|
||||
#!/usr/bin/env ruby
|
||||
|
||||
require 'json'
|
||||
|
||||
`grep -rPIHn '\t' src/* include/* samples/*`.lines { |line|
|
||||
if /(?<filename>.+(hpp|cpp|chai)):(?<linenumber>[0-9]+):(?<restofline>.+)/ =~ line
|
||||
puts(JSON.dump({:line => linenumber, :filename => filename, :tool => "tab_checker", :message => "Source Code Line Contains Tabs", :messagetype => "warning"}))
|
||||
end
|
||||
}
|
||||
|
||||
|
11
contrib/check_for_todos.rb
Executable file
11
contrib/check_for_todos.rb
Executable file
@@ -0,0 +1,11 @@
|
||||
#!/usr/bin/env ruby
|
||||
|
||||
require 'json'
|
||||
|
||||
`grep -rPIHni 'todo' src/* include/* samples/*`.lines { |line|
|
||||
if /(?<filename>.+(hpp|cpp|chai)):(?<linenumber>[0-9]+):(?<restofline>.+)/ =~ line
|
||||
puts(JSON.dump({:line => linenumber, :filename => filename, :tool => "todo_checker", :message => "todo: #{restofline.strip}", :messagetype => "info"}))
|
||||
end
|
||||
}
|
||||
|
||||
|
@@ -1,7 +1,7 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
|
||||
// Copyright 2009-2016, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#ifndef CHAISCRIPT_HPP_
|
||||
|
@@ -1,18 +1,22 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
|
||||
// Copyright 2009-2016, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#ifndef CHAISCRIPT_DEFINES_HPP_
|
||||
#define CHAISCRIPT_DEFINES_HPP_
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define CHAISCRIPT_STRINGIZE(x) "" #x
|
||||
#define CHAISCRIPT_COMPILER_VERSION CHAISCRIPT_STRINGIZE(_MSC_FULL_VER)
|
||||
#define CHAISCRIPT_MSVC _MSC_VER
|
||||
#define CHAISCRIPT_HAS_DECLSPEC
|
||||
#if _MSC_VER <= 1800
|
||||
#define CHAISCRIPT_MSVC_12
|
||||
#endif
|
||||
#else
|
||||
#define CHAISCRIPT_COMPILER_VERSION __VERSION__
|
||||
#endif
|
||||
|
||||
#ifndef CHAISCRIPT_MSVC_12
|
||||
@@ -29,13 +33,39 @@
|
||||
#define CHAISCRIPT_WINDOWS
|
||||
#endif
|
||||
|
||||
#if (defined(__GNUC__) && __GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8) || (defined(__llvm__) && !defined(CHAISCRIPT_LIBCPP))
|
||||
#if defined(_WIN32)
|
||||
#if defined(__llvm__)
|
||||
#define CHAISCRIPT_COMPILER_NAME "clang(windows)"
|
||||
#elif defined(__GNUC__)
|
||||
#define CHAISCRIPT_COMPILER_NAME "gcc(mingw)"
|
||||
#else
|
||||
#define CHAISCRIPT_COMPILER_NAME "msvc"
|
||||
#endif
|
||||
#else
|
||||
#if defined(__llvm__)
|
||||
#define CHAISCRIPT_COMPILER_NAME "clang"
|
||||
#elif defined(__GNUC__)
|
||||
#define CHAISCRIPT_COMPILER_NAME "gcc"
|
||||
#else
|
||||
#define CHAISCRIPT_COMPILER_NAME "unknown"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if (defined(CHAISCRIPT_MSVC) && !defined(CHAISCRIPT_MSVC_12)) || (defined(__GNUC__) && __GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8) || (defined(__llvm__) && !defined(CHAISCRIPT_LIBCPP))
|
||||
/// Currently only g++>=4.8 supports 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__)
|
||||
#if (defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ == 6)
|
||||
#define CHAISCRIPT_GCC_4_6
|
||||
#endif
|
||||
|
||||
#if defined(__llvm__)
|
||||
#define CHAISCRIPT_CLANG
|
||||
#endif
|
||||
|
||||
#if (defined(__GNUC__) && __GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7) || defined(CHAISCRIPT_MSVC) || defined(CHAISCRIPT_CLANG)
|
||||
#define CHAISCRIPT_OVERRIDE override
|
||||
#else
|
||||
#define CHAISCRIPT_OVERRIDE
|
||||
@@ -48,7 +78,7 @@
|
||||
#define CHAISCRIPT_MODULE_EXPORT extern "C"
|
||||
#endif
|
||||
|
||||
#ifdef CHAISCRIPT_MSVC
|
||||
#ifdef CHAISCRIPT_MSVC_12
|
||||
#define CHAISCRIPT_NOEXCEPT throw()
|
||||
#define CHAISCRIPT_CONSTEXPR
|
||||
#else
|
||||
@@ -56,12 +86,24 @@
|
||||
#define CHAISCRIPT_CONSTEXPR constexpr
|
||||
#endif
|
||||
|
||||
#ifdef _DEBUG
|
||||
#define CHAISCRIPT_DEBUG true
|
||||
#else
|
||||
#define CHAISCRIPT_DEBUG false
|
||||
#endif
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <cmath>
|
||||
|
||||
namespace chaiscript {
|
||||
static const int version_major = 5;
|
||||
static const int version_minor = 7;
|
||||
static const int version_patch = 0;
|
||||
static const int version_minor = 8;
|
||||
static const int version_patch = 6;
|
||||
|
||||
static const char *compiler_version = CHAISCRIPT_COMPILER_VERSION;
|
||||
static const char *compiler_name = CHAISCRIPT_COMPILER_NAME;
|
||||
static const bool debug_build = CHAISCRIPT_DEBUG;
|
||||
|
||||
template<typename B, typename D, typename ...Arg>
|
||||
inline std::shared_ptr<B> make_shared(Arg && ... arg)
|
||||
@@ -73,6 +115,78 @@ namespace chaiscript {
|
||||
#endif
|
||||
}
|
||||
|
||||
template<typename Iter, typename Distance>
|
||||
Iter advance_copy(Iter iter, Distance distance) {
|
||||
std::advance(iter, static_cast<typename std::iterator_traits<Iter>::difference_type>(distance));
|
||||
return iter;
|
||||
}
|
||||
|
||||
|
||||
template<typename T>
|
||||
auto parse_num(const char *t_str) -> typename std::enable_if<std::is_integral<T>::value, T>::type
|
||||
{
|
||||
T t = 0;
|
||||
for (char c = *t_str; (c = *t_str); ++t_str) {
|
||||
if (c < '0' || c > '9') {
|
||||
return t;
|
||||
}
|
||||
t *= 10;
|
||||
t += c - '0';
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
|
||||
template<typename T>
|
||||
auto parse_num(const char *t_str) -> typename std::enable_if<!std::is_integral<T>::value, T>::type
|
||||
{
|
||||
T t = 0;
|
||||
T base = 0;
|
||||
T decimal_place = 0;
|
||||
bool exponent = false;
|
||||
bool neg_exponent = false;
|
||||
|
||||
const auto final_value = [](const T val, const T baseval, const bool hasexp, const bool negexp) -> T {
|
||||
if (!hasexp) {
|
||||
return val;
|
||||
} else {
|
||||
return baseval * std::pow(T(10), val*T(negexp?-1:1));
|
||||
}
|
||||
};
|
||||
|
||||
for(; *t_str != '\0'; ++t_str) {
|
||||
char c = *t_str;
|
||||
if (c == '.') {
|
||||
decimal_place = 10;
|
||||
} else if (c == 'e' || c == 'E') {
|
||||
exponent = true;
|
||||
decimal_place = 0;
|
||||
base = t;
|
||||
t = 0;
|
||||
} else if (c == '-' && exponent) {
|
||||
neg_exponent = true;
|
||||
} else if (c == '+' && exponent) {
|
||||
neg_exponent = false;
|
||||
} else if (c < '0' || c > '9') {
|
||||
return final_value(t, base, exponent, neg_exponent);
|
||||
} else if (decimal_place < T(10)) {
|
||||
t *= T(10);
|
||||
t += T(c - '0');
|
||||
} else {
|
||||
t += (T(c - '0') / (T(decimal_place)));
|
||||
decimal_place *= 10;
|
||||
}
|
||||
}
|
||||
|
||||
return final_value(t, base, exponent, neg_exponent);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T parse_num(const std::string &t_str)
|
||||
{
|
||||
return parse_num<T>(t_str.c_str());
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@@ -18,6 +18,8 @@
|
||||
#include "dispatchkit/bootstrap.hpp"
|
||||
#include "dispatchkit/bootstrap_stl.hpp"
|
||||
#include "dispatchkit/boxed_value.hpp"
|
||||
#include "language/chaiscript_prelude.chai"
|
||||
#include "utility/json_wrap.hpp"
|
||||
|
||||
#ifndef CHAISCRIPT_NO_THREADS
|
||||
#include <future>
|
||||
@@ -47,9 +49,13 @@ namespace chaiscript
|
||||
|
||||
#ifndef CHAISCRIPT_NO_THREADS
|
||||
lib->add(standard_library::future_type<std::future<chaiscript::Boxed_Value>>("future"));
|
||||
lib->add(chaiscript::fun<std::future<Boxed_Value> (const std::function<chaiscript::Boxed_Value ()> &)>([](const std::function<chaiscript::Boxed_Value ()> &t_func){ return std::async(std::launch::async, t_func);}), "async");
|
||||
lib->add(chaiscript::fun([](const std::function<chaiscript::Boxed_Value ()> &t_func){ return std::async(std::launch::async, t_func);}), "async");
|
||||
#endif
|
||||
|
||||
lib->add(json_wrap::library());
|
||||
|
||||
lib->eval(ChaiScript_Prelude::chaiscript_prelude() /*, "standard prelude"*/ );
|
||||
|
||||
return lib;
|
||||
}
|
||||
|
||||
|
@@ -1,7 +1,7 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
|
||||
// Copyright 2009-2016, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#ifndef CHAISCRIPT_THREADING_HPP_
|
||||
@@ -14,8 +14,10 @@
|
||||
#include <thread>
|
||||
#include <mutex>
|
||||
#else
|
||||
#ifndef CHAISCRIPT_NO_THREADS_WARNING
|
||||
#pragma message ("ChaiScript is compiling without thread safety.")
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include "chaiscript_defines.hpp"
|
||||
|
||||
@@ -43,14 +45,14 @@ namespace chaiscript
|
||||
class unique_lock : public std::unique_lock<T>
|
||||
{
|
||||
public:
|
||||
unique_lock(T &t) : std::unique_lock<T>(t) {}
|
||||
explicit unique_lock(T &t) : std::unique_lock<T>(t) {}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class shared_lock : public std::unique_lock<T>
|
||||
{
|
||||
public:
|
||||
shared_lock(T &t) : std::unique_lock<T>(t) {}
|
||||
explicit shared_lock(T &t) : std::unique_lock<T>(t) {}
|
||||
void unlock() {}
|
||||
};
|
||||
|
||||
@@ -58,7 +60,7 @@ namespace chaiscript
|
||||
class lock_guard : public std::lock_guard<T>
|
||||
{
|
||||
public:
|
||||
lock_guard(T &t) : std::lock_guard<T>(t) {}
|
||||
explicit lock_guard(T &t) : std::lock_guard<T>(t) {}
|
||||
};
|
||||
|
||||
class shared_mutex : public std::mutex { };
|
||||
@@ -75,7 +77,7 @@ namespace chaiscript
|
||||
{
|
||||
public:
|
||||
|
||||
Thread_Storage(void *t_key)
|
||||
explicit Thread_Storage(void *t_key)
|
||||
: m_key(t_key)
|
||||
{
|
||||
}
|
||||
@@ -127,7 +129,7 @@ namespace chaiscript
|
||||
{
|
||||
public:
|
||||
|
||||
Thread_Storage(void *)
|
||||
explicit Thread_Storage(void *)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -153,17 +155,19 @@ namespace chaiscript
|
||||
|
||||
|
||||
private:
|
||||
/// \todo this leaks thread instances. It needs to be culled from time to time
|
||||
std::shared_ptr<T> get_tls() const
|
||||
{
|
||||
unique_lock<mutex> lock(m_mutex);
|
||||
|
||||
auto itr = m_instances.find(std::this_thread::get_id());
|
||||
const auto id = std::this_thread::get_id();
|
||||
auto itr = m_instances.find(id);
|
||||
|
||||
if (itr != m_instances.end()) { return itr->second; }
|
||||
|
||||
std::shared_ptr<T> new_instance(std::make_shared<T>());
|
||||
|
||||
m_instances.insert(std::make_pair(std::this_thread::get_id(), new_instance));
|
||||
m_instances.insert(std::make_pair(id, new_instance));
|
||||
|
||||
return new_instance;
|
||||
}
|
||||
@@ -179,7 +183,7 @@ namespace chaiscript
|
||||
class unique_lock
|
||||
{
|
||||
public:
|
||||
unique_lock(T &) {}
|
||||
explicit unique_lock(T &) {}
|
||||
void lock() {}
|
||||
void unlock() {}
|
||||
};
|
||||
@@ -188,7 +192,7 @@ namespace chaiscript
|
||||
class shared_lock
|
||||
{
|
||||
public:
|
||||
shared_lock(T &) {}
|
||||
explicit shared_lock(T &) {}
|
||||
void lock() {}
|
||||
void unlock() {}
|
||||
};
|
||||
@@ -197,7 +201,7 @@ namespace chaiscript
|
||||
class lock_guard
|
||||
{
|
||||
public:
|
||||
lock_guard(T &) {}
|
||||
explicit lock_guard(T &) {}
|
||||
};
|
||||
|
||||
class shared_mutex { };
|
||||
@@ -209,7 +213,7 @@ namespace chaiscript
|
||||
class Thread_Storage
|
||||
{
|
||||
public:
|
||||
Thread_Storage(void *)
|
||||
explicit Thread_Storage(void *)
|
||||
{
|
||||
}
|
||||
|
||||
|
@@ -46,7 +46,7 @@ namespace chaiscript {
|
||||
private:
|
||||
struct Data
|
||||
{
|
||||
Data(const std::type_info &t_type)
|
||||
explicit Data(const std::type_info &t_type)
|
||||
: m_type(t_type)
|
||||
{
|
||||
}
|
||||
|
@@ -1,7 +1,7 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
|
||||
// Copyright 2009-2016, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#ifndef CHAISCRIPT_BAD_BOXED_CAST_HPP_
|
||||
@@ -36,11 +36,11 @@ namespace chaiscript
|
||||
}
|
||||
|
||||
bad_boxed_cast(Type_Info t_from, const std::type_info &t_to)
|
||||
: from(std::move(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: " + t_from.name() + " to: " + t_to.name())
|
||||
{
|
||||
}
|
||||
|
||||
bad_boxed_cast(std::string t_what) CHAISCRIPT_NOEXCEPT
|
||||
explicit bad_boxed_cast(std::string t_what) CHAISCRIPT_NOEXCEPT
|
||||
: to(nullptr), m_what(std::move(t_what))
|
||||
{
|
||||
}
|
||||
|
@@ -1,7 +1,7 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
|
||||
// Copyright 2009-2016, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#ifndef CHAISCRIPT_BIND_FIRST_HPP_
|
||||
|
@@ -1,7 +1,7 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
|
||||
// Copyright 2009-2016, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#ifndef CHAISCRIPT_BOOTSTRAP_HPP_
|
||||
@@ -57,7 +57,7 @@ namespace chaiscript
|
||||
typedef typename std::remove_extent<T>::type ReturnType;
|
||||
const auto extent = std::extent<T>::value;
|
||||
m->add(user_type<T>(), type);
|
||||
m->add(fun<ReturnType& (T &, size_t)>(
|
||||
m->add(fun(
|
||||
[extent](T& t, size_t index)->ReturnType &{
|
||||
if (extent > 0 && index >= extent) {
|
||||
throw std::range_error("Array index out of range. Received: " + std::to_string(index) + " expected < " + std::to_string(extent));
|
||||
@@ -68,7 +68,7 @@ namespace chaiscript
|
||||
), "[]"
|
||||
);
|
||||
|
||||
m->add(fun<const ReturnType& (const T &, size_t)>(
|
||||
m->add(fun(
|
||||
[extent](const T &t, size_t index)->const ReturnType &{
|
||||
if (extent > 0 && index >= extent) {
|
||||
throw std::range_error("Array index out of range. Received: " + std::to_string(index) + " expected < " + std::to_string(extent));
|
||||
@@ -79,7 +79,7 @@ namespace chaiscript
|
||||
), "[]"
|
||||
);
|
||||
|
||||
m->add(fun<size_t (const T &)>(
|
||||
m->add(fun(
|
||||
[extent](const T &) {
|
||||
return extent;
|
||||
}), "size");
|
||||
@@ -157,7 +157,12 @@ namespace chaiscript
|
||||
/// Internal function for converting from a string to a value
|
||||
/// uses ostream operator >> to perform the conversion
|
||||
template<typename Input>
|
||||
Input parse_string(const std::string &i)
|
||||
auto parse_string(const std::string &i)
|
||||
-> typename std::enable_if<
|
||||
!std::is_same<Input, wchar_t>::value
|
||||
&& !std::is_same<Input, char16_t>::value
|
||||
&& !std::is_same<Input, char32_t>::value,
|
||||
Input>::type
|
||||
{
|
||||
std::stringstream ss(i);
|
||||
Input t;
|
||||
@@ -165,6 +170,17 @@ namespace chaiscript
|
||||
return t;
|
||||
}
|
||||
|
||||
template<typename Input>
|
||||
auto parse_string(const std::string &)
|
||||
-> typename std::enable_if<
|
||||
std::is_same<Input, wchar_t>::value
|
||||
|| std::is_same<Input, char16_t>::value
|
||||
|| std::is_same<Input, char32_t>::value,
|
||||
Input>::type
|
||||
{
|
||||
throw std::runtime_error("Parsing of wide characters is not yet supported");
|
||||
}
|
||||
|
||||
|
||||
/// Add all common functions for a POD type. All operators, and
|
||||
/// common conversions
|
||||
@@ -175,11 +191,6 @@ namespace chaiscript
|
||||
m->add(constructor<T()>(), name);
|
||||
construct_pod<T>(name, m);
|
||||
|
||||
auto to_s = fun(&to_string<T>);
|
||||
|
||||
if (!m->has_function(to_s, "to_string")) {
|
||||
m->add(to_s, "to_string");
|
||||
}
|
||||
m->add(fun(&parse_string<T>), "to_" + name);
|
||||
return m;
|
||||
}
|
||||
@@ -293,13 +304,17 @@ namespace chaiscript
|
||||
/// the remaining parameters are the args to bind into the result
|
||||
static Boxed_Value bind_function(const std::vector<Boxed_Value> ¶ms)
|
||||
{
|
||||
if (params.size() < 2)
|
||||
{
|
||||
throw exception::arity_error(static_cast<int>(params.size()), 2);
|
||||
if (params.empty()) {
|
||||
throw exception::arity_error(0, 1);
|
||||
}
|
||||
|
||||
Const_Proxy_Function f = boxed_cast<Const_Proxy_Function>(params[0]);
|
||||
|
||||
if (f->get_arity() != -1 && size_t(f->get_arity()) != params.size() - 1)
|
||||
{
|
||||
throw exception::arity_error(static_cast<int>(params.size()), f->get_arity());
|
||||
}
|
||||
|
||||
return Boxed_Value(Const_Proxy_Function(std::make_shared<dispatch::Bound_Function>(std::move(f),
|
||||
std::vector<Boxed_Value>(params.begin() + 1, params.end()))));
|
||||
}
|
||||
@@ -408,6 +423,12 @@ namespace chaiscript
|
||||
m->add(fun(return_boxed_value_vector(&dispatch::Proxy_Function_Base::get_contained_functions)), "get_contained_functions");
|
||||
|
||||
|
||||
m->add(user_type<std::out_of_range>(), "out_of_range");
|
||||
m->add(user_type<std::logic_error>(), "logic_error");
|
||||
m->add(chaiscript::base_class<std::exception, std::logic_error>());
|
||||
m->add(chaiscript::base_class<std::logic_error, std::out_of_range>());
|
||||
m->add(chaiscript::base_class<std::exception, std::out_of_range>());
|
||||
|
||||
m->add(user_type<std::runtime_error>(), "runtime_error");
|
||||
m->add(chaiscript::base_class<std::exception, std::runtime_error>());
|
||||
|
||||
@@ -419,6 +440,8 @@ namespace chaiscript
|
||||
m->add(constructor<dispatch::Dynamic_Object ()>(), "Dynamic_Object");
|
||||
m->add(fun(&dispatch::Dynamic_Object::get_type_name), "get_type_name");
|
||||
m->add(fun(&dispatch::Dynamic_Object::get_attrs), "get_attrs");
|
||||
m->add(fun(&dispatch::Dynamic_Object::set_explicit), "set_explicit");
|
||||
m->add(fun(&dispatch::Dynamic_Object::is_explicit), "is_explicit");
|
||||
|
||||
m->add(fun(static_cast<Boxed_Value & (dispatch::Dynamic_Object::*)(const std::string &)>(&dispatch::Dynamic_Object::get_attr)), "get_attr");
|
||||
m->add(fun(static_cast<const Boxed_Value & (dispatch::Dynamic_Object::*)(const std::string &) const>(&dispatch::Dynamic_Object::get_attr)), "get_attr");
|
||||
@@ -429,7 +452,13 @@ namespace chaiscript
|
||||
m->add(fun(static_cast<Boxed_Value & (dispatch::Dynamic_Object::*)(const std::string &)>(&dispatch::Dynamic_Object::get_attr)), "[]");
|
||||
m->add(fun(static_cast<const Boxed_Value & (dispatch::Dynamic_Object::*)(const std::string &) const>(&dispatch::Dynamic_Object::get_attr)), "[]");
|
||||
|
||||
m->eval("def Dynamic_Object::clone() { auto &new_o = Dynamic_Object(this.get_type_name()); for_each(this.get_attrs(), bind(fun(new_o, x) { new_o.get_attr(x.first) = x.second; }, new_o, _) ); return new_o; }");
|
||||
m->eval(R""(
|
||||
def Dynamic_Object::clone() {
|
||||
auto &new_o = Dynamic_Object(this.get_type_name());
|
||||
for_each(this.get_attrs(), fun[new_o](x) { new_o.get_attr(x.first) = x.second; } );
|
||||
new_o;
|
||||
}
|
||||
)"");
|
||||
|
||||
m->add(fun(&has_guard), "has_guard");
|
||||
m->add(fun(&get_guard), "get_guard");
|
||||
@@ -439,9 +468,12 @@ namespace chaiscript
|
||||
m->add(fun(&Boxed_Value::is_const), "is_var_const");
|
||||
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_return_value), "is_var_return_value");
|
||||
m->add(fun(&Boxed_Value::reset_return_value), "reset_var_return_value");
|
||||
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::clone_attrs), "clone_var_attrs");
|
||||
|
||||
m->add(fun(&Boxed_Value::get_type_info), "get_type_info");
|
||||
m->add(user_type<Type_Info>(), "Type_Info");
|
||||
@@ -464,13 +496,17 @@ namespace chaiscript
|
||||
basic_constructors<bool>("bool", m);
|
||||
operators::assign<bool>(m);
|
||||
operators::equal<bool>(m);
|
||||
operators::not_equal<bool>(m);
|
||||
|
||||
m->add(fun<std::string (const std::string &t_ss)>([](const std::string &s) -> std::string { return s; }), "to_string");
|
||||
m->add(fun([](const std::string &s) -> std::string { return s; }), "to_string");
|
||||
m->add(fun(&Bootstrap::bool_to_string), "to_string");
|
||||
m->add(fun(&unknown_assign), "=");
|
||||
m->add(fun(&throw_exception), "throw");
|
||||
m->add(fun(&what), "what");
|
||||
|
||||
m->add(fun(&to_string<char>), "to_string");
|
||||
m->add(fun(&Boxed_Number::to_string), "to_string");
|
||||
|
||||
bootstrap_pod_type<double>("double", m);
|
||||
bootstrap_pod_type<long double>("long_double", m);
|
||||
bootstrap_pod_type<float>("float", m);
|
||||
@@ -478,8 +514,13 @@ namespace chaiscript
|
||||
bootstrap_pod_type<long>("long", m);
|
||||
bootstrap_pod_type<unsigned int>("unsigned_int", m);
|
||||
bootstrap_pod_type<unsigned long>("unsigned_long", m);
|
||||
bootstrap_pod_type<long long>("long_long", m);
|
||||
bootstrap_pod_type<unsigned long long>("unsigned_long_long", m);
|
||||
bootstrap_pod_type<size_t>("size_t", m);
|
||||
bootstrap_pod_type<char>("char", m);
|
||||
bootstrap_pod_type<wchar_t>("wchar_t", m);
|
||||
bootstrap_pod_type<char16_t>("char16_t", m);
|
||||
bootstrap_pod_type<char32_t>("char32_t", m);
|
||||
bootstrap_pod_type<std::int8_t>("int8_t", m);
|
||||
bootstrap_pod_type<std::int16_t>("int16_t", m);
|
||||
bootstrap_pod_type<std::int32_t>("int32_t", m);
|
||||
@@ -497,13 +538,13 @@ namespace chaiscript
|
||||
m->add(fun(&print), "print_string");
|
||||
m->add(fun(&println), "println_string");
|
||||
|
||||
m->add(chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Dynamic_Proxy_Function>(&bind_function), "bind");
|
||||
m->add(dispatch::make_dynamic_proxy_function(&bind_function), "bind");
|
||||
|
||||
m->add(fun(&shared_ptr_unconst_clone<dispatch::Proxy_Function_Base>), "clone");
|
||||
m->add(fun(&ptr_assign<std::remove_const<dispatch::Proxy_Function_Base>::type>), "=");
|
||||
m->add(fun(&ptr_assign<std::add_const<dispatch::Proxy_Function_Base>::type>), "=");
|
||||
m->add(chaiscript::base_class<dispatch::Proxy_Function_Base, dispatch::Assignable_Proxy_Function>());
|
||||
m->add(fun<void (dispatch::Assignable_Proxy_Function &, const std::shared_ptr<const dispatch::Proxy_Function_Base> &)>(
|
||||
m->add(fun(
|
||||
[](dispatch::Assignable_Proxy_Function &t_lhs, const std::shared_ptr<const dispatch::Proxy_Function_Base> &t_rhs) {
|
||||
t_lhs.assign(t_rhs);
|
||||
}
|
||||
@@ -529,13 +570,14 @@ namespace chaiscript
|
||||
"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"} }
|
||||
{fun(&chaiscript::exception::eval_error::pretty_print), "pretty_print"},
|
||||
{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<const std::shared_ptr<const chaiscript::AST_Node> &>);
|
||||
return retval;
|
||||
})), "call_stack"} }
|
||||
);
|
||||
|
||||
|
||||
@@ -561,7 +603,7 @@ namespace chaiscript
|
||||
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>>);
|
||||
&chaiscript::var<const std::shared_ptr<chaiscript::AST_Node> &>);
|
||||
return retval;
|
||||
})), "children"},
|
||||
{fun(&AST_Node::replace_child), "replace_child"}
|
||||
|
@@ -1,7 +1,7 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
|
||||
// Copyright 2009-2016, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
/// \file
|
||||
@@ -243,18 +243,22 @@ namespace chaiscript
|
||||
template<typename ContainerType>
|
||||
ModulePtr random_access_container_type(const std::string &/*type*/, ModulePtr m = std::make_shared<Module>())
|
||||
{
|
||||
// cppcheck-suppress syntaxError
|
||||
typedef typename ContainerType::reference(ContainerType::*indexoper)(size_t);
|
||||
|
||||
//In the interest of runtime safety for the m, we prefer the at() method for [] access,
|
||||
//to throw an exception in an out of bounds condition.
|
||||
m->add(
|
||||
fun(std::function<typename ContainerType::reference (ContainerType *, int)>
|
||||
(std::mem_fn(static_cast<indexoper>(&ContainerType::at)))), "[]");
|
||||
fun(
|
||||
[](ContainerType &c, int index) -> typename ContainerType::reference {
|
||||
/// \todo we are prefering to keep the key as 'int' to avoid runtime conversions
|
||||
/// during dispatch. reevaluate
|
||||
return c.at(static_cast<typename ContainerType::size_type>(index));
|
||||
}), "[]");
|
||||
|
||||
m->add(
|
||||
fun<typename ContainerType::const_reference (const ContainerType *, int)>(
|
||||
[](const ContainerType *c, int index) -> typename ContainerType::const_reference {
|
||||
return c->at(index);
|
||||
fun(
|
||||
[](const ContainerType &c, int index) -> typename ContainerType::const_reference {
|
||||
/// \todo we are prefering to keep the key as 'int' to avoid runtime conversions
|
||||
/// during dispatch. reevaluate
|
||||
return c.at(static_cast<typename ContainerType::size_type>(index));
|
||||
}), "[]");
|
||||
|
||||
return m;
|
||||
@@ -277,9 +281,9 @@ namespace chaiscript
|
||||
template<typename ContainerType>
|
||||
ModulePtr container_type(const std::string &/*type*/, ModulePtr m = std::make_shared<Module>())
|
||||
{
|
||||
m->add(fun<size_t (const ContainerType *)>([](const ContainerType *a) { return a->size(); } ), "size");
|
||||
m->add(fun<bool (const ContainerType *)>([](const ContainerType *a) { return a->empty(); } ), "empty");
|
||||
m->add(fun<void (ContainerType *)>([](ContainerType *a) { a->clear(); } ), "clear");
|
||||
m->add(fun([](const ContainerType *a) { return a->size(); } ), "size");
|
||||
m->add(fun([](const ContainerType *a) { return a->empty(); } ), "empty");
|
||||
m->add(fun([](ContainerType *a) { a->clear(); } ), "clear");
|
||||
return m;
|
||||
}
|
||||
|
||||
@@ -319,7 +323,7 @@ namespace chaiscript
|
||||
/// Add back insertion sequence concept to the given ContainerType
|
||||
/// http://www.sgi.com/tech/stl/BackInsertionSequence.html
|
||||
template<typename ContainerType>
|
||||
ModulePtr back_insertion_sequence_type(const std::string &/*type*/, ModulePtr m = std::make_shared<Module>())
|
||||
ModulePtr back_insertion_sequence_type(const std::string &type, ModulePtr m = std::make_shared<Module>())
|
||||
{
|
||||
typedef typename ContainerType::reference (ContainerType::*backptr)();
|
||||
|
||||
@@ -328,8 +332,21 @@ namespace chaiscript
|
||||
|
||||
typedef void (ContainerType::*push_back)(const typename ContainerType::value_type &);
|
||||
m->add(fun(static_cast<push_back>(&ContainerType::push_back)),
|
||||
[]()->std::string{
|
||||
if (typeid(typename ContainerType::value_type) == typeid(Boxed_Value)) {
|
||||
[&]()->std::string{
|
||||
if (typeid(typename ContainerType::value_type) == typeid(Boxed_Value)) {
|
||||
m->eval(
|
||||
"# Pushes the second value onto the container while making a clone of the value\n"
|
||||
"def push_back(" + type + " container, x)\n"
|
||||
"{ \n"
|
||||
" if (x.is_var_return_value()) {\n"
|
||||
" x.reset_var_return_value() \n"
|
||||
" container.push_back_ref(x) \n"
|
||||
" } else { \n"
|
||||
" container.push_back_ref(clone(x)); \n"
|
||||
" }\n"
|
||||
"} \n"
|
||||
);
|
||||
|
||||
return "push_back_ref";
|
||||
} else {
|
||||
return "push_back";
|
||||
@@ -345,7 +362,7 @@ namespace chaiscript
|
||||
/// Front insertion sequence
|
||||
/// http://www.sgi.com/tech/stl/FrontInsertionSequence.html
|
||||
template<typename ContainerType>
|
||||
ModulePtr front_insertion_sequence_type(const std::string &, ModulePtr m = std::make_shared<Module>())
|
||||
ModulePtr front_insertion_sequence_type(const std::string &type, ModulePtr m = std::make_shared<Module>())
|
||||
{
|
||||
typedef typename ContainerType::reference (ContainerType::*front_ptr)();
|
||||
typedef typename ContainerType::const_reference (ContainerType::*const_front_ptr)() const;
|
||||
@@ -356,8 +373,20 @@ namespace chaiscript
|
||||
m->add(fun(static_cast<const_front_ptr>(&ContainerType::front)), "front");
|
||||
|
||||
m->add(fun(static_cast<push_ptr>(&ContainerType::push_front)),
|
||||
[]()->std::string{
|
||||
[&]()->std::string{
|
||||
if (typeid(typename ContainerType::value_type) == typeid(Boxed_Value)) {
|
||||
m->eval(
|
||||
"# Pushes the second value onto the front of container while making a clone of the value\n"
|
||||
"def push_front(" + type + " container, x)\n"
|
||||
"{ \n"
|
||||
" if (x.is_var_return_value()) {\n"
|
||||
" x.reset_var_return_value() \n"
|
||||
" container.push_front_ref(x) \n"
|
||||
" } else { \n"
|
||||
" container.push_front_ref(clone(x)); \n"
|
||||
" }\n"
|
||||
"} \n"
|
||||
);
|
||||
return "push_front_ref";
|
||||
} else {
|
||||
return "push_front";
|
||||
@@ -438,9 +467,37 @@ namespace chaiscript
|
||||
m->add(user_type<MapType>(), type);
|
||||
|
||||
typedef typename MapType::mapped_type &(MapType::*elem_access)(const typename MapType::key_type &);
|
||||
typedef const typename MapType::mapped_type &(MapType::*const_elem_access)(const typename MapType::key_type &) const;
|
||||
|
||||
m->add(fun(static_cast<elem_access>(&MapType::operator[])), "[]");
|
||||
|
||||
m->add(fun(static_cast<elem_access>(&MapType::at)), "at");
|
||||
m->add(fun(static_cast<const_elem_access>(&MapType::at)), "at");
|
||||
|
||||
if (typeid(MapType) == typeid(std::map<std::string, Boxed_Value>))
|
||||
{
|
||||
m->eval(R"(
|
||||
def Map::`==`(Map rhs) {
|
||||
if ( rhs.size() != this.size() ) {
|
||||
return false;
|
||||
} else {
|
||||
auto r1 = range(this);
|
||||
auto r2 = range(rhs);
|
||||
while (!r1.empty())
|
||||
{
|
||||
if (!eq(r1.front().first, r2.front().first) || !eq(r1.front().second, r2.front().second))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
r1.pop_front();
|
||||
r2.pop_front();
|
||||
}
|
||||
true;
|
||||
}
|
||||
} )"
|
||||
);
|
||||
}
|
||||
|
||||
container_type<MapType>(type, m);
|
||||
default_constructible_type<MapType>(type, m);
|
||||
assignable_type<MapType>(type, m);
|
||||
@@ -496,7 +553,7 @@ namespace chaiscript
|
||||
if (typeid(VectorType) == typeid(std::vector<Boxed_Value>))
|
||||
{
|
||||
m->eval(R"(
|
||||
def Vector::`==`(rhs) : type_match(rhs, this) {
|
||||
def Vector::`==`(Vector rhs) {
|
||||
if ( rhs.size() != this.size() ) {
|
||||
return false;
|
||||
} else {
|
||||
@@ -547,23 +604,20 @@ namespace chaiscript
|
||||
}());
|
||||
|
||||
|
||||
typedef std::function<size_t (const String *, const String &, size_t)> find_func;
|
||||
m->add(fun([](const String *s, const String &f, size_t pos) { return s->find(f, pos); } ), "find");
|
||||
m->add(fun([](const String *s, const String &f, size_t pos) { return s->rfind(f, pos); } ), "rfind");
|
||||
m->add(fun([](const String *s, const String &f, size_t pos) { return s->find_first_of(f, pos); } ), "find_first_of");
|
||||
m->add(fun([](const String *s, const String &f, size_t pos) { return s->find_last_of(f, pos); } ), "find_last_of");
|
||||
m->add(fun([](const String *s, const String &f, size_t pos) { return s->find_last_not_of(f, pos); } ), "find_last_not_of");
|
||||
m->add(fun([](const String *s, const String &f, size_t pos) { return s->find_first_not_of(f, pos); } ), "find_first_not_of");
|
||||
|
||||
m->add(fun([](String *s) { s->clear(); } ), "clear");
|
||||
m->add(fun([](const String *s) { return s->empty(); } ), "empty");
|
||||
m->add(fun([](const String *s) { return s->size(); } ), "size");
|
||||
|
||||
m->add(fun(find_func( [](const String *s, const String &f, size_t pos) { return s->find(f, pos); } )), "find");
|
||||
m->add(fun(find_func( [](const String *s, const String &f, size_t pos) { return s->rfind(f, pos); } ) ), "rfind");
|
||||
m->add(fun(find_func( [](const String *s, const String &f, size_t pos) { return s->find_first_of(f, pos); } ) ), "find_first_of");
|
||||
m->add(fun(find_func( [](const String *s, const String &f, size_t pos) { return s->find_last_of(f, pos); } ) ), "find_last_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( 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<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->data(); } ) ), "data");
|
||||
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");
|
||||
m->add(fun([](const String *s) { return s->c_str(); } ), "c_str");
|
||||
m->add(fun([](const String *s) { return s->data(); } ), "data");
|
||||
m->add(fun([](const String *s, size_t pos, size_t len) { return s->substr(pos, len); } ), "substr");
|
||||
|
||||
return m;
|
||||
}
|
||||
@@ -577,7 +631,7 @@ namespace chaiscript
|
||||
{
|
||||
m->add(user_type<FutureType>(), type);
|
||||
|
||||
m->add(fun<bool (const FutureType &)>([](const FutureType &t) { return t.valid(); }), "valid");
|
||||
m->add(fun([](const FutureType &t) { return t.valid(); }), "valid");
|
||||
m->add(fun(&FutureType::get), "get");
|
||||
m->add(fun(&FutureType::wait), "wait");
|
||||
|
||||
|
@@ -1,7 +1,7 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
|
||||
// Copyright 2009-2016, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#ifndef CHAISCRIPT_BOXED_CAST_HPP_
|
||||
@@ -69,9 +69,9 @@ namespace chaiscript
|
||||
/// assert(i == 5);
|
||||
/// \endcode
|
||||
template<typename Type>
|
||||
typename detail::Cast_Helper<Type>::Result_Type boxed_cast(const Boxed_Value &bv, const Type_Conversions *t_conversions = nullptr)
|
||||
typename detail::Cast_Helper<Type>::Result_Type boxed_cast(const Boxed_Value &bv, const Type_Conversions_State *t_conversions = nullptr)
|
||||
{
|
||||
if (!t_conversions || bv.get_type_info().bare_equal(user_type<Type>()) || (t_conversions && !t_conversions->convertable_type<Type>())) {
|
||||
if (!t_conversions || bv.get_type_info().bare_equal(user_type<Type>()) || (t_conversions && !(*t_conversions)->convertable_type<Type>())) {
|
||||
try {
|
||||
return detail::Cast_Helper<Type>::cast(bv, t_conversions);
|
||||
} catch (const chaiscript::detail::exception::bad_any_cast &) {
|
||||
@@ -79,25 +79,18 @@ namespace chaiscript
|
||||
}
|
||||
|
||||
|
||||
#ifdef CHAISCRIPT_MSVC
|
||||
//Thank you MSVC, yes we know that a constant value is being used in the if
|
||||
// statment in THIS VERSION of the template instantiation
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4127)
|
||||
#endif
|
||||
|
||||
if (t_conversions && t_conversions->convertable_type<Type>())
|
||||
if (t_conversions && (*t_conversions)->convertable_type<Type>())
|
||||
{
|
||||
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
|
||||
// either way, we are not responsible if it doesn't work
|
||||
return detail::Cast_Helper<Type>::cast(t_conversions->boxed_type_conversion<Type>(bv), t_conversions);
|
||||
return detail::Cast_Helper<Type>::cast((*t_conversions)->boxed_type_conversion<Type>(t_conversions->saves(), bv), t_conversions);
|
||||
} catch (...) {
|
||||
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);
|
||||
return detail::Cast_Helper<Type>::cast((*t_conversions)->boxed_type_down_conversion<Type>(t_conversions->saves(), bv), t_conversions);
|
||||
} catch (const chaiscript::detail::exception::bad_any_cast &) {
|
||||
throw exception::bad_boxed_cast(bv.get_type_info(), typeid(Type));
|
||||
}
|
||||
@@ -108,10 +101,6 @@ namespace chaiscript
|
||||
throw exception::bad_boxed_cast(bv.get_type_info(), typeid(Type));
|
||||
}
|
||||
|
||||
#ifdef CHAISCRIPT_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -1,7 +1,7 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
|
||||
// Copyright 2009-2016, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#ifndef CHAISCRIPT_BOXED_CAST_HELPER_HPP_
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
class Type_Conversions;
|
||||
class Type_Conversions_State;
|
||||
|
||||
namespace detail
|
||||
{
|
||||
@@ -33,14 +33,14 @@ namespace chaiscript
|
||||
template<typename Result>
|
||||
struct Cast_Helper_Inner
|
||||
{
|
||||
typedef std::reference_wrapper<typename std::add_const<Result>::type > Result_Type;
|
||||
typedef typename std::add_const<Result>::type Result_Type;
|
||||
|
||||
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *)
|
||||
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions_State *)
|
||||
{
|
||||
if (ob.get_type_info().bare_equal_type_info(typeid(Result)))
|
||||
{
|
||||
auto p = throw_if_null(ob.get_const_ptr());
|
||||
return std::cref(*static_cast<const Result *>(p));
|
||||
return *static_cast<const Result *>(p);
|
||||
} else {
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
}
|
||||
@@ -52,22 +52,17 @@ namespace chaiscript
|
||||
{
|
||||
};
|
||||
|
||||
/// Cast_Helper_Inner for casting to a const & type
|
||||
template<typename Result>
|
||||
struct Cast_Helper_Inner<const Result &> : Cast_Helper_Inner<Result>
|
||||
{
|
||||
};
|
||||
|
||||
/// Cast_Helper_Inner for casting to a const * type
|
||||
template<typename Result>
|
||||
struct Cast_Helper_Inner<const Result *>
|
||||
{
|
||||
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 Type_Conversions_State *)
|
||||
{
|
||||
if (ob.get_type_info().bare_equal_type_info(typeid(Result)))
|
||||
{
|
||||
return static_cast<const Result *>(throw_if_null(ob.get_const_ptr()));
|
||||
return static_cast<const Result *>(ob.get_const_ptr());
|
||||
} else {
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
}
|
||||
@@ -79,13 +74,42 @@ namespace chaiscript
|
||||
struct Cast_Helper_Inner<Result *>
|
||||
{
|
||||
typedef Result * Result_Type;
|
||||
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *)
|
||||
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions_State *)
|
||||
{
|
||||
if (ob.is_ref())
|
||||
if (!ob.get_type_info().is_const() && ob.get_type_info() == typeid(Result))
|
||||
{
|
||||
return &(ob.get().cast<std::reference_wrapper<Result> >()).get();
|
||||
return static_cast<Result *>(ob.get_ptr());
|
||||
} else {
|
||||
return (ob.get().cast<std::shared_ptr<Result> >()).get();
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Result>
|
||||
struct Cast_Helper_Inner<Result * const &> : public Cast_Helper_Inner<Result *>
|
||||
{
|
||||
};
|
||||
|
||||
template<typename Result>
|
||||
struct Cast_Helper_Inner<const Result * const &> : public Cast_Helper_Inner<const Result *>
|
||||
{
|
||||
};
|
||||
|
||||
|
||||
/// Cast_Helper_Inner for casting to a & type
|
||||
template<typename Result>
|
||||
struct Cast_Helper_Inner<const Result &>
|
||||
{
|
||||
typedef const Result& Result_Type;
|
||||
|
||||
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions_State *)
|
||||
{
|
||||
if (ob.get_type_info().bare_equal_type_info(typeid(Result)))
|
||||
{
|
||||
auto p = throw_if_null(ob.get_const_ptr());
|
||||
return *static_cast<const Result *>(p);
|
||||
} else {
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -98,7 +122,7 @@ namespace chaiscript
|
||||
{
|
||||
typedef Result& Result_Type;
|
||||
|
||||
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *)
|
||||
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions_State *)
|
||||
{
|
||||
if (!ob.get_type_info().is_const() && ob.get_type_info().bare_equal_type_info(typeid(Result)))
|
||||
{
|
||||
@@ -115,7 +139,7 @@ namespace chaiscript
|
||||
{
|
||||
typedef std::shared_ptr<Result> Result_Type;
|
||||
|
||||
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *)
|
||||
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions_State *)
|
||||
{
|
||||
return ob.get().cast<std::shared_ptr<Result> >();
|
||||
}
|
||||
@@ -127,7 +151,7 @@ namespace chaiscript
|
||||
{
|
||||
typedef std::shared_ptr<const Result> Result_Type;
|
||||
|
||||
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *)
|
||||
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions_State *)
|
||||
{
|
||||
if (!ob.get_type_info().is_const())
|
||||
{
|
||||
@@ -149,6 +173,20 @@ namespace chaiscript
|
||||
{
|
||||
};
|
||||
|
||||
template<typename Result>
|
||||
struct Cast_Helper_Inner<std::shared_ptr<Result> &>
|
||||
{
|
||||
static_assert(!std::is_const<Result>::value, "Non-const reference to std::shared_ptr<const T> is not supported");
|
||||
|
||||
typedef Boxed_Value::Sentinel<Result> Result_Type;
|
||||
|
||||
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions_State *)
|
||||
{
|
||||
std::shared_ptr<Result> &res = ob.get().cast<std::shared_ptr<Result> >();
|
||||
return ob.pointer_sentinel(res);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/// Cast_Helper_Inner for casting to a const std::shared_ptr<const> & type
|
||||
template<typename Result>
|
||||
@@ -162,14 +200,13 @@ namespace chaiscript
|
||||
};
|
||||
|
||||
|
||||
|
||||
/// Cast_Helper_Inner for casting to a Boxed_Value type
|
||||
template<>
|
||||
struct Cast_Helper_Inner<Boxed_Value>
|
||||
{
|
||||
typedef const Boxed_Value & Result_Type;
|
||||
typedef Boxed_Value Result_Type;
|
||||
|
||||
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *)
|
||||
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions_State *)
|
||||
{
|
||||
return ob;
|
||||
}
|
||||
@@ -179,11 +216,11 @@ namespace chaiscript
|
||||
template<>
|
||||
struct Cast_Helper_Inner<Boxed_Value &>
|
||||
{
|
||||
typedef Boxed_Value& Result_Type;
|
||||
typedef std::reference_wrapper<Boxed_Value> Result_Type;
|
||||
|
||||
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *)
|
||||
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions_State *)
|
||||
{
|
||||
return const_cast<Boxed_Value &>(ob);
|
||||
return std::ref(const_cast<Boxed_Value &>(ob));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -237,7 +274,7 @@ namespace chaiscript
|
||||
{
|
||||
typedef typename Cast_Helper_Inner<T>::Result_Type Result_Type;
|
||||
|
||||
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *t_conversions)
|
||||
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions_State *t_conversions)
|
||||
{
|
||||
return Cast_Helper_Inner<T>::cast(ob, t_conversions);
|
||||
}
|
||||
|
@@ -1,7 +1,7 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
|
||||
// Copyright 2009-2016, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#ifndef CHAISCRIPT_BOXED_NUMERIC_HPP_
|
||||
@@ -43,24 +43,41 @@ namespace chaiscript
|
||||
// this is OK, so we're disabling size/and sign type warnings
|
||||
#ifdef CHAISCRIPT_MSVC
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4244 4018 4389 4146 4365)
|
||||
#pragma warning(disable : 4244 4018 4389 4146 4365 4267 4242)
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wunknown-pragmas"
|
||||
#pragma GCC diagnostic ignored "-Wpragmas"
|
||||
#pragma GCC diagnostic ignored "-Wsign-compare"
|
||||
#pragma GCC diagnostic ignored "-Wfloat-equal"
|
||||
#pragma GCC diagnostic ignored "-Wconversion"
|
||||
#pragma GCC diagnostic ignored "-Wsign-conversion"
|
||||
#pragma GCC diagnostic ignored "-Wfloat-conversion"
|
||||
#endif
|
||||
|
||||
/// \brief Represents any numeric type, generically. Used internally for generic operations between POD values
|
||||
class Boxed_Number
|
||||
{
|
||||
private:
|
||||
enum class Common_Types {
|
||||
t_int32,
|
||||
t_double,
|
||||
t_uint8,
|
||||
t_int8,
|
||||
t_uint16,
|
||||
t_int16,
|
||||
t_uint32,
|
||||
t_uint64,
|
||||
t_int64,
|
||||
t_float,
|
||||
t_long_double
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
static void check_divide_by_zero(T t, typename std::enable_if<std::is_integral<T>::value>::type* = nullptr)
|
||||
static inline void check_divide_by_zero(T t, typename std::enable_if<std::is_integral<T>::value>::type* = nullptr)
|
||||
{
|
||||
#ifndef CHAISCRIPT_NO_PROTECT_DIVIDEBYZERO
|
||||
if (t == 0) {
|
||||
@@ -70,292 +87,406 @@ namespace chaiscript
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static void check_divide_by_zero(T, typename std::enable_if<std::is_floating_point<T>::value>::type* = nullptr)
|
||||
static inline void check_divide_by_zero(T, typename std::enable_if<std::is_floating_point<T>::value>::type* = nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
struct boolean
|
||||
static CHAISCRIPT_CONSTEXPR Common_Types get_common_type(size_t t_size, bool t_signed)
|
||||
{
|
||||
return (t_size == 1 && t_signed)?(Common_Types::t_int8)
|
||||
:(t_size == 1)?(Common_Types::t_uint8)
|
||||
:(t_size == 2 && t_signed)?(Common_Types::t_int16)
|
||||
:(t_size == 2)?(Common_Types::t_uint16)
|
||||
:(t_size == 4 && t_signed)?(Common_Types::t_int32)
|
||||
:(t_size == 4)?(Common_Types::t_uint32)
|
||||
:(t_size == 8 && t_signed)?(Common_Types::t_int64)
|
||||
:(Common_Types::t_uint64);
|
||||
}
|
||||
|
||||
template<typename T, typename U>
|
||||
static Boxed_Value go(Operators::Opers t_oper, const T &t, const U &u, const Boxed_Value &)
|
||||
{
|
||||
switch (t_oper)
|
||||
{
|
||||
case Operators::equals:
|
||||
return const_var(t == u);
|
||||
case Operators::less_than:
|
||||
return const_var(t < u);
|
||||
case Operators::greater_than:
|
||||
return const_var(t > u);
|
||||
case Operators::less_than_equal:
|
||||
return const_var(t <= u);
|
||||
case Operators::greater_than_equal:
|
||||
return const_var(t >= u);
|
||||
case Operators::not_equal:
|
||||
return const_var(t != u);
|
||||
default:
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
}
|
||||
|
||||
static Common_Types get_common_type(const Boxed_Value &t_bv)
|
||||
{
|
||||
const Type_Info &inp_ = t_bv.get_type_info();
|
||||
|
||||
if (inp_ == typeid(int)) {
|
||||
return get_common_type(sizeof(int), true);
|
||||
} else if (inp_ == typeid(double)) {
|
||||
return Common_Types::t_double;
|
||||
} else if (inp_ == typeid(long double)) {
|
||||
return Common_Types::t_long_double;
|
||||
} else if (inp_ == typeid(float)) {
|
||||
return Common_Types::t_float;
|
||||
} else if (inp_ == typeid(char)) {
|
||||
return get_common_type(sizeof(char), std::is_signed<char>::value);
|
||||
} else if (inp_ == typeid(unsigned char)) {
|
||||
return get_common_type(sizeof(unsigned char), false);
|
||||
} else if (inp_ == typeid(unsigned int)) {
|
||||
return get_common_type(sizeof(unsigned int), false);
|
||||
} else if (inp_ == typeid(long)) {
|
||||
return get_common_type(sizeof(long), true);
|
||||
} else if (inp_ == typeid(long long)) {
|
||||
return get_common_type(sizeof(long long), true);
|
||||
} else if (inp_ == typeid(unsigned long)) {
|
||||
return get_common_type(sizeof(unsigned long), false);
|
||||
} else if (inp_ == typeid(unsigned long long)) {
|
||||
return get_common_type(sizeof(unsigned long long), false);
|
||||
} else if (inp_ == typeid(std::int8_t)) {
|
||||
return Common_Types::t_int8;
|
||||
} else if (inp_ == typeid(std::int16_t)) {
|
||||
return Common_Types::t_int16;
|
||||
} else if (inp_ == typeid(std::int32_t)) {
|
||||
return Common_Types::t_int32;
|
||||
} else if (inp_ == typeid(std::int64_t)) {
|
||||
return Common_Types::t_int64;
|
||||
} else if (inp_ == typeid(std::uint8_t)) {
|
||||
return Common_Types::t_uint8;
|
||||
} else if (inp_ == typeid(std::uint16_t)) {
|
||||
return Common_Types::t_uint16;
|
||||
} else if (inp_ == typeid(std::uint32_t)) {
|
||||
return Common_Types::t_uint32;
|
||||
} else if (inp_ == typeid(std::uint64_t)) {
|
||||
return Common_Types::t_uint64;
|
||||
} else if (inp_ == typeid(wchar_t)) {
|
||||
return get_common_type(sizeof(wchar_t), std::is_signed<wchar_t>::value);
|
||||
} else if (inp_ == typeid(char16_t)) {
|
||||
return get_common_type(sizeof(char16_t), std::is_signed<char16_t>::value);
|
||||
} else if (inp_ == typeid(char32_t)) {
|
||||
return get_common_type(sizeof(char32_t), std::is_signed<char32_t>::value);
|
||||
} else {
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
struct binary
|
||||
template<typename T>
|
||||
static Boxed_Value boolean_go(Operators::Opers t_oper, const T &t, const T &u)
|
||||
{
|
||||
template<typename T, typename U>
|
||||
static Boxed_Value go(Operators::Opers t_oper, T &t, const U &u, const Boxed_Value &t_lhs)
|
||||
switch (t_oper)
|
||||
{
|
||||
switch (t_oper)
|
||||
{
|
||||
case Operators::assign:
|
||||
t = u;
|
||||
break;
|
||||
case Operators::pre_increment:
|
||||
++t;
|
||||
break;
|
||||
case Operators::pre_decrement:
|
||||
--t;
|
||||
break;
|
||||
case Operators::assign_product:
|
||||
t *= u;
|
||||
break;
|
||||
case Operators::assign_sum:
|
||||
t += u;
|
||||
break;
|
||||
case Operators::assign_quotient:
|
||||
check_divide_by_zero(u);
|
||||
t /= u;
|
||||
break;
|
||||
case Operators::assign_difference:
|
||||
t -= u;
|
||||
break;
|
||||
default:
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
}
|
||||
|
||||
return t_lhs;
|
||||
}
|
||||
};
|
||||
|
||||
struct binary_int
|
||||
{
|
||||
template<typename T, typename U>
|
||||
static Boxed_Value go(Operators::Opers t_oper, T &t, const U &u, const Boxed_Value &t_lhs)
|
||||
{
|
||||
switch (t_oper)
|
||||
{
|
||||
case Operators::assign_bitwise_and:
|
||||
t &= u;
|
||||
break;
|
||||
case Operators::assign_bitwise_or:
|
||||
t |= u;
|
||||
break;
|
||||
case Operators::assign_shift_left:
|
||||
t <<= u;
|
||||
break;
|
||||
case Operators::assign_shift_right:
|
||||
t >>= u;
|
||||
break;
|
||||
case Operators::assign_remainder:
|
||||
check_divide_by_zero(u);
|
||||
t %= u;
|
||||
break;
|
||||
case Operators::assign_bitwise_xor:
|
||||
t ^= u;
|
||||
break;
|
||||
default:
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
}
|
||||
return t_lhs;
|
||||
}
|
||||
};
|
||||
|
||||
struct const_binary_int
|
||||
{
|
||||
template<typename T, typename U>
|
||||
static Boxed_Value go(Operators::Opers t_oper, const T &t, const U &u, const Boxed_Value &)
|
||||
{
|
||||
switch (t_oper)
|
||||
{
|
||||
case Operators::shift_left:
|
||||
return const_var(t << u);
|
||||
case Operators::shift_right:
|
||||
return const_var(t >> u);
|
||||
case Operators::remainder:
|
||||
check_divide_by_zero(u);
|
||||
return const_var(t % u);
|
||||
case Operators::bitwise_and:
|
||||
return const_var(t & u);
|
||||
case Operators::bitwise_or:
|
||||
return const_var(t | u);
|
||||
case Operators::bitwise_xor:
|
||||
return const_var(t ^ u);
|
||||
case Operators::bitwise_complement:
|
||||
return const_var(~t);
|
||||
default:
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct const_binary
|
||||
{
|
||||
template<typename T, typename U>
|
||||
static Boxed_Value go(Operators::Opers t_oper, const T &t, const U &u, const Boxed_Value &)
|
||||
{
|
||||
switch (t_oper)
|
||||
{
|
||||
case Operators::sum:
|
||||
return const_var(t + u);
|
||||
case Operators::quotient:
|
||||
check_divide_by_zero(u);
|
||||
return const_var(t / u);
|
||||
case Operators::product:
|
||||
return const_var(t * u);
|
||||
case Operators::difference:
|
||||
return const_var(t - u);
|
||||
case Operators::unary_minus:
|
||||
return const_var(-t);
|
||||
case Operators::unary_plus:
|
||||
return const_var(+t);
|
||||
default:
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<typename LHS, typename RHS, bool Float>
|
||||
struct Go
|
||||
{
|
||||
static Boxed_Value go(Operators::Opers t_oper, const Boxed_Value &t_lhs, const Boxed_Value &t_rhs)
|
||||
{
|
||||
if (t_oper > Operators::boolean_flag && t_oper < Operators::non_const_flag)
|
||||
{
|
||||
return boolean::go<LHS, RHS>(t_oper, *static_cast<const LHS *>(t_lhs.get_const_ptr()), *static_cast<const RHS *>(t_rhs.get_const_ptr()), t_lhs);
|
||||
} else if (t_oper > Operators::non_const_flag && t_oper < Operators::non_const_int_flag && !t_lhs.is_const() && !t_lhs.is_return_value()) {
|
||||
return binary::go<LHS, RHS>(t_oper, *static_cast<LHS *>(t_lhs.get_ptr()), *static_cast<const RHS *>(t_rhs.get_const_ptr()), t_lhs);
|
||||
} else if (t_oper > Operators::non_const_int_flag && t_oper < Operators::const_int_flag && !t_lhs.is_const() && !t_lhs.is_return_value()) {
|
||||
return binary_int::go<LHS, RHS>(t_oper, *static_cast<LHS *>(t_lhs.get_ptr()), *static_cast<const RHS *>(t_rhs.get_const_ptr()), t_lhs);
|
||||
} else if (t_oper > Operators::const_int_flag && t_oper < Operators::const_flag) {
|
||||
return const_binary_int::go<LHS, RHS>(t_oper, *static_cast<const LHS *>(t_lhs.get_const_ptr()), *static_cast<const RHS *>(t_rhs.get_const_ptr()), t_lhs);
|
||||
} else if (t_oper > Operators::const_flag) {
|
||||
return const_binary::go<LHS, RHS>(t_oper, *static_cast<const LHS *>(t_lhs.get_const_ptr()), *static_cast<const RHS *>(t_rhs.get_const_ptr()), t_lhs);
|
||||
} else {
|
||||
case Operators::equals:
|
||||
return const_var(t == u);
|
||||
case Operators::less_than:
|
||||
return const_var(t < u);
|
||||
case Operators::greater_than:
|
||||
return const_var(t > u);
|
||||
case Operators::less_than_equal:
|
||||
return const_var(t <= u);
|
||||
case Operators::greater_than_equal:
|
||||
return const_var(t >= u);
|
||||
case Operators::not_equal:
|
||||
return const_var(t != u);
|
||||
default:
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static Boxed_Value unary_go(Operators::Opers t_oper, T &t, const Boxed_Value &t_lhs)
|
||||
{
|
||||
switch (t_oper)
|
||||
{
|
||||
case Operators::pre_increment:
|
||||
++t;
|
||||
break;
|
||||
case Operators::pre_decrement:
|
||||
--t;
|
||||
break;
|
||||
default:
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
}
|
||||
|
||||
return t_lhs;
|
||||
}
|
||||
|
||||
template<typename T, typename U>
|
||||
static Boxed_Value binary_go(Operators::Opers t_oper, T &t, const U &u, const Boxed_Value &t_lhs)
|
||||
{
|
||||
switch (t_oper)
|
||||
{
|
||||
case Operators::assign:
|
||||
t = u;
|
||||
break;
|
||||
case Operators::assign_product:
|
||||
t *= u;
|
||||
break;
|
||||
case Operators::assign_sum:
|
||||
t += u;
|
||||
break;
|
||||
case Operators::assign_quotient:
|
||||
check_divide_by_zero(u);
|
||||
t /= u;
|
||||
break;
|
||||
case Operators::assign_difference:
|
||||
t -= u;
|
||||
break;
|
||||
default:
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
}
|
||||
|
||||
return t_lhs;
|
||||
}
|
||||
|
||||
template<typename T, typename U>
|
||||
static Boxed_Value binary_int_go(Operators::Opers t_oper, T &t, const U &u, const Boxed_Value &t_lhs)
|
||||
{
|
||||
switch (t_oper)
|
||||
{
|
||||
case Operators::assign_bitwise_and:
|
||||
t &= u;
|
||||
break;
|
||||
case Operators::assign_bitwise_or:
|
||||
t |= u;
|
||||
break;
|
||||
case Operators::assign_shift_left:
|
||||
t <<= u;
|
||||
break;
|
||||
case Operators::assign_shift_right:
|
||||
t >>= u;
|
||||
break;
|
||||
case Operators::assign_remainder:
|
||||
check_divide_by_zero(u);
|
||||
t %= u;
|
||||
break;
|
||||
case Operators::assign_bitwise_xor:
|
||||
t ^= u;
|
||||
break;
|
||||
default:
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
}
|
||||
return t_lhs;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static Boxed_Value const_unary_int_go(Operators::Opers t_oper, const T &t)
|
||||
{
|
||||
switch (t_oper)
|
||||
{
|
||||
case Operators::bitwise_complement:
|
||||
return const_var(~t);
|
||||
default:
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static Boxed_Value const_binary_int_go(Operators::Opers t_oper, const T &t, const T &u)
|
||||
{
|
||||
switch (t_oper)
|
||||
{
|
||||
case Operators::shift_left:
|
||||
return const_var(t << u);
|
||||
case Operators::shift_right:
|
||||
return const_var(t >> u);
|
||||
case Operators::remainder:
|
||||
check_divide_by_zero(u);
|
||||
return const_var(t % u);
|
||||
case Operators::bitwise_and:
|
||||
return const_var(t & u);
|
||||
case Operators::bitwise_or:
|
||||
return const_var(t | u);
|
||||
case Operators::bitwise_xor:
|
||||
return const_var(t ^ u);
|
||||
default:
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static Boxed_Value const_unary_go(Operators::Opers t_oper, const T &t)
|
||||
{
|
||||
switch (t_oper)
|
||||
{
|
||||
case Operators::unary_minus:
|
||||
return const_var(-t);
|
||||
case Operators::unary_plus:
|
||||
return const_var(+t);
|
||||
default:
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static Boxed_Value const_binary_go(Operators::Opers t_oper, const T &t, const T &u)
|
||||
{
|
||||
switch (t_oper)
|
||||
{
|
||||
case Operators::sum:
|
||||
return const_var(t + u);
|
||||
case Operators::quotient:
|
||||
check_divide_by_zero(u);
|
||||
return const_var(t / u);
|
||||
case Operators::product:
|
||||
return const_var(t * u);
|
||||
case Operators::difference:
|
||||
return const_var(t - u);
|
||||
default:
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
}
|
||||
}
|
||||
|
||||
template<typename LHS, typename RHS>
|
||||
struct Go<LHS, RHS, true>
|
||||
static auto go(Operators::Opers t_oper, const Boxed_Value &t_lhs, const Boxed_Value &t_rhs)
|
||||
-> typename std::enable_if<!std::is_floating_point<LHS>::value && !std::is_floating_point<RHS>::value, Boxed_Value>::type
|
||||
{
|
||||
static Boxed_Value go(Operators::Opers t_oper, const Boxed_Value &t_lhs, const Boxed_Value &t_rhs)
|
||||
typedef typename std::common_type<LHS, RHS>::type common_type;
|
||||
if (t_oper > Operators::boolean_flag && t_oper < Operators::non_const_flag)
|
||||
{
|
||||
if (t_oper > Operators::boolean_flag && t_oper < Operators::non_const_flag)
|
||||
{
|
||||
return boolean::go<LHS, RHS>(t_oper, *static_cast<const LHS *>(t_lhs.get_const_ptr()), *static_cast<const RHS *>(t_rhs.get_const_ptr()), t_lhs);
|
||||
} else if (t_oper > Operators::non_const_flag && t_oper < Operators::non_const_int_flag && !t_lhs.is_const() && !t_lhs.is_return_value()) {
|
||||
return binary::go<LHS, RHS>(t_oper, *static_cast<LHS *>(t_lhs.get_ptr()), *static_cast<const RHS *>(t_rhs.get_const_ptr()), t_lhs);
|
||||
} else if (t_oper > Operators::non_const_int_flag && t_oper < Operators::const_int_flag) {
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
} else if (t_oper > Operators::const_int_flag && t_oper < Operators::const_flag) {
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
} else if (t_oper > Operators::const_flag) {
|
||||
return const_binary::go<LHS, RHS>(t_oper, *static_cast<const LHS *>(t_lhs.get_const_ptr()), *static_cast<const RHS *>(t_rhs.get_const_ptr()), t_lhs);
|
||||
} else {
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
}
|
||||
return boolean_go(t_oper, get_as_aux<common_type, LHS>(t_lhs), get_as_aux<common_type, RHS>(t_rhs));
|
||||
} else if (t_oper > Operators::non_const_flag && t_oper < Operators::non_const_int_flag && !t_lhs.is_const() && !t_lhs.is_return_value()) {
|
||||
return binary_go(t_oper, *static_cast<LHS *>(t_lhs.get_ptr()), get_as_aux<common_type, RHS>(t_rhs), t_lhs);
|
||||
} else if (t_oper > Operators::non_const_int_flag && t_oper < Operators::const_int_flag && !t_lhs.is_const() && !t_lhs.is_return_value()) {
|
||||
return binary_int_go(t_oper, *static_cast<LHS *>(t_lhs.get_ptr()), get_as_aux<common_type, RHS>(t_rhs), t_lhs);
|
||||
} else if (t_oper > Operators::const_int_flag && t_oper < Operators::const_flag) {
|
||||
return const_binary_int_go(t_oper, get_as_aux<common_type, LHS>(t_lhs), get_as_aux<common_type, RHS>(t_rhs));
|
||||
} else if (t_oper > Operators::const_flag) {
|
||||
return const_binary_go(t_oper, get_as_aux<common_type, LHS>(t_lhs), get_as_aux<common_type, RHS>(t_rhs));
|
||||
} else {
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
template<typename LHS, bool Float>
|
||||
static Boxed_Value oper_rhs(Operators::Opers t_oper, const Boxed_Value &t_lhs, const Boxed_Value &t_rhs)
|
||||
template<typename LHS, typename RHS>
|
||||
static auto go(Operators::Opers t_oper, const Boxed_Value &t_lhs, const Boxed_Value &t_rhs)
|
||||
-> typename std::enable_if<std::is_floating_point<LHS>::value || std::is_floating_point<RHS>::value, Boxed_Value>::type
|
||||
{
|
||||
typedef typename std::common_type<LHS, RHS>::type common_type;
|
||||
if (t_oper > Operators::boolean_flag && t_oper < Operators::non_const_flag)
|
||||
{
|
||||
const auto &inp_ = t_rhs.get_type_info();
|
||||
return boolean_go(t_oper, get_as_aux<common_type, LHS>(t_lhs), get_as_aux<common_type, RHS>(t_rhs));
|
||||
} else if (t_oper > Operators::non_const_flag && t_oper < Operators::non_const_int_flag && !t_lhs.is_const() && !t_lhs.is_return_value()) {
|
||||
return binary_go(t_oper, *static_cast<LHS *>(t_lhs.get_ptr()), get_as_aux<common_type, RHS>(t_rhs), t_lhs);
|
||||
} else if (t_oper > Operators::const_flag) {
|
||||
return const_binary_go(t_oper, get_as_aux<common_type, LHS>(t_lhs), get_as_aux<common_type, RHS>(t_rhs));
|
||||
} else {
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
}
|
||||
}
|
||||
|
||||
if (inp_ == typeid(int)) {
|
||||
return Go<LHS, int, Float>::go(t_oper, t_lhs, t_rhs);
|
||||
} else if (inp_ == typeid(double)) {
|
||||
return Go<LHS, double, true>::go(t_oper, t_lhs, t_rhs);
|
||||
} else if (inp_ == typeid(float)) {
|
||||
return Go<LHS, float, true>::go(t_oper, t_lhs, t_rhs);
|
||||
} else if (inp_ == typeid(long double)) {
|
||||
return Go<LHS, long double, true>::go(t_oper, t_lhs, t_rhs);
|
||||
} else if (inp_ == typeid(char)) {
|
||||
return Go<LHS, char, Float>::go(t_oper, t_lhs, t_rhs);
|
||||
} else if (inp_ == typeid(unsigned int)) {
|
||||
return Go<LHS, unsigned int, Float>::go(t_oper, t_lhs, t_rhs);
|
||||
} else if (inp_ == typeid(long)) {
|
||||
return Go<LHS, long, Float>::go(t_oper, t_lhs, t_rhs);
|
||||
} else if (inp_ == typeid(unsigned long)) {
|
||||
return Go<LHS, unsigned long, Float>::go(t_oper, t_lhs, t_rhs);
|
||||
} else if (inp_ == typeid(std::int8_t)) {
|
||||
return Go<LHS, std::int8_t, Float>::go(t_oper, t_lhs, t_rhs);
|
||||
} else if (inp_ == typeid(std::int16_t)) {
|
||||
return Go<LHS, std::int16_t, Float>::go(t_oper, t_lhs, t_rhs);
|
||||
} else if (inp_ == typeid(std::int32_t)) {
|
||||
return Go<LHS, std::int32_t, Float>::go(t_oper, t_lhs, t_rhs);
|
||||
} else if (inp_ == typeid(std::int64_t)) {
|
||||
return Go<LHS, std::int64_t, Float>::go(t_oper, t_lhs, t_rhs);
|
||||
} else if (inp_ == typeid(std::uint8_t)) {
|
||||
return Go<LHS, std::uint8_t, Float>::go(t_oper, t_lhs, t_rhs);
|
||||
} else if (inp_ == typeid(std::uint16_t)) {
|
||||
return Go<LHS, std::uint16_t, Float>::go(t_oper, t_lhs, t_rhs);
|
||||
} else if (inp_ == typeid(std::uint32_t)) {
|
||||
return Go<LHS, std::uint32_t, Float>::go(t_oper, t_lhs, t_rhs);
|
||||
} else if (inp_ == typeid(std::uint64_t)) {
|
||||
return Go<LHS, std::uint64_t, Float>::go(t_oper, t_lhs, t_rhs);
|
||||
} else {
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
// Unary
|
||||
template<typename LHS>
|
||||
static auto go(Operators::Opers t_oper, const Boxed_Value &t_lhs)
|
||||
-> typename std::enable_if<!std::is_floating_point<LHS>::value, Boxed_Value>::type
|
||||
{
|
||||
if (t_oper > Operators::non_const_flag && t_oper < Operators::non_const_int_flag && !t_lhs.is_const() && !t_lhs.is_return_value()) {
|
||||
return unary_go(t_oper, *static_cast<LHS *>(t_lhs.get_ptr()), t_lhs);
|
||||
} else if (t_oper > Operators::const_int_flag && t_oper < Operators::const_flag) {
|
||||
return const_unary_int_go(t_oper, *static_cast<const LHS *>(t_lhs.get_const_ptr()));
|
||||
} else if (t_oper > Operators::const_flag) {
|
||||
return const_unary_go(t_oper, *static_cast<const LHS *>(t_lhs.get_const_ptr()));
|
||||
} else {
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
}
|
||||
}
|
||||
|
||||
template<typename LHS>
|
||||
static auto go(Operators::Opers t_oper, const Boxed_Value &t_lhs)
|
||||
-> typename std::enable_if<std::is_floating_point<LHS>::value, Boxed_Value>::type
|
||||
{
|
||||
if (t_oper > Operators::non_const_flag && t_oper < Operators::non_const_int_flag && !t_lhs.is_const() && !t_lhs.is_return_value()) {
|
||||
return unary_go(t_oper, *static_cast<LHS *>(t_lhs.get_ptr()), t_lhs);
|
||||
} else if (t_oper > Operators::const_flag) {
|
||||
return const_unary_go(t_oper, *static_cast<const LHS *>(t_lhs.get_const_ptr()));
|
||||
} else {
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
}
|
||||
}
|
||||
|
||||
template<typename LHS>
|
||||
inline static Boxed_Value oper_rhs(Operators::Opers t_oper, const Boxed_Value &t_lhs, const Boxed_Value &t_rhs)
|
||||
{
|
||||
switch (get_common_type(t_rhs)) {
|
||||
case Common_Types::t_int32:
|
||||
return go<LHS, int32_t>(t_oper, t_lhs, t_rhs);
|
||||
case Common_Types::t_uint8:
|
||||
return go<LHS, uint8_t>(t_oper, t_lhs, t_rhs);
|
||||
case Common_Types::t_int8:
|
||||
return go<LHS, int8_t>(t_oper, t_lhs, t_rhs);
|
||||
case Common_Types::t_uint16:
|
||||
return go<LHS, uint16_t>(t_oper, t_lhs, t_rhs);
|
||||
case Common_Types::t_int16:
|
||||
return go<LHS, int16_t>(t_oper, t_lhs, t_rhs);
|
||||
case Common_Types::t_uint32:
|
||||
return go<LHS, uint32_t>(t_oper, t_lhs, t_rhs);
|
||||
case Common_Types::t_uint64:
|
||||
return go<LHS, uint64_t>(t_oper, t_lhs, t_rhs);
|
||||
case Common_Types::t_int64:
|
||||
return go<LHS, int64_t>(t_oper, t_lhs, t_rhs);
|
||||
case Common_Types::t_double:
|
||||
return go<LHS, double>(t_oper, t_lhs, t_rhs);
|
||||
case Common_Types::t_float:
|
||||
return go<LHS, float>(t_oper, t_lhs, t_rhs);
|
||||
case Common_Types::t_long_double:
|
||||
return go<LHS, long double>(t_oper, t_lhs, t_rhs);
|
||||
}
|
||||
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
}
|
||||
|
||||
static Boxed_Value oper(Operators::Opers t_oper, const Boxed_Value &t_lhs, const Boxed_Value &t_rhs)
|
||||
inline static Boxed_Value oper(Operators::Opers t_oper, const Boxed_Value &t_lhs)
|
||||
{
|
||||
const Type_Info &inp_ = t_lhs.get_type_info();
|
||||
|
||||
if (inp_ == typeid(int)) {
|
||||
return oper_rhs<int, false>(t_oper, t_lhs, t_rhs);
|
||||
} else if (inp_ == typeid(double)) {
|
||||
return oper_rhs<double, true>(t_oper, t_lhs, t_rhs);
|
||||
} else if (inp_ == typeid(long double)) {
|
||||
return oper_rhs<long double, true>(t_oper, t_lhs, t_rhs);
|
||||
} else if (inp_ == typeid(float)) {
|
||||
return oper_rhs<float, true>(t_oper, t_lhs, t_rhs);
|
||||
} else if (inp_ == typeid(char)) {
|
||||
return oper_rhs<char, false>(t_oper, t_lhs, t_rhs);
|
||||
} else if (inp_ == typeid(unsigned int)) {
|
||||
return oper_rhs<unsigned int, false>(t_oper, t_lhs, t_rhs);
|
||||
} else if (inp_ == typeid(long)) {
|
||||
return oper_rhs<long, false>(t_oper, t_lhs, t_rhs);
|
||||
} else if (inp_ == typeid(unsigned long)) {
|
||||
return oper_rhs<unsigned long, false>(t_oper, t_lhs, t_rhs);
|
||||
} else if (inp_ == typeid(std::int8_t)) {
|
||||
return oper_rhs<std::int8_t, false>(t_oper, t_lhs, t_rhs);
|
||||
} else if (inp_ == typeid(std::int16_t)) {
|
||||
return oper_rhs<std::int16_t, false>(t_oper, t_lhs, t_rhs);
|
||||
} else if (inp_ == typeid(std::int32_t)) {
|
||||
return oper_rhs<std::int32_t, false>(t_oper, t_lhs, t_rhs);
|
||||
} else if (inp_ == typeid(std::int64_t)) {
|
||||
return oper_rhs<std::int64_t, false>(t_oper, t_lhs, t_rhs);
|
||||
} else if (inp_ == typeid(std::uint8_t)) {
|
||||
return oper_rhs<std::uint8_t, false>(t_oper, t_lhs, t_rhs);
|
||||
} else if (inp_ == typeid(std::uint16_t)) {
|
||||
return oper_rhs<std::uint16_t, false>(t_oper, t_lhs, t_rhs);
|
||||
} else if (inp_ == typeid(std::uint32_t)) {
|
||||
return oper_rhs<std::uint32_t, false>(t_oper, t_lhs, t_rhs);
|
||||
} else if (inp_ == typeid(std::uint64_t)) {
|
||||
return oper_rhs<std::uint64_t, false>(t_oper, t_lhs, t_rhs);
|
||||
} else {
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
switch (get_common_type(t_lhs)) {
|
||||
case Common_Types::t_int32:
|
||||
return go<int32_t>(t_oper, t_lhs);
|
||||
case Common_Types::t_uint8:
|
||||
return go<uint8_t>(t_oper, t_lhs);
|
||||
case Common_Types::t_int8:
|
||||
return go<int8_t>(t_oper, t_lhs);
|
||||
case Common_Types::t_uint16:
|
||||
return go<uint16_t>(t_oper, t_lhs);
|
||||
case Common_Types::t_int16:
|
||||
return go<int16_t>(t_oper, t_lhs);
|
||||
case Common_Types::t_uint32:
|
||||
return go<uint32_t>(t_oper, t_lhs);
|
||||
case Common_Types::t_uint64:
|
||||
return go<uint64_t>(t_oper, t_lhs);
|
||||
case Common_Types::t_int64:
|
||||
return go<int64_t>(t_oper, t_lhs);
|
||||
case Common_Types::t_double:
|
||||
return go<double>(t_oper, t_lhs);
|
||||
case Common_Types::t_float:
|
||||
return go<float>(t_oper, t_lhs);
|
||||
case Common_Types::t_long_double:
|
||||
return go<long double>(t_oper, t_lhs);
|
||||
}
|
||||
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
}
|
||||
|
||||
|
||||
inline static Boxed_Value oper(Operators::Opers t_oper, const Boxed_Value &t_lhs, const Boxed_Value &t_rhs)
|
||||
{
|
||||
switch (get_common_type(t_lhs)) {
|
||||
case Common_Types::t_int32:
|
||||
return oper_rhs<int32_t>(t_oper, t_lhs, t_rhs);
|
||||
case Common_Types::t_uint8:
|
||||
return oper_rhs<uint8_t>(t_oper, t_lhs, t_rhs);
|
||||
case Common_Types::t_int8:
|
||||
return oper_rhs<int8_t>(t_oper, t_lhs, t_rhs);
|
||||
case Common_Types::t_uint16:
|
||||
return oper_rhs<uint16_t>(t_oper, t_lhs, t_rhs);
|
||||
case Common_Types::t_int16:
|
||||
return oper_rhs<int16_t>(t_oper, t_lhs, t_rhs);
|
||||
case Common_Types::t_uint32:
|
||||
return oper_rhs<uint32_t>(t_oper, t_lhs, t_rhs);
|
||||
case Common_Types::t_uint64:
|
||||
return oper_rhs<uint64_t>(t_oper, t_lhs, t_rhs);
|
||||
case Common_Types::t_int64:
|
||||
return oper_rhs<int64_t>(t_oper, t_lhs, t_rhs);
|
||||
case Common_Types::t_double:
|
||||
return oper_rhs<double>(t_oper, t_lhs, t_rhs);
|
||||
case Common_Types::t_float:
|
||||
return oper_rhs<float>(t_oper, t_lhs, t_rhs);
|
||||
case Common_Types::t_long_double:
|
||||
return oper_rhs<long double>(t_oper, t_lhs, t_rhs);
|
||||
}
|
||||
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
}
|
||||
|
||||
template<typename Target, typename Source>
|
||||
Target get_as_aux() const
|
||||
{
|
||||
return static_cast<Target>(*static_cast<const Source *>(bv.get_const_ptr()));
|
||||
}
|
||||
static inline Target get_as_aux(const Boxed_Value &t_bv)
|
||||
{
|
||||
return static_cast<Target>(*static_cast<const Source *>(t_bv.get_const_ptr()));
|
||||
}
|
||||
|
||||
template<typename Source>
|
||||
static std::string to_string_aux(const Boxed_Value &v)
|
||||
@@ -390,6 +521,21 @@ namespace chaiscript
|
||||
validate_boxed_number(bv);
|
||||
}
|
||||
|
||||
static bool is_floating_point(const Boxed_Value &t_bv)
|
||||
{
|
||||
const Type_Info &inp_ = t_bv.get_type_info();
|
||||
|
||||
if (inp_ == typeid(double)) {
|
||||
return true;
|
||||
} else if (inp_ == typeid(long double)) {
|
||||
return true;
|
||||
} else if (inp_ == typeid(float)) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Boxed_Number get_as(const Type_Info &inp_) const
|
||||
{
|
||||
if (inp_.bare_equal_type_info(typeid(int))) {
|
||||
@@ -402,12 +548,24 @@ namespace chaiscript
|
||||
return Boxed_Number(get_as<long double>());
|
||||
} else if (inp_.bare_equal_type_info(typeid(char))) {
|
||||
return Boxed_Number(get_as<char>());
|
||||
} else if (inp_.bare_equal_type_info(typeid(unsigned char))) {
|
||||
return Boxed_Number(get_as<unsigned char>());
|
||||
} else if (inp_.bare_equal_type_info(typeid(wchar_t))) {
|
||||
return Boxed_Number(get_as<wchar_t>());
|
||||
} else if (inp_.bare_equal_type_info(typeid(char16_t))) {
|
||||
return Boxed_Number(get_as<char16_t>());
|
||||
} else if (inp_.bare_equal_type_info(typeid(char32_t))) {
|
||||
return Boxed_Number(get_as<char32_t>());
|
||||
} else if (inp_.bare_equal_type_info(typeid(unsigned int))) {
|
||||
return Boxed_Number(get_as<unsigned int>());
|
||||
} else if (inp_.bare_equal_type_info(typeid(long))) {
|
||||
return Boxed_Number(get_as<long>());
|
||||
} else if (inp_.bare_equal_type_info(typeid(long long))) {
|
||||
return Boxed_Number(get_as<long long>());
|
||||
} else if (inp_.bare_equal_type_info(typeid(unsigned long))) {
|
||||
return Boxed_Number(get_as<unsigned long>());
|
||||
} else if (inp_.bare_equal_type_info(typeid(unsigned long long))) {
|
||||
return Boxed_Number(get_as<unsigned long long>());
|
||||
} else if (inp_.bare_equal_type_info(typeid(int8_t))) {
|
||||
return Boxed_Number(get_as<int8_t>());
|
||||
} else if (inp_.bare_equal_type_info(typeid(int16_t))) {
|
||||
@@ -432,84 +590,62 @@ namespace chaiscript
|
||||
|
||||
template<typename Target> Target get_as() const
|
||||
{
|
||||
const Type_Info &inp_ = bv.get_type_info();
|
||||
|
||||
if (inp_ == typeid(int)) {
|
||||
return get_as_aux<Target, int>();
|
||||
} else if (inp_ == typeid(double)) {
|
||||
return get_as_aux<Target, double>();
|
||||
} else if (inp_ == typeid(float)) {
|
||||
return get_as_aux<Target, float>();
|
||||
} else if (inp_ == typeid(long double)) {
|
||||
return get_as_aux<Target, long double>();
|
||||
} else if (inp_ == typeid(char)) {
|
||||
return get_as_aux<Target, char>();
|
||||
} else if (inp_ == typeid(unsigned int)) {
|
||||
return get_as_aux<Target, unsigned int>();
|
||||
} else if (inp_ == typeid(long)) {
|
||||
return get_as_aux<Target, long>();
|
||||
} else if (inp_ == typeid(unsigned long)) {
|
||||
return get_as_aux<Target, unsigned long>();
|
||||
} else if (inp_ == typeid(std::int8_t)) {
|
||||
return get_as_aux<Target, std::int8_t>();
|
||||
} else if (inp_ == typeid(std::int16_t)) {
|
||||
return get_as_aux<Target, std::int16_t>();
|
||||
} else if (inp_ == typeid(std::int32_t)) {
|
||||
return get_as_aux<Target, std::int32_t>();
|
||||
} else if (inp_ == typeid(std::int64_t)) {
|
||||
return get_as_aux<Target, std::int64_t>();
|
||||
} else if (inp_ == typeid(std::uint8_t)) {
|
||||
return get_as_aux<Target, std::uint8_t>();
|
||||
} else if (inp_ == typeid(std::uint16_t)) {
|
||||
return get_as_aux<Target, std::uint16_t>();
|
||||
} else if (inp_ == typeid(std::uint32_t)) {
|
||||
return get_as_aux<Target, std::uint32_t>();
|
||||
} else if (inp_ == typeid(std::uint64_t)) {
|
||||
return get_as_aux<Target, std::uint64_t>();
|
||||
} else {
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
switch (get_common_type(bv)) {
|
||||
case Common_Types::t_int32:
|
||||
return get_as_aux<Target, int32_t>(bv);
|
||||
case Common_Types::t_uint8:
|
||||
return get_as_aux<Target, uint8_t>(bv);
|
||||
case Common_Types::t_int8:
|
||||
return get_as_aux<Target, int8_t>(bv);
|
||||
case Common_Types::t_uint16:
|
||||
return get_as_aux<Target, uint16_t>(bv);
|
||||
case Common_Types::t_int16:
|
||||
return get_as_aux<Target, int16_t>(bv);
|
||||
case Common_Types::t_uint32:
|
||||
return get_as_aux<Target, uint32_t>(bv);
|
||||
case Common_Types::t_uint64:
|
||||
return get_as_aux<Target, uint64_t>(bv);
|
||||
case Common_Types::t_int64:
|
||||
return get_as_aux<Target, int64_t>(bv);
|
||||
case Common_Types::t_double:
|
||||
return get_as_aux<Target, double>(bv);
|
||||
case Common_Types::t_float:
|
||||
return get_as_aux<Target, float>(bv);
|
||||
case Common_Types::t_long_double:
|
||||
return get_as_aux<Target, long double>(bv);
|
||||
}
|
||||
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
}
|
||||
|
||||
std::string to_string() const
|
||||
{
|
||||
const Type_Info &inp_ = bv.get_type_info();
|
||||
|
||||
if (inp_ == typeid(int)) {
|
||||
return to_string_aux<int>(bv);
|
||||
} else if (inp_ == typeid(double)) {
|
||||
return to_string_aux<double>(bv);
|
||||
} else if (inp_ == typeid(float)) {
|
||||
return to_string_aux<float>(bv);
|
||||
} else if (inp_ == typeid(long double)) {
|
||||
return to_string_aux<long double>(bv);
|
||||
} else if (inp_ == typeid(char)) {
|
||||
return to_string_aux<int>(Boxed_Value(get_as_aux<int, char>()));
|
||||
} else if (inp_ == typeid(unsigned int)) {
|
||||
return to_string_aux<unsigned int>(bv);
|
||||
} else if (inp_ == typeid(long)) {
|
||||
return to_string_aux<long>(bv);
|
||||
} else if (inp_ == typeid(unsigned long)) {
|
||||
return to_string_aux<unsigned long>(bv);
|
||||
} else if (inp_ == typeid(std::int8_t)) {
|
||||
return to_string_aux<int>(Boxed_Value(get_as_aux<int, std::int8_t>()));
|
||||
} else if (inp_ == typeid(std::int16_t)) {
|
||||
return to_string_aux<std::int16_t>(bv);
|
||||
} else if (inp_ == typeid(std::int32_t)) {
|
||||
return to_string_aux<std::int32_t>(bv);
|
||||
} else if (inp_ == typeid(std::int64_t)) {
|
||||
return to_string_aux<std::int64_t>(bv);
|
||||
} else if (inp_ == typeid(std::uint8_t)) {
|
||||
return to_string_aux<unsigned int>(Boxed_Value(get_as_aux<unsigned int, std::uint8_t>()));
|
||||
} else if (inp_ == typeid(std::uint16_t)) {
|
||||
return to_string_aux<std::uint16_t>(bv);
|
||||
} else if (inp_ == typeid(std::uint32_t)) {
|
||||
return to_string_aux<std::uint32_t>(bv);
|
||||
} else if (inp_ == typeid(std::uint64_t)) {
|
||||
return to_string_aux<std::uint64_t>(bv);
|
||||
} else {
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
switch (get_common_type(bv)) {
|
||||
case Common_Types::t_int32:
|
||||
return std::to_string(get_as<int32_t>());
|
||||
case Common_Types::t_uint8:
|
||||
return std::to_string(get_as<uint32_t>());
|
||||
case Common_Types::t_int8:
|
||||
return std::to_string(get_as<int32_t>());
|
||||
case Common_Types::t_uint16:
|
||||
return std::to_string(get_as<uint16_t>());
|
||||
case Common_Types::t_int16:
|
||||
return std::to_string(get_as<int16_t>());
|
||||
case Common_Types::t_uint32:
|
||||
return std::to_string(get_as<uint32_t>());
|
||||
case Common_Types::t_uint64:
|
||||
return std::to_string(get_as<uint64_t>());
|
||||
case Common_Types::t_int64:
|
||||
return std::to_string(get_as<int64_t>());
|
||||
case Common_Types::t_double:
|
||||
return to_string_aux<double>(bv);
|
||||
case Common_Types::t_float:
|
||||
return to_string_aux<float>(bv);
|
||||
case Common_Types::t_long_double:
|
||||
return to_string_aux<long double>(bv);
|
||||
}
|
||||
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
}
|
||||
|
||||
bool operator==(const Boxed_Number &t_rhs) const
|
||||
@@ -544,12 +680,12 @@ namespace chaiscript
|
||||
|
||||
Boxed_Number operator--()
|
||||
{
|
||||
return oper(Operators::pre_decrement, this->bv, var(0));
|
||||
return oper(Operators::pre_decrement, this->bv);
|
||||
}
|
||||
|
||||
Boxed_Number operator++()
|
||||
{
|
||||
return oper(Operators::pre_increment, this->bv, var(0));
|
||||
return oper(Operators::pre_increment, this->bv);
|
||||
}
|
||||
|
||||
Boxed_Number operator+(const Boxed_Number &t_rhs) const
|
||||
@@ -559,12 +695,12 @@ namespace chaiscript
|
||||
|
||||
Boxed_Number operator+() const
|
||||
{
|
||||
return oper(Operators::unary_plus, this->bv, Boxed_Value(0));
|
||||
return oper(Operators::unary_plus, this->bv);
|
||||
}
|
||||
|
||||
Boxed_Number operator-() const
|
||||
{
|
||||
return oper(Operators::unary_minus, this->bv, Boxed_Value(0));
|
||||
return oper(Operators::unary_minus, this->bv);
|
||||
}
|
||||
|
||||
Boxed_Number operator-(const Boxed_Number &t_rhs) const
|
||||
@@ -637,7 +773,7 @@ namespace chaiscript
|
||||
|
||||
Boxed_Number operator~() const
|
||||
{
|
||||
return oper(Operators::bitwise_complement, this->bv, Boxed_Value(0));
|
||||
return oper(Operators::bitwise_complement, this->bv);
|
||||
}
|
||||
|
||||
Boxed_Number operator^(const Boxed_Number &t_rhs) const
|
||||
@@ -726,12 +862,12 @@ namespace chaiscript
|
||||
|
||||
static Boxed_Number pre_decrement(Boxed_Number t_lhs)
|
||||
{
|
||||
return oper(Operators::pre_decrement, t_lhs.bv, var(0));
|
||||
return oper(Operators::pre_decrement, t_lhs.bv);
|
||||
}
|
||||
|
||||
static Boxed_Number pre_increment(Boxed_Number t_lhs)
|
||||
{
|
||||
return oper(Operators::pre_increment, t_lhs.bv, var(0));
|
||||
return oper(Operators::pre_increment, t_lhs.bv);
|
||||
}
|
||||
|
||||
static const Boxed_Number sum(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs)
|
||||
@@ -741,12 +877,12 @@ namespace chaiscript
|
||||
|
||||
static const Boxed_Number unary_plus(const Boxed_Number &t_lhs)
|
||||
{
|
||||
return oper(Operators::unary_plus, t_lhs.bv, Boxed_Value(0));
|
||||
return oper(Operators::unary_plus, t_lhs.bv);
|
||||
}
|
||||
|
||||
static const Boxed_Number unary_minus(const Boxed_Number &t_lhs)
|
||||
{
|
||||
return oper(Operators::unary_minus, t_lhs.bv, Boxed_Value(0));
|
||||
return oper(Operators::unary_minus, t_lhs.bv);
|
||||
}
|
||||
|
||||
static const Boxed_Number difference(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs)
|
||||
@@ -862,7 +998,7 @@ namespace chaiscript
|
||||
|
||||
static Boxed_Value do_oper(Operators::Opers t_oper, const Boxed_Value &t_lhs)
|
||||
{
|
||||
return oper(t_oper, t_lhs, const_var(0));
|
||||
return oper(t_oper, t_lhs);
|
||||
}
|
||||
|
||||
|
||||
@@ -878,7 +1014,7 @@ namespace chaiscript
|
||||
{
|
||||
typedef Boxed_Number Result_Type;
|
||||
|
||||
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *)
|
||||
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions_State *)
|
||||
{
|
||||
return Boxed_Number(ob);
|
||||
}
|
||||
|
@@ -1,7 +1,7 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
|
||||
// Copyright 2009-2016, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#ifndef CHAISCRIPT_BOXED_VALUE_HPP_
|
||||
@@ -231,6 +231,50 @@ namespace chaiscript
|
||||
return m_data->m_type_info.bare_equal(ti);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
struct Sentinel {
|
||||
Sentinel(std::shared_ptr<T> &ptr, Data &data)
|
||||
: m_ptr(ptr), m_data(data)
|
||||
{
|
||||
}
|
||||
|
||||
~Sentinel()
|
||||
{
|
||||
// save new pointer data
|
||||
m_data.get().m_data_ptr = m_ptr.get().get();
|
||||
m_data.get().m_const_data_ptr = m_ptr.get().get();
|
||||
}
|
||||
|
||||
Sentinel& operator=(Sentinel&&s) {
|
||||
m_ptr = std::move(s.m_ptr);
|
||||
m_data = std::move(s.m_data);
|
||||
}
|
||||
|
||||
Sentinel(Sentinel &&s)
|
||||
: m_ptr(std::move(s.m_ptr)),
|
||||
m_data(std::move(s.m_data))
|
||||
{
|
||||
}
|
||||
|
||||
operator std::shared_ptr<T>&() const
|
||||
{
|
||||
return m_ptr.get();
|
||||
}
|
||||
|
||||
Sentinel &operator=(const Sentinel &) = delete;
|
||||
Sentinel(Sentinel&) = delete;
|
||||
|
||||
std::reference_wrapper<std::shared_ptr<T>> m_ptr;
|
||||
std::reference_wrapper<Data> m_data;
|
||||
};
|
||||
|
||||
|
||||
template<typename T>
|
||||
Sentinel<T> pointer_sentinel(std::shared_ptr<T> &ptr) const
|
||||
{
|
||||
return Sentinel<T>(ptr, *(m_data.get()));
|
||||
}
|
||||
|
||||
bool is_null() const CHAISCRIPT_NOEXCEPT
|
||||
{
|
||||
return (m_data->m_data_ptr == nullptr && m_data->m_const_data_ptr == nullptr);
|
||||
@@ -297,6 +341,13 @@ namespace chaiscript
|
||||
return *this;
|
||||
}
|
||||
|
||||
Boxed_Value &clone_attrs(const Boxed_Value &t_obj)
|
||||
{
|
||||
copy_attrs(t_obj);
|
||||
reset_return_value();
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
/// \returns true if the two Boxed_Values share the same internal type
|
||||
static bool type_match(const Boxed_Value &l, const Boxed_Value &r) CHAISCRIPT_NOEXCEPT
|
||||
@@ -330,9 +381,9 @@ namespace chaiscript
|
||||
///
|
||||
/// @sa @ref adding_objects
|
||||
template<typename T>
|
||||
Boxed_Value var(T t)
|
||||
Boxed_Value var(T &&t)
|
||||
{
|
||||
return Boxed_Value(t);
|
||||
return Boxed_Value(std::forward<T>(t));
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
|
107
include/chaiscript/dispatchkit/callable_traits.hpp
Normal file
107
include/chaiscript/dispatchkit/callable_traits.hpp
Normal file
@@ -0,0 +1,107 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// Copyright 2009-2016, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#ifndef CHAISCRIPT_CALLABLE_TRAITS_HPP_
|
||||
#define CHAISCRIPT_CALLABLE_TRAITS_HPP_
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace chaiscript {
|
||||
namespace dispatch {
|
||||
namespace detail {
|
||||
|
||||
template<typename Class, typename ... Param>
|
||||
struct Constructor
|
||||
{
|
||||
template<typename ... Inner>
|
||||
std::shared_ptr<Class> operator()(Inner&& ... inner) const {
|
||||
return std::make_shared<Class>(std::forward<Inner>(inner)...);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Ret, typename Class, typename ... Param>
|
||||
struct Const_Caller
|
||||
{
|
||||
Const_Caller(Ret (Class::*t_func)(Param...) const) : m_func(t_func) {}
|
||||
|
||||
template<typename ... Inner>
|
||||
Ret operator()(const Class &o, Inner&& ... inner) const {
|
||||
return (o.*m_func)(std::forward<Inner>(inner)...);
|
||||
}
|
||||
|
||||
Ret (Class::*m_func)(Param...) const;
|
||||
};
|
||||
|
||||
template<typename Ret, typename ... Param>
|
||||
struct Fun_Caller
|
||||
{
|
||||
Fun_Caller(Ret( * t_func)(Param...) ) : m_func(t_func) {}
|
||||
|
||||
template<typename ... Inner>
|
||||
Ret operator()(Inner&& ... inner) const {
|
||||
return (m_func)(std::forward<Inner>(inner)...);
|
||||
}
|
||||
|
||||
Ret(*m_func)(Param...);
|
||||
};
|
||||
|
||||
template<typename Ret, typename Class, typename ... Param>
|
||||
struct Caller
|
||||
{
|
||||
Caller(Ret (Class::*t_func)(Param...)) : m_func(t_func) {}
|
||||
|
||||
template<typename ... Inner>
|
||||
Ret operator()(Class &o, Inner&& ... inner) const {
|
||||
return (o.*m_func)(std::forward<Inner>(inner)...);
|
||||
}
|
||||
|
||||
Ret (Class::*m_func)(Param...);
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct Arity
|
||||
{
|
||||
};
|
||||
|
||||
template<typename Ret, typename ... Params>
|
||||
struct Arity<Ret (Params...)>
|
||||
{
|
||||
static const size_t arity = sizeof...(Params);
|
||||
};
|
||||
|
||||
|
||||
template<typename T>
|
||||
struct Function_Signature
|
||||
{
|
||||
};
|
||||
|
||||
template<typename Ret, typename ... Params>
|
||||
struct Function_Signature<Ret (Params...)>
|
||||
{
|
||||
typedef Ret Return_Type;
|
||||
typedef Ret (Signature)(Params...);
|
||||
};
|
||||
|
||||
template<typename Ret, typename T, typename ... Params>
|
||||
struct Function_Signature<Ret (T::*)(Params...) const>
|
||||
{
|
||||
typedef Ret Return_Type;
|
||||
typedef Ret (Signature)(Params...);
|
||||
};
|
||||
|
||||
|
||||
template<typename T>
|
||||
struct Callable_Traits
|
||||
{
|
||||
typedef typename Function_Signature<decltype(&T::operator())>::Signature Signature;
|
||||
typedef typename Function_Signature<decltype(&T::operator())>::Return_Type Return_Type;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@@ -1,7 +1,7 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
|
||||
// Copyright 2009-2016, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#ifndef CHAISCRIPT_DISPATCHKIT_HPP_
|
||||
@@ -22,6 +22,7 @@
|
||||
|
||||
#include "../chaiscript_defines.hpp"
|
||||
#include "../chaiscript_threading.hpp"
|
||||
#include "bad_boxed_cast.hpp"
|
||||
#include "boxed_cast.hpp"
|
||||
#include "boxed_cast_helper.hpp"
|
||||
#include "boxed_value.hpp"
|
||||
@@ -313,7 +314,7 @@ namespace chaiscript
|
||||
return arity;
|
||||
}
|
||||
|
||||
virtual bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
|
||||
virtual bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const CHAISCRIPT_OVERRIDE
|
||||
{
|
||||
return std::any_of(m_funcs.cbegin(), m_funcs.cend(),
|
||||
[&vals, &t_conversions](const Proxy_Function &f){ return f->call_match(vals, t_conversions); });
|
||||
@@ -325,7 +326,7 @@ namespace chaiscript
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual Boxed_Value do_call(const std::vector<Boxed_Value> ¶ms, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
|
||||
virtual Boxed_Value do_call(const std::vector<Boxed_Value> ¶ms, const Type_Conversions_State &t_conversions) const CHAISCRIPT_OVERRIDE
|
||||
{
|
||||
return dispatch::dispatch(m_funcs, params, t_conversions);
|
||||
}
|
||||
@@ -384,19 +385,41 @@ namespace chaiscript
|
||||
|
||||
namespace detail
|
||||
{
|
||||
struct Stack_Holder
|
||||
{
|
||||
typedef std::vector<std::pair<std::string, Boxed_Value>> Scope;
|
||||
typedef std::vector<Scope> StackData;
|
||||
|
||||
Stack_Holder()
|
||||
: call_depth(0)
|
||||
{
|
||||
stacks.reserve(2);
|
||||
stacks.emplace_back(1);
|
||||
call_params.emplace_back();
|
||||
call_params.back().reserve(2);
|
||||
}
|
||||
|
||||
std::vector<StackData> stacks;
|
||||
|
||||
std::vector<std::vector<Boxed_Value>> call_params;
|
||||
int call_depth;
|
||||
};
|
||||
|
||||
/// Main class for the dispatchkit. Handles management
|
||||
/// of the object stack, functions and registered types.
|
||||
class Dispatch_Engine
|
||||
{
|
||||
|
||||
public:
|
||||
typedef std::map<std::string, chaiscript::Type_Info> Type_Name_Map;
|
||||
typedef std::map<std::string, Boxed_Value> Scope;
|
||||
typedef std::vector<std::pair<std::string, Boxed_Value>> Scope;
|
||||
typedef std::vector<Scope> StackData;
|
||||
|
||||
struct State
|
||||
{
|
||||
std::map<std::string, std::vector<Proxy_Function> > m_functions;
|
||||
std::map<std::string, Proxy_Function> m_function_objects;
|
||||
std::vector<std::pair<std::string, std::shared_ptr<std::vector<Proxy_Function>>>> m_functions;
|
||||
std::vector<std::pair<std::string, Proxy_Function>> m_function_objects;
|
||||
std::vector<std::pair<std::string, Boxed_Value>> m_boxed_functions;
|
||||
std::map<std::string, Boxed_Value> m_global_objects;
|
||||
Type_Name_Map m_types;
|
||||
std::set<std::string> m_reserved_words;
|
||||
@@ -408,7 +431,7 @@ namespace chaiscript
|
||||
|
||||
Dispatch_Engine()
|
||||
: m_stack_holder(this),
|
||||
m_place_holder(std::make_shared<dispatch::Placeholder_Object>())
|
||||
m_method_missing_loc(0)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -420,7 +443,8 @@ namespace chaiscript
|
||||
template<typename Type>
|
||||
typename detail::Cast_Helper<Type>::Result_Type boxed_cast(const Boxed_Value &bv) const
|
||||
{
|
||||
return chaiscript::boxed_cast<Type>(bv, &m_conversions);
|
||||
Type_Conversions_State state(m_conversions, m_conversions.conversion_saves());
|
||||
return chaiscript::boxed_cast<Type>(bv, &state);
|
||||
}
|
||||
|
||||
/// Add a new conversion for upcasting to a base class
|
||||
@@ -438,14 +462,18 @@ namespace chaiscript
|
||||
|
||||
/// Set the value of an object, by name. If the object
|
||||
/// is not available in the current scope it is created
|
||||
void add(const Boxed_Value &obj, const std::string &name)
|
||||
void add(Boxed_Value obj, const std::string &name)
|
||||
{
|
||||
validate_object_name(name);
|
||||
auto &stack = get_stack_data();
|
||||
|
||||
for (auto stack_elem = stack.rbegin(); stack_elem != stack.rend(); ++stack_elem)
|
||||
{
|
||||
auto itr = stack_elem->find(name);
|
||||
auto itr = std::find_if(stack_elem->begin(), stack_elem->end(),
|
||||
[&](const std::pair<std::string, Boxed_Value> &o) {
|
||||
return o.first == name;
|
||||
});
|
||||
|
||||
if (itr != stack_elem->end())
|
||||
{
|
||||
itr->second = std::move(obj);
|
||||
@@ -456,16 +484,31 @@ namespace chaiscript
|
||||
add_object(name, std::move(obj));
|
||||
}
|
||||
|
||||
/// Adds a named object to the current scope
|
||||
/// \warning This version does not check the validity of the name
|
||||
/// it is meant for internal use only
|
||||
void add_object(const std::string &t_name, Boxed_Value obj, Stack_Holder &t_holder)
|
||||
{
|
||||
auto &stack_elem = get_stack_data(t_holder).back();
|
||||
|
||||
if (std::any_of(stack_elem.begin(), stack_elem.end(),
|
||||
[&](const std::pair<std::string, Boxed_Value> &o) {
|
||||
return o.first == t_name;
|
||||
}))
|
||||
{
|
||||
throw chaiscript::exception::name_conflict_error(t_name);
|
||||
}
|
||||
|
||||
get_stack_data(t_holder).back().emplace_back(t_name, std::move(obj));
|
||||
}
|
||||
|
||||
|
||||
/// Adds a named object to the current scope
|
||||
/// \warning This version does not check the validity of the name
|
||||
/// it is meant for internal use only
|
||||
void add_object(const std::string &name, const Boxed_Value &obj)
|
||||
void add_object(const std::string &name, Boxed_Value obj)
|
||||
{
|
||||
if (!get_stack_data().back().insert(std::make_pair(name, obj)).second)
|
||||
{
|
||||
throw chaiscript::exception::name_conflict_error(name);
|
||||
}
|
||||
add_object(name, std::move(obj), get_stack_holder());
|
||||
}
|
||||
|
||||
/// Adds a new global shared object, between all the threads
|
||||
@@ -477,7 +520,7 @@ namespace chaiscript
|
||||
throw chaiscript::exception::global_non_const();
|
||||
}
|
||||
|
||||
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l(m_global_object_mutex);
|
||||
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
|
||||
|
||||
if (m_state.m_global_objects.find(name) != m_state.m_global_objects.end())
|
||||
{
|
||||
@@ -492,7 +535,7 @@ namespace chaiscript
|
||||
{
|
||||
validate_object_name(name);
|
||||
|
||||
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l(m_global_object_mutex);
|
||||
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
|
||||
|
||||
const auto itr = m_state.m_global_objects.find(name);
|
||||
if (itr == m_state.m_global_objects.end())
|
||||
@@ -510,7 +553,7 @@ namespace chaiscript
|
||||
{
|
||||
validate_object_name(name);
|
||||
|
||||
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l(m_global_object_mutex);
|
||||
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
|
||||
|
||||
if (m_state.m_global_objects.find(name) != m_state.m_global_objects.end())
|
||||
{
|
||||
@@ -520,19 +563,46 @@ namespace chaiscript
|
||||
}
|
||||
}
|
||||
|
||||
/// Updates an existing global shared object or adds a new global shared object if not found
|
||||
void set_global(const Boxed_Value &obj, const std::string &name)
|
||||
{
|
||||
validate_object_name(name);
|
||||
|
||||
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
|
||||
|
||||
const auto itr = m_state.m_global_objects.find(name);
|
||||
if (itr != m_state.m_global_objects.end())
|
||||
{
|
||||
itr->second.assign(obj);
|
||||
} else {
|
||||
m_state.m_global_objects.insert(std::make_pair(name, obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// Adds a new scope to the stack
|
||||
void new_scope()
|
||||
{
|
||||
get_stack_data().emplace_back();
|
||||
m_stack_holder->call_params.emplace_back();
|
||||
new_scope(*m_stack_holder);
|
||||
}
|
||||
|
||||
/// Pops the current scope from the stack
|
||||
void pop_scope()
|
||||
{
|
||||
m_stack_holder->call_params.pop_back();
|
||||
StackData &stack = get_stack_data();
|
||||
pop_scope(*m_stack_holder);
|
||||
}
|
||||
|
||||
/// Adds a new scope to the stack
|
||||
static void new_scope(Stack_Holder &t_holder)
|
||||
{
|
||||
get_stack_data(t_holder).emplace_back();
|
||||
t_holder.call_params.emplace_back();
|
||||
}
|
||||
|
||||
/// Pops the current scope from the stack
|
||||
static void pop_scope(Stack_Holder &t_holder)
|
||||
{
|
||||
t_holder.call_params.pop_back();
|
||||
StackData &stack = get_stack_data(t_holder);
|
||||
if (stack.size() > 1)
|
||||
{
|
||||
stack.pop_back();
|
||||
@@ -543,53 +613,72 @@ namespace chaiscript
|
||||
|
||||
|
||||
/// Pushes a new stack on to the list of stacks
|
||||
void new_stack()
|
||||
static void new_stack(Stack_Holder &t_holder)
|
||||
{
|
||||
// add a new Stack with 1 element
|
||||
m_stack_holder->stacks.emplace_back(1);
|
||||
t_holder.stacks.emplace_back(1);
|
||||
}
|
||||
|
||||
void pop_stack()
|
||||
static void pop_stack(Stack_Holder &t_holder)
|
||||
{
|
||||
m_stack_holder->stacks.pop_back();
|
||||
t_holder.stacks.pop_back();
|
||||
}
|
||||
|
||||
/// Searches the current stack for an object of the given name
|
||||
/// includes a special overload for the _ place holder object to
|
||||
/// ensure that it is always in scope.
|
||||
Boxed_Value get_object(const std::string &name) const
|
||||
Boxed_Value get_object(const std::string &name, std::atomic_uint_fast32_t &t_loc) const
|
||||
{
|
||||
// Is it a placeholder object?
|
||||
if (name == "_")
|
||||
{
|
||||
return m_place_holder;
|
||||
}
|
||||
enum class Loc : uint_fast32_t {
|
||||
located = 0x80000000,
|
||||
is_local = 0x40000000,
|
||||
stack_mask = 0x0FFF0000,
|
||||
loc_mask = 0x0000FFFF
|
||||
};
|
||||
|
||||
auto &stack = get_stack_data();
|
||||
uint_fast32_t loc = t_loc;
|
||||
|
||||
// Is it in the stack?
|
||||
for (auto stack_elem = stack.rbegin(); stack_elem != stack.rend(); ++stack_elem)
|
||||
if (loc == 0)
|
||||
{
|
||||
const auto stackitr = stack_elem->find(name);
|
||||
if (stackitr != stack_elem->end())
|
||||
auto &stack = get_stack_data();
|
||||
|
||||
// Is it in the stack?
|
||||
for (auto stack_elem = stack.rbegin(); stack_elem != stack.rend(); ++stack_elem)
|
||||
{
|
||||
return stackitr->second;
|
||||
for (auto s = stack_elem->begin(); s != stack_elem->end(); ++s )
|
||||
{
|
||||
if (s->first == name) {
|
||||
t_loc = static_cast<uint_fast32_t>(std::distance(stack.rbegin(), stack_elem) << 16)
|
||||
| static_cast<uint_fast32_t>(std::distance(stack_elem->begin(), s))
|
||||
| static_cast<uint_fast32_t>(Loc::located)
|
||||
| static_cast<uint_fast32_t>(Loc::is_local);
|
||||
return s->second;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
t_loc = static_cast<uint_fast32_t>(Loc::located);
|
||||
} else if (loc & static_cast<uint_fast32_t>(Loc::is_local)) {
|
||||
auto &stack = get_stack_data();
|
||||
|
||||
return stack[stack.size() - 1 - ((loc & static_cast<uint_fast32_t>(Loc::stack_mask)) >> 16)][loc & static_cast<uint_fast32_t>(Loc::loc_mask)].second;
|
||||
}
|
||||
|
||||
// Is the value we are looking for a global?
|
||||
// Is the value we are looking for a global or function?
|
||||
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
|
||||
|
||||
const auto itr = m_state.m_global_objects.find(name);
|
||||
if (itr != m_state.m_global_objects.end())
|
||||
{
|
||||
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_global_object_mutex);
|
||||
|
||||
const auto itr = m_state.m_global_objects.find(name);
|
||||
if (itr != m_state.m_global_objects.end())
|
||||
{
|
||||
return itr->second;
|
||||
}
|
||||
return itr->second;
|
||||
}
|
||||
|
||||
// If all that failed, then check to see if it's a function
|
||||
return get_function_object(name);
|
||||
// no? is it a function object?
|
||||
auto obj = get_function_object_int(name, loc);
|
||||
if (obj.first != loc) t_loc = uint_fast32_t(obj.first);
|
||||
return obj.second;
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// Registers a new named type
|
||||
@@ -647,20 +736,29 @@ namespace chaiscript
|
||||
return std::vector<std::pair<std::string, Type_Info> >(m_state.m_types.begin(), m_state.m_types.end());
|
||||
}
|
||||
|
||||
std::shared_ptr<std::vector<Proxy_Function>> get_method_missing_functions() const
|
||||
{
|
||||
uint_fast32_t method_missing_loc = m_method_missing_loc;
|
||||
auto method_missing_funs = get_function("method_missing", method_missing_loc);
|
||||
if (method_missing_funs.first != method_missing_loc) m_method_missing_loc = uint_fast32_t(method_missing_funs.first);
|
||||
return std::move(method_missing_funs.second);
|
||||
}
|
||||
|
||||
|
||||
/// Return a function by name
|
||||
std::vector< Proxy_Function > get_function(const std::string &t_name) const
|
||||
std::pair<size_t, std::shared_ptr<std::vector< Proxy_Function>>> get_function(const std::string &t_name, const size_t t_hint) const
|
||||
{
|
||||
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
|
||||
|
||||
const auto &funs = get_functions_int();
|
||||
|
||||
auto itr = funs.find(t_name);
|
||||
auto itr = find_keyed_value(funs, t_name, t_hint);
|
||||
|
||||
if (itr != funs.end())
|
||||
{
|
||||
return itr->second;
|
||||
return std::make_pair(std::distance(funs.begin(), itr), itr->second);
|
||||
} else {
|
||||
return std::vector<Proxy_Function>();
|
||||
return std::make_pair(size_t(0), std::make_shared<std::vector<Proxy_Function>>());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -668,28 +766,36 @@ namespace chaiscript
|
||||
/// \throws std::range_error if it does not
|
||||
Boxed_Value get_function_object(const std::string &t_name) const
|
||||
{
|
||||
// std::cout << "Getting function object: " << t_name << '\n';
|
||||
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
|
||||
|
||||
const auto &funs = get_function_objects_int();
|
||||
return get_function_object_int(t_name, 0).second;
|
||||
}
|
||||
|
||||
auto itr = funs.find(t_name);
|
||||
/// \returns a function object (Boxed_Value wrapper) if it exists
|
||||
/// \throws std::range_error if it does not
|
||||
/// \warn does not obtain a mutex lock. \sa get_function_object for public version
|
||||
std::pair<size_t, Boxed_Value> get_function_object_int(const std::string &t_name, const size_t t_hint) const
|
||||
{
|
||||
const auto &funs = get_boxed_functions_int();
|
||||
|
||||
auto itr = find_keyed_value(funs, t_name, t_hint);
|
||||
|
||||
if (itr != funs.end())
|
||||
{
|
||||
return const_var(itr->second);
|
||||
return std::make_pair(std::distance(funs.begin(), itr), itr->second);
|
||||
} else {
|
||||
throw std::range_error("Object not found: " + t_name);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Return true if a function exists
|
||||
bool function_exists(const std::string &name) const
|
||||
{
|
||||
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
|
||||
|
||||
const auto &functions = get_functions_int();
|
||||
return functions.find(name) != functions.end();
|
||||
return find_keyed_value(functions, name) != functions.end();
|
||||
}
|
||||
|
||||
/// \returns All values in the local thread state in the parent scope, or if it doesn't exist,
|
||||
@@ -699,9 +805,9 @@ namespace chaiscript
|
||||
auto &stack = get_stack_data();
|
||||
if (stack.size() > 1)
|
||||
{
|
||||
return stack[1];
|
||||
return std::map<std::string, Boxed_Value>(stack[1].begin(), stack[1].end());
|
||||
} else {
|
||||
return stack[0];
|
||||
return std::map<std::string, Boxed_Value>(stack[0].begin(), stack[0].end());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -710,7 +816,7 @@ namespace chaiscript
|
||||
{
|
||||
auto &stack = get_stack_data();
|
||||
auto &scope = stack.front();
|
||||
return scope;
|
||||
return std::map<std::string, Boxed_Value>(scope.begin(), scope.end());
|
||||
}
|
||||
|
||||
/// \brief Sets all of the locals for the current thread state.
|
||||
@@ -722,7 +828,7 @@ namespace chaiscript
|
||||
{
|
||||
auto &stack = get_stack_data();
|
||||
auto &scope = stack.front();
|
||||
scope = t_locals;
|
||||
scope = std::vector<std::pair<std::string, Boxed_Value>>(t_locals.begin(), t_locals.end());
|
||||
}
|
||||
|
||||
|
||||
@@ -746,11 +852,8 @@ namespace chaiscript
|
||||
}
|
||||
|
||||
// add the global values
|
||||
{
|
||||
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_global_object_mutex);
|
||||
|
||||
retval.insert(m_state.m_global_objects.begin(), m_state.m_global_objects.end());
|
||||
}
|
||||
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
|
||||
retval.insert(m_state.m_global_objects.begin(), m_state.m_global_objects.end());
|
||||
|
||||
return retval;
|
||||
}
|
||||
@@ -787,7 +890,7 @@ namespace chaiscript
|
||||
|
||||
for (const auto & function : functions)
|
||||
{
|
||||
for (const auto & internal_func : function.second)
|
||||
for (const auto & internal_func : *function.second)
|
||||
{
|
||||
rets.emplace_back(function.first, internal_func);
|
||||
}
|
||||
@@ -808,8 +911,8 @@ namespace chaiscript
|
||||
return m_conversions;
|
||||
}
|
||||
|
||||
bool is_attribute_call(const std::vector<Proxy_Function> &t_funs, const std::vector<Boxed_Value> &t_params,
|
||||
bool t_has_params) const
|
||||
static bool is_attribute_call(const std::vector<Proxy_Function> &t_funs, const std::vector<Boxed_Value> &t_params,
|
||||
bool t_has_params, const Type_Conversions_State &t_conversions)
|
||||
{
|
||||
if (!t_has_params || t_params.empty()) {
|
||||
return false;
|
||||
@@ -817,7 +920,7 @@ namespace chaiscript
|
||||
|
||||
for (const auto &fun : t_funs) {
|
||||
if (fun->is_attribute_function()) {
|
||||
if (fun->compare_first_type(t_params[0], m_conversions)) {
|
||||
if (fun->compare_first_type(t_params[0], t_conversions)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -832,31 +935,61 @@ namespace chaiscript
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4715)
|
||||
#endif
|
||||
Boxed_Value call_member(const std::string &t_name, const std::vector<Boxed_Value> ¶ms, bool t_has_params) const
|
||||
Boxed_Value call_member(const std::string &t_name, std::atomic_uint_fast32_t &t_loc, const std::vector<Boxed_Value> ¶ms, bool t_has_params,
|
||||
const Type_Conversions_State &t_conversions)
|
||||
{
|
||||
const auto funs = get_function(t_name);
|
||||
uint_fast32_t loc = t_loc;
|
||||
const auto funs = get_function(t_name, loc);
|
||||
if (funs.first != loc) t_loc = uint_fast32_t(funs.first);
|
||||
|
||||
const auto do_attribute_call =
|
||||
[this](int l_num_params, const std::vector<Boxed_Value> &l_params, const std::vector<Proxy_Function> &l_funs, const Type_Conversions &l_conversions)->Boxed_Value
|
||||
[this](int l_num_params, const std::vector<Boxed_Value> &l_params, const std::vector<Proxy_Function> &l_funs, const Type_Conversions_State &l_conversions)->Boxed_Value
|
||||
{
|
||||
std::vector<Boxed_Value> attr_params{l_params.begin(), l_params.begin() + l_num_params};
|
||||
std::vector<Boxed_Value> remaining_params{l_params.begin() + l_num_params, l_params.end()};
|
||||
Boxed_Value bv = dispatch::dispatch(l_funs, attr_params, l_conversions);
|
||||
if (!remaining_params.empty() || bv.get_type_info().bare_equal(user_type<dispatch::Proxy_Function_Base>())) {
|
||||
return (*boxed_cast<const dispatch::Proxy_Function_Base *>(bv))(remaining_params, l_conversions);
|
||||
if (l_num_params < int(l_params.size()) || bv.get_type_info().bare_equal(user_type<dispatch::Proxy_Function_Base>())) {
|
||||
struct This_Foist {
|
||||
This_Foist(Dispatch_Engine &e, const Boxed_Value &t_bv) : m_e(e) {
|
||||
m_e.get().new_scope();
|
||||
m_e.get().add_object("__this", t_bv);
|
||||
}
|
||||
|
||||
~This_Foist() {
|
||||
m_e.get().pop_scope();
|
||||
}
|
||||
|
||||
std::reference_wrapper<Dispatch_Engine> m_e;
|
||||
};
|
||||
|
||||
This_Foist fi(*this, l_params.front());
|
||||
|
||||
try {
|
||||
auto func = boxed_cast<std::shared_ptr<const dispatch::Proxy_Function_Base>>(bv);
|
||||
try {
|
||||
return (*func)({l_params.begin() + l_num_params, l_params.end()}, l_conversions);
|
||||
} catch (const chaiscript::exception::bad_boxed_cast &) {
|
||||
} catch (const chaiscript::exception::arity_error &) {
|
||||
} catch (const chaiscript::exception::guard_error &) {
|
||||
}
|
||||
throw chaiscript::exception::dispatch_error({l_params.begin() + l_num_params, l_params.end()}, std::vector<Const_Proxy_Function>{func});
|
||||
} catch (const chaiscript::exception::bad_boxed_cast &) {
|
||||
// unable to convert bv into a Proxy_Function_Base
|
||||
throw chaiscript::exception::dispatch_error({l_params.begin() + l_num_params, l_params.end()},
|
||||
std::vector<Const_Proxy_Function>(l_funs.begin(), l_funs.end()));
|
||||
}
|
||||
} else {
|
||||
return bv;
|
||||
}
|
||||
};
|
||||
|
||||
if (is_attribute_call(funs, params, t_has_params)) {
|
||||
return do_attribute_call(1, params, funs, m_conversions);
|
||||
if (is_attribute_call(*funs.second, params, t_has_params, t_conversions)) {
|
||||
return do_attribute_call(1, params, *funs.second, t_conversions);
|
||||
} else {
|
||||
std::exception_ptr except;
|
||||
|
||||
if (!funs.empty()) {
|
||||
if (!funs.second->empty()) {
|
||||
try {
|
||||
return dispatch::dispatch(funs, params, m_conversions);
|
||||
return dispatch::dispatch(*funs.second, params, t_conversions);
|
||||
} catch(chaiscript::exception::dispatch_error&) {
|
||||
except = std::current_exception();
|
||||
}
|
||||
@@ -868,9 +1001,11 @@ namespace chaiscript
|
||||
const auto functions = [&]()->std::vector<Proxy_Function> {
|
||||
std::vector<Proxy_Function> fs;
|
||||
|
||||
for (const auto &f : get_function("method_missing"))
|
||||
const auto method_missing_funs = get_method_missing_functions();
|
||||
|
||||
for (const auto &f : *method_missing_funs)
|
||||
{
|
||||
if(f->compare_first_type(params[0], m_conversions)) {
|
||||
if(f->compare_first_type(params[0], t_conversions)) {
|
||||
fs.push_back(f);
|
||||
}
|
||||
}
|
||||
@@ -890,12 +1025,17 @@ namespace chaiscript
|
||||
}();
|
||||
|
||||
if (!functions.empty()) {
|
||||
if (is_no_param) {
|
||||
std::vector<Boxed_Value> tmp_params(params);
|
||||
tmp_params.insert(tmp_params.begin() + 1, var(t_name));
|
||||
return do_attribute_call(2, tmp_params, functions, m_conversions);
|
||||
} else {
|
||||
return dispatch::dispatch(functions, {params[0], var(t_name), var(std::vector<Boxed_Value>(params.begin()+1, params.end()))}, m_conversions);
|
||||
try {
|
||||
if (is_no_param) {
|
||||
std::vector<Boxed_Value> tmp_params(params);
|
||||
tmp_params.insert(tmp_params.begin() + 1, var(t_name));
|
||||
return do_attribute_call(2, tmp_params, functions, t_conversions);
|
||||
} else {
|
||||
return dispatch::dispatch(functions, {params[0], var(t_name), var(std::vector<Boxed_Value>(params.begin()+1, params.end()))}, t_conversions);
|
||||
}
|
||||
} catch (const dispatch::option_explicit_set &e) {
|
||||
throw chaiscript::exception::dispatch_error(params, std::vector<Const_Proxy_Function>(funs.second->begin(), funs.second->end()),
|
||||
e.what());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -904,7 +1044,7 @@ namespace chaiscript
|
||||
if (except) {
|
||||
std::rethrow_exception(except);
|
||||
} else {
|
||||
throw chaiscript::exception::dispatch_error(params, std::vector<Const_Proxy_Function>(funs.begin(), funs.end()));
|
||||
throw chaiscript::exception::dispatch_error(params, std::vector<Const_Proxy_Function>(funs.second->begin(), funs.second->end()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -914,30 +1054,15 @@ namespace chaiscript
|
||||
|
||||
|
||||
|
||||
Boxed_Value call_function(const std::string &t_name, const std::vector<Boxed_Value> ¶ms) const
|
||||
Boxed_Value call_function(const std::string &t_name, std::atomic_uint_fast32_t &t_loc, const std::vector<Boxed_Value> ¶ms,
|
||||
const Type_Conversions_State &t_conversions) const
|
||||
{
|
||||
Boxed_Value bv = dispatch::dispatch(get_function(t_name), params, m_conversions);
|
||||
// the result of a clone is never to be marked as a return_value
|
||||
if (t_name == "clone") {
|
||||
bv.reset_return_value();
|
||||
}
|
||||
return bv;
|
||||
uint_fast32_t loc = t_loc;
|
||||
const auto funs = get_function(t_name, loc);
|
||||
if (funs.first != loc) t_loc = uint_fast32_t(funs.first);
|
||||
return dispatch::dispatch(*funs.second, params, t_conversions);
|
||||
}
|
||||
|
||||
Boxed_Value call_function(const std::string &t_name) const
|
||||
{
|
||||
return call_function(t_name, std::vector<Boxed_Value>());
|
||||
}
|
||||
|
||||
Boxed_Value call_function(const std::string &t_name, Boxed_Value p1) const
|
||||
{
|
||||
return call_function(t_name, std::vector<Boxed_Value>({std::move(p1)}));
|
||||
}
|
||||
|
||||
Boxed_Value call_function(const std::string &t_name, Boxed_Value p1, Boxed_Value p2) const
|
||||
{
|
||||
return call_function(t_name, std::vector<Boxed_Value>({std::move(p1), std::move(p2)}));
|
||||
}
|
||||
|
||||
/// Dump object info to stdout
|
||||
void dump_object(const Boxed_Value &o) const
|
||||
@@ -981,7 +1106,7 @@ namespace chaiscript
|
||||
|
||||
/// Returns true if a call can be made that consists of the first parameter
|
||||
/// (the function) with the remaining parameters as its arguments.
|
||||
Boxed_Value call_exists(const std::vector<Boxed_Value> ¶ms)
|
||||
Boxed_Value call_exists(const std::vector<Boxed_Value> ¶ms) const
|
||||
{
|
||||
if (params.empty())
|
||||
{
|
||||
@@ -989,8 +1114,9 @@ namespace chaiscript
|
||||
}
|
||||
|
||||
const Const_Proxy_Function &f = this->boxed_cast<Const_Proxy_Function>(params[0]);
|
||||
const Type_Conversions_State convs(m_conversions, m_conversions.conversion_saves());
|
||||
|
||||
return Boxed_Value(f->call_match(std::vector<Boxed_Value>(params.begin() + 1, params.end()), m_conversions));
|
||||
return Boxed_Value(f->call_match(std::vector<Boxed_Value>(params.begin() + 1, params.end()), convs));
|
||||
}
|
||||
|
||||
/// Dump all system info to stdout
|
||||
@@ -1048,7 +1174,6 @@ namespace chaiscript
|
||||
State get_state() const
|
||||
{
|
||||
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
|
||||
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l2(m_global_object_mutex);
|
||||
|
||||
return m_state;
|
||||
}
|
||||
@@ -1056,61 +1181,83 @@ namespace chaiscript
|
||||
void set_state(const State &t_state)
|
||||
{
|
||||
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
|
||||
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l2(m_global_object_mutex);
|
||||
|
||||
m_state = t_state;
|
||||
}
|
||||
|
||||
static void save_function_params(Stack_Holder &t_s, std::initializer_list<Boxed_Value> t_params)
|
||||
{
|
||||
t_s.call_params.back().insert(t_s.call_params.back().begin(), std::move(t_params));
|
||||
}
|
||||
|
||||
static void save_function_params(Stack_Holder &t_s, std::vector<Boxed_Value> &&t_params)
|
||||
{
|
||||
for (auto &¶m : t_params)
|
||||
{
|
||||
t_s.call_params.back().insert(t_s.call_params.back().begin(), std::move(param));
|
||||
}
|
||||
}
|
||||
|
||||
static void save_function_params(Stack_Holder &t_s, const std::vector<Boxed_Value> &t_params)
|
||||
{
|
||||
t_s.call_params.back().insert(t_s.call_params.back().begin(), t_params.begin(), t_params.end());
|
||||
}
|
||||
|
||||
void save_function_params(std::initializer_list<Boxed_Value> t_params)
|
||||
{
|
||||
Stack_Holder &s = *m_stack_holder;
|
||||
s.call_params.back().insert(s.call_params.back().begin(), std::move(t_params));
|
||||
save_function_params(*m_stack_holder, std::move(t_params));
|
||||
}
|
||||
|
||||
void save_function_params(std::vector<Boxed_Value> &&t_params)
|
||||
{
|
||||
Stack_Holder &s = *m_stack_holder;
|
||||
|
||||
for (auto &¶m : t_params)
|
||||
{
|
||||
s.call_params.back().insert(s.call_params.back().begin(), std::move(param));
|
||||
}
|
||||
save_function_params(*m_stack_holder, std::move(t_params));
|
||||
}
|
||||
|
||||
void save_function_params(const std::vector<Boxed_Value> &t_params)
|
||||
{
|
||||
Stack_Holder &s = *m_stack_holder;
|
||||
s.call_params.back().insert(s.call_params.back().begin(), t_params.begin(), t_params.end());
|
||||
save_function_params(*m_stack_holder, t_params);
|
||||
}
|
||||
|
||||
void new_function_call(Stack_Holder &t_s, Type_Conversions::Conversion_Saves &t_saves)
|
||||
{
|
||||
if (t_s.call_depth == 0)
|
||||
{
|
||||
m_conversions.enable_conversion_saves(t_saves, true);
|
||||
}
|
||||
|
||||
++t_s.call_depth;
|
||||
|
||||
save_function_params(m_conversions.take_saves(t_saves));
|
||||
}
|
||||
|
||||
void pop_function_call(Stack_Holder &t_s, Type_Conversions::Conversion_Saves &t_saves)
|
||||
{
|
||||
--t_s.call_depth;
|
||||
|
||||
assert(t_s.call_depth >= 0);
|
||||
|
||||
if (t_s.call_depth == 0)
|
||||
{
|
||||
t_s.call_params.back().clear();
|
||||
m_conversions.enable_conversion_saves(t_saves, false);
|
||||
}
|
||||
}
|
||||
|
||||
void new_function_call()
|
||||
{
|
||||
Stack_Holder &s = *m_stack_holder;
|
||||
if (s.call_depth == 0)
|
||||
{
|
||||
m_conversions.enable_conversion_saves(true);
|
||||
}
|
||||
|
||||
++s.call_depth;
|
||||
|
||||
save_function_params(m_conversions.take_saves());
|
||||
new_function_call(*m_stack_holder, m_conversions.conversion_saves());
|
||||
}
|
||||
|
||||
void pop_function_call()
|
||||
{
|
||||
Stack_Holder &s = *m_stack_holder;
|
||||
--s.call_depth;
|
||||
|
||||
assert(s.call_depth >= 0);
|
||||
|
||||
if (s.call_depth == 0)
|
||||
{
|
||||
s.call_params.back().clear();
|
||||
m_conversions.enable_conversion_saves(false);
|
||||
}
|
||||
pop_function_call(*m_stack_holder, m_conversions.conversion_saves());
|
||||
}
|
||||
|
||||
Stack_Holder &get_stack_holder()
|
||||
{
|
||||
return *m_stack_holder;
|
||||
}
|
||||
|
||||
private:
|
||||
/// Returns the current stack
|
||||
/// make const/non const versions
|
||||
const StackData &get_stack_data() const
|
||||
@@ -1118,27 +1265,44 @@ namespace chaiscript
|
||||
return m_stack_holder->stacks.back();
|
||||
}
|
||||
|
||||
static StackData &get_stack_data(Stack_Holder &t_holder)
|
||||
{
|
||||
return t_holder.stacks.back();
|
||||
}
|
||||
|
||||
StackData &get_stack_data()
|
||||
{
|
||||
return m_stack_holder->stacks.back();
|
||||
}
|
||||
|
||||
const std::map<std::string, Proxy_Function> &get_function_objects_int() const
|
||||
private:
|
||||
|
||||
const std::vector<std::pair<std::string, Boxed_Value>> &get_boxed_functions_int() const
|
||||
{
|
||||
return m_state.m_boxed_functions;
|
||||
}
|
||||
|
||||
std::vector<std::pair<std::string, Boxed_Value>> &get_boxed_functions_int()
|
||||
{
|
||||
return m_state.m_boxed_functions;
|
||||
}
|
||||
|
||||
const std::vector<std::pair<std::string, Proxy_Function>> &get_function_objects_int() const
|
||||
{
|
||||
return m_state.m_function_objects;
|
||||
}
|
||||
|
||||
std::map<std::string, Proxy_Function> &get_function_objects_int()
|
||||
std::vector<std::pair<std::string, Proxy_Function>> &get_function_objects_int()
|
||||
{
|
||||
return m_state.m_function_objects;
|
||||
}
|
||||
|
||||
const std::map<std::string, std::vector<Proxy_Function> > &get_functions_int() const
|
||||
const std::vector<std::pair<std::string, std::shared_ptr<std::vector<Proxy_Function>>>> &get_functions_int() const
|
||||
{
|
||||
return m_state.m_functions;
|
||||
}
|
||||
|
||||
std::map<std::string, std::vector<Proxy_Function> > &get_functions_int()
|
||||
std::vector<std::pair<std::string, std::shared_ptr<std::vector<Proxy_Function>>>> &get_functions_int()
|
||||
{
|
||||
return m_state.m_functions;
|
||||
}
|
||||
@@ -1175,8 +1339,13 @@ namespace chaiscript
|
||||
const auto lhssize = lhsparamtypes.size();
|
||||
const auto rhssize = rhsparamtypes.size();
|
||||
|
||||
CHAISCRIPT_CONSTEXPR auto boxed_type = user_type<Boxed_Value>();
|
||||
CHAISCRIPT_CONSTEXPR auto boxed_pod_type = user_type<Boxed_Number>();
|
||||
#ifdef CHAISCRIPT_HAS_MAGIC_STATICS
|
||||
static auto boxed_type = user_type<Boxed_Value>();
|
||||
static auto boxed_pod_type = user_type<Boxed_Number>();
|
||||
#else
|
||||
auto boxed_type = user_type<Boxed_Value>();
|
||||
auto boxed_pod_type = user_type<Boxed_Number>();
|
||||
#endif
|
||||
|
||||
for (size_t i = 1; i < lhssize && i < rhssize; ++i)
|
||||
{
|
||||
@@ -1247,6 +1416,49 @@ namespace chaiscript
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Container, typename Key, typename Value>
|
||||
static void add_keyed_value(Container &t_c, const Key &t_key, Value &&t_value)
|
||||
{
|
||||
auto itr = find_keyed_value(t_c, t_key);
|
||||
|
||||
if (itr == t_c.end()) {
|
||||
t_c.reserve(t_c.size() + 1); // tightly control growth of memory usage here
|
||||
t_c.emplace_back(t_key, std::forward<Value>(t_value));
|
||||
} else {
|
||||
typedef typename Container::value_type value_type;
|
||||
*itr = value_type(t_key, std::forward<Value>(t_value));
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Container, typename Key>
|
||||
static typename Container::iterator find_keyed_value(Container &t_c, const Key &t_key)
|
||||
{
|
||||
return std::find_if(t_c.begin(), t_c.end(),
|
||||
[&t_key](const typename Container::value_type &o) {
|
||||
return o.first == t_key;
|
||||
});
|
||||
}
|
||||
|
||||
template<typename Container, typename Key>
|
||||
static typename Container::const_iterator find_keyed_value(const Container &t_c, const Key &t_key)
|
||||
{
|
||||
return std::find_if(t_c.begin(), t_c.end(),
|
||||
[&t_key](const typename Container::value_type &o) {
|
||||
return o.first == t_key;
|
||||
});
|
||||
}
|
||||
|
||||
template<typename Container, typename Key>
|
||||
static typename Container::const_iterator find_keyed_value(const Container &t_c, const Key &t_key, const size_t t_hint)
|
||||
{
|
||||
if (t_c.size() > t_hint && t_c[t_hint].first == t_key) {
|
||||
return advance_copy(t_c.begin(), t_hint);
|
||||
} else {
|
||||
return find_keyed_value(t_c, t_key);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Implementation detail for adding a function.
|
||||
/// \throws exception::name_conflict_error if there's a function matching the given one being added
|
||||
void add_function(const Proxy_Function &t_f, const std::string &t_name)
|
||||
@@ -1255,64 +1467,92 @@ namespace chaiscript
|
||||
|
||||
auto &funcs = get_functions_int();
|
||||
|
||||
auto itr = funcs.find(t_name);
|
||||
auto itr = find_keyed_value(funcs, t_name);
|
||||
|
||||
auto &func_objs = get_function_objects_int();
|
||||
|
||||
if (itr != funcs.end())
|
||||
{
|
||||
auto &vec = itr->second;
|
||||
for (const auto &func : vec)
|
||||
{
|
||||
if ((*t_f) == *(func))
|
||||
Proxy_Function new_func =
|
||||
[&]() -> Proxy_Function {
|
||||
if (itr != funcs.end())
|
||||
{
|
||||
throw chaiscript::exception::name_conflict_error(t_name);
|
||||
auto vec = *itr->second;
|
||||
for (const auto &func : vec)
|
||||
{
|
||||
if ((*t_f) == *(func))
|
||||
{
|
||||
throw chaiscript::exception::name_conflict_error(t_name);
|
||||
}
|
||||
}
|
||||
|
||||
vec.reserve(vec.size() + 1); // tightly control vec growth
|
||||
vec.push_back(t_f);
|
||||
std::stable_sort(vec.begin(), vec.end(), &function_less_than);
|
||||
itr->second = std::make_shared<std::vector<Proxy_Function>>(vec);
|
||||
return std::make_shared<Dispatch_Function>(std::move(vec));
|
||||
} else if (t_f->has_arithmetic_param()) {
|
||||
// if the function is the only function but it also contains
|
||||
// arithmetic operators, we must wrap it in a dispatch function
|
||||
// to allow for automatic arithmetic type conversions
|
||||
std::vector<Proxy_Function> vec({t_f});
|
||||
funcs.emplace_back(t_name, std::make_shared<std::vector<Proxy_Function>>(vec));
|
||||
return std::make_shared<Dispatch_Function>(std::move(vec));
|
||||
} else {
|
||||
funcs.emplace_back(t_name, std::make_shared<std::vector<Proxy_Function>>(std::initializer_list<Proxy_Function>({t_f})));
|
||||
return t_f;
|
||||
}
|
||||
}
|
||||
|
||||
vec.push_back(t_f);
|
||||
std::stable_sort(vec.begin(), vec.end(), &function_less_than);
|
||||
func_objs[t_name] = std::make_shared<Dispatch_Function>(vec);
|
||||
} else if (t_f->has_arithmetic_param()) {
|
||||
// if the function is the only function but it also contains
|
||||
// arithmetic operators, we must wrap it in a dispatch function
|
||||
// to allow for automatic arithmetic type conversions
|
||||
std::vector<Proxy_Function> vec({t_f});
|
||||
funcs.insert(std::make_pair(t_name, vec));
|
||||
func_objs[t_name] = std::make_shared<Dispatch_Function>(std::move(vec));
|
||||
} else {
|
||||
funcs.insert(std::make_pair(t_name, std::vector<Proxy_Function>{t_f}));
|
||||
func_objs[t_name] = t_f;
|
||||
}
|
||||
|
||||
}();
|
||||
|
||||
add_keyed_value(get_boxed_functions_int(), t_name, const_var(new_func));
|
||||
add_keyed_value(get_function_objects_int(), t_name, std::move(new_func));
|
||||
}
|
||||
|
||||
mutable chaiscript::detail::threading::shared_mutex m_mutex;
|
||||
mutable chaiscript::detail::threading::shared_mutex m_global_object_mutex;
|
||||
|
||||
struct Stack_Holder
|
||||
{
|
||||
Stack_Holder()
|
||||
: call_depth(0)
|
||||
{
|
||||
stacks.emplace_back(1);
|
||||
call_params.emplace_back();
|
||||
}
|
||||
|
||||
std::deque<StackData> stacks;
|
||||
|
||||
std::deque<std::list<Boxed_Value>> call_params;
|
||||
int call_depth;
|
||||
};
|
||||
|
||||
Type_Conversions m_conversions;
|
||||
chaiscript::detail::threading::Thread_Storage<Stack_Holder> m_stack_holder;
|
||||
|
||||
mutable std::atomic_uint_fast32_t m_method_missing_loc;
|
||||
|
||||
State m_state;
|
||||
};
|
||||
|
||||
Boxed_Value m_place_holder;
|
||||
class Dispatch_State
|
||||
{
|
||||
public:
|
||||
Dispatch_State(Dispatch_Engine &t_engine)
|
||||
: m_engine(t_engine),
|
||||
m_stack_holder(t_engine.get_stack_holder()),
|
||||
m_conversions(t_engine.conversions(), t_engine.conversions().conversion_saves())
|
||||
{
|
||||
}
|
||||
|
||||
Dispatch_Engine *operator->() const {
|
||||
return &m_engine.get();
|
||||
}
|
||||
|
||||
Dispatch_Engine &operator*() const {
|
||||
return m_engine.get();
|
||||
}
|
||||
|
||||
Stack_Holder &stack_holder() const {
|
||||
return m_stack_holder.get();
|
||||
}
|
||||
|
||||
const Type_Conversions_State &conversions() const {
|
||||
return m_conversions;
|
||||
}
|
||||
|
||||
Type_Conversions::Conversion_Saves &conversion_saves() const {
|
||||
return m_conversions.saves();
|
||||
}
|
||||
|
||||
void add_object(const std::string &t_name, Boxed_Value obj) const {
|
||||
m_engine.get().add_object(t_name, std::move(obj), m_stack_holder.get());
|
||||
}
|
||||
|
||||
private:
|
||||
std::reference_wrapper<Dispatch_Engine> m_engine;
|
||||
std::reference_wrapper<Stack_Holder> m_stack_holder;
|
||||
Type_Conversions_State m_conversions;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@@ -1,7 +1,7 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
|
||||
// Copyright 2009-2016, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#ifndef CHAISCRIPT_DYNAMIC_OBJECT_HPP_
|
||||
@@ -24,23 +24,55 @@ namespace chaiscript
|
||||
{
|
||||
namespace dispatch
|
||||
{
|
||||
struct option_explicit_set : std::runtime_error {
|
||||
option_explicit_set(const std::string &t_param_name)
|
||||
: std::runtime_error("option explicit set and parameter '" + t_param_name + "' does not exist")
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
option_explicit_set(const option_explicit_set &) = default;
|
||||
|
||||
virtual ~option_explicit_set() CHAISCRIPT_NOEXCEPT {}
|
||||
};
|
||||
|
||||
class Dynamic_Object
|
||||
{
|
||||
public:
|
||||
Dynamic_Object(std::string t_type_name)
|
||||
: m_type_name(std::move(t_type_name))
|
||||
: m_type_name(std::move(t_type_name)), m_option_explicit(false)
|
||||
{
|
||||
}
|
||||
|
||||
Dynamic_Object() : m_type_name("")
|
||||
Dynamic_Object() : m_type_name(""), m_option_explicit(false)
|
||||
{
|
||||
}
|
||||
|
||||
bool is_explicit() const
|
||||
{
|
||||
return m_option_explicit;
|
||||
}
|
||||
|
||||
void set_explicit(const bool t_explicit)
|
||||
{
|
||||
m_option_explicit = t_explicit;
|
||||
}
|
||||
|
||||
std::string get_type_name() const
|
||||
{
|
||||
return m_type_name;
|
||||
}
|
||||
|
||||
const Boxed_Value &operator[](const std::string &t_attr_name) const
|
||||
{
|
||||
return get_attr(t_attr_name);
|
||||
}
|
||||
|
||||
Boxed_Value &operator[](const std::string &t_attr_name)
|
||||
{
|
||||
return get_attr(t_attr_name);
|
||||
}
|
||||
|
||||
const Boxed_Value &get_attr(const std::string &t_attr_name) const
|
||||
{
|
||||
auto a = m_attrs.find(t_attr_name);
|
||||
@@ -59,11 +91,19 @@ namespace chaiscript
|
||||
|
||||
Boxed_Value &method_missing(const std::string &t_method_name)
|
||||
{
|
||||
if (m_option_explicit && m_attrs.find(t_method_name) == m_attrs.end()) {
|
||||
throw option_explicit_set(t_method_name);
|
||||
}
|
||||
|
||||
return get_attr(t_method_name);
|
||||
}
|
||||
|
||||
const Boxed_Value &method_missing(const std::string &t_method_name) const
|
||||
{
|
||||
if (m_option_explicit && m_attrs.find(t_method_name) == m_attrs.end()) {
|
||||
throw option_explicit_set(t_method_name);
|
||||
}
|
||||
|
||||
return get_attr(t_method_name);
|
||||
}
|
||||
|
||||
@@ -75,6 +115,7 @@ namespace chaiscript
|
||||
|
||||
private:
|
||||
std::string m_type_name;
|
||||
bool m_option_explicit;
|
||||
|
||||
std::map<std::string, Boxed_Value> m_attrs;
|
||||
};
|
||||
|
@@ -1,7 +1,7 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
|
||||
// Copyright 2009-2016, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#ifndef CHAISCRIPT_DYNAMIC_OBJECT_DETAIL_HPP_
|
||||
@@ -84,7 +84,7 @@ namespace chaiscript
|
||||
|
||||
virtual bool is_attribute_function() const CHAISCRIPT_OVERRIDE { return m_is_attribute; }
|
||||
|
||||
virtual bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
|
||||
virtual bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const CHAISCRIPT_OVERRIDE
|
||||
{
|
||||
if (dynamic_object_typename_match(vals, m_type_name, m_ti, t_conversions))
|
||||
{
|
||||
@@ -106,7 +106,7 @@ namespace chaiscript
|
||||
|
||||
|
||||
protected:
|
||||
virtual Boxed_Value do_call(const std::vector<Boxed_Value> ¶ms, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
|
||||
virtual Boxed_Value do_call(const std::vector<Boxed_Value> ¶ms, const Type_Conversions_State &t_conversions) const CHAISCRIPT_OVERRIDE
|
||||
{
|
||||
if (dynamic_object_typename_match(params, m_type_name, m_ti, t_conversions))
|
||||
{
|
||||
@@ -116,7 +116,7 @@ namespace chaiscript
|
||||
}
|
||||
}
|
||||
|
||||
virtual bool compare_first_type(const Boxed_Value &bv, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
|
||||
virtual bool compare_first_type(const Boxed_Value &bv, const Type_Conversions_State &t_conversions) const CHAISCRIPT_OVERRIDE
|
||||
{
|
||||
return dynamic_object_typename_match(bv, m_type_name, m_ti, t_conversions);
|
||||
}
|
||||
@@ -134,7 +134,7 @@ namespace chaiscript
|
||||
}
|
||||
|
||||
bool dynamic_object_typename_match(const Boxed_Value &bv, const std::string &name,
|
||||
const std::unique_ptr<Type_Info> &ti, const Type_Conversions &t_conversions) const
|
||||
const std::unique_ptr<Type_Info> &ti, const Type_Conversions_State &t_conversions) const
|
||||
{
|
||||
if (bv.get_type_info().bare_equal(m_doti))
|
||||
{
|
||||
@@ -156,7 +156,7 @@ namespace chaiscript
|
||||
}
|
||||
|
||||
bool dynamic_object_typename_match(const std::vector<Boxed_Value> &bvs, const std::string &name,
|
||||
const std::unique_ptr<Type_Info> &ti, const Type_Conversions &t_conversions) const
|
||||
const std::unique_ptr<Type_Info> &ti, const Type_Conversions_State &t_conversions) const
|
||||
{
|
||||
if (bvs.size() > 0)
|
||||
{
|
||||
@@ -216,7 +216,7 @@ namespace chaiscript
|
||||
return dc && dc->m_type_name == m_type_name && (*dc->m_func) == (*m_func);
|
||||
}
|
||||
|
||||
virtual bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
|
||||
virtual bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const CHAISCRIPT_OVERRIDE
|
||||
{
|
||||
std::vector<Boxed_Value> new_vals{Boxed_Value(Dynamic_Object(m_type_name))};
|
||||
new_vals.insert(new_vals.end(), vals.begin(), vals.end());
|
||||
@@ -230,9 +230,9 @@ namespace chaiscript
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual Boxed_Value do_call(const std::vector<Boxed_Value> ¶ms, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
|
||||
virtual Boxed_Value do_call(const std::vector<Boxed_Value> ¶ms, const Type_Conversions_State &t_conversions) const CHAISCRIPT_OVERRIDE
|
||||
{
|
||||
auto bv = var(Dynamic_Object(m_type_name));
|
||||
auto bv = Boxed_Value(Dynamic_Object(m_type_name), true);
|
||||
std::vector<Boxed_Value> new_params{bv};
|
||||
new_params.insert(new_params.end(), params.begin(), params.end());
|
||||
|
||||
|
@@ -1,7 +1,7 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
|
||||
// Copyright 2009-2016, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#ifndef CHAISCRIPT_EXCEPTION_SPECIFICATION_HPP_
|
||||
@@ -32,7 +32,7 @@ namespace chaiscript
|
||||
|
||||
protected:
|
||||
template<typename T>
|
||||
void throw_type(const Boxed_Value &bv, const Dispatch_Engine &t_engine)
|
||||
static void throw_type(const Boxed_Value &bv, const Dispatch_Engine &t_engine)
|
||||
{
|
||||
try { T t = t_engine.boxed_cast<T>(bv); throw t; } catch (const chaiscript::exception::bad_boxed_cast &) {}
|
||||
}
|
||||
|
@@ -1,7 +1,7 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
|
||||
// Copyright 2009-2016, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#ifndef CHAISCRIPT_FUNCTION_CALL_HPP_
|
||||
@@ -14,10 +14,11 @@
|
||||
#include "boxed_cast.hpp"
|
||||
#include "function_call_detail.hpp"
|
||||
#include "proxy_functions.hpp"
|
||||
#include "callable_traits.hpp"
|
||||
|
||||
namespace chaiscript {
|
||||
class Boxed_Value;
|
||||
class Type_Conversions;
|
||||
class Type_Conversions_State;
|
||||
namespace detail {
|
||||
template <typename T> struct Cast_Helper;
|
||||
} // namespace detail
|
||||
@@ -35,8 +36,17 @@ namespace chaiscript
|
||||
/// \param[in] funcs the set of functions to dispatch on.
|
||||
template<typename FunctionType>
|
||||
std::function<FunctionType>
|
||||
functor(const std::vector<Const_Proxy_Function> &funcs, const Type_Conversions *t_conversions)
|
||||
functor(const std::vector<Const_Proxy_Function> &funcs, const Type_Conversions_State *t_conversions)
|
||||
{
|
||||
const bool has_arity_match = std::any_of(funcs.begin(), funcs.end(),
|
||||
[](const Const_Proxy_Function &f) {
|
||||
return f->get_arity() == -1 || size_t(f->get_arity()) == chaiscript::dispatch::detail::Arity<FunctionType>::arity;
|
||||
});
|
||||
|
||||
if (!has_arity_match) {
|
||||
throw exception::bad_boxed_cast(user_type<Const_Proxy_Function>(), typeid(std::function<FunctionType>));
|
||||
}
|
||||
|
||||
FunctionType *p=nullptr;
|
||||
return detail::build_function_caller_helper(p, funcs, t_conversions);
|
||||
}
|
||||
@@ -54,7 +64,7 @@ namespace chaiscript
|
||||
/// \param[in] func A function to execute.
|
||||
template<typename FunctionType>
|
||||
std::function<FunctionType>
|
||||
functor(Const_Proxy_Function func, const Type_Conversions *t_conversions)
|
||||
functor(Const_Proxy_Function func, const Type_Conversions_State *t_conversions)
|
||||
{
|
||||
return functor<FunctionType>(std::vector<Const_Proxy_Function>({std::move(func)}), t_conversions);
|
||||
}
|
||||
@@ -63,7 +73,7 @@ namespace chaiscript
|
||||
/// and creating a typesafe C++ function caller from it.
|
||||
template<typename FunctionType>
|
||||
std::function<FunctionType>
|
||||
functor(const Boxed_Value &bv, const Type_Conversions *t_conversions)
|
||||
functor(const Boxed_Value &bv, const Type_Conversions_State *t_conversions)
|
||||
{
|
||||
return functor<FunctionType>(boxed_cast<Const_Proxy_Function >(bv, t_conversions), t_conversions);
|
||||
}
|
||||
@@ -76,7 +86,7 @@ namespace chaiscript
|
||||
{
|
||||
typedef std::function<Signature> Result_Type;
|
||||
|
||||
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *t_conversions)
|
||||
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions_State *t_conversions)
|
||||
{
|
||||
if (ob.get_type_info().bare_equal(user_type<Const_Proxy_Function>()))
|
||||
{
|
||||
@@ -93,7 +103,7 @@ namespace chaiscript
|
||||
{
|
||||
typedef std::function<Signature> Result_Type;
|
||||
|
||||
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *t_conversions)
|
||||
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions_State *t_conversions)
|
||||
{
|
||||
if (ob.get_type_info().bare_equal(user_type<Const_Proxy_Function>()))
|
||||
{
|
||||
@@ -110,7 +120,7 @@ namespace chaiscript
|
||||
{
|
||||
typedef std::function<Signature> Result_Type;
|
||||
|
||||
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *t_conversions)
|
||||
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions_State *t_conversions)
|
||||
{
|
||||
if (ob.get_type_info().bare_equal(user_type<Const_Proxy_Function>()))
|
||||
{
|
||||
|
@@ -1,7 +1,7 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
|
||||
// Copyright 2009-2016, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#ifndef CHAISCRIPT_FUNCTION_CALL_DETAIL_HPP_
|
||||
@@ -31,9 +31,15 @@ namespace chaiscript
|
||||
struct Function_Caller_Ret
|
||||
{
|
||||
static Ret call(const std::vector<Const_Proxy_Function> &t_funcs,
|
||||
const std::vector<Boxed_Value> ¶ms, const Type_Conversions &t_conversions)
|
||||
const std::vector<Boxed_Value> ¶ms, const Type_Conversions_State *t_conversions)
|
||||
{
|
||||
return boxed_cast<Ret>(dispatch::dispatch(t_funcs, params, t_conversions));
|
||||
if (t_conversions) {
|
||||
return boxed_cast<Ret>(dispatch::dispatch(t_funcs, params, *t_conversions), t_conversions);
|
||||
} else {
|
||||
Type_Conversions conv;
|
||||
Type_Conversions_State state(conv, conv.conversion_saves());
|
||||
return boxed_cast<Ret>(dispatch::dispatch(t_funcs, params, state), t_conversions);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -44,9 +50,15 @@ namespace chaiscript
|
||||
struct Function_Caller_Ret<Ret, true>
|
||||
{
|
||||
static Ret call(const std::vector<Const_Proxy_Function> &t_funcs,
|
||||
const std::vector<Boxed_Value> ¶ms, const Type_Conversions &t_conversions)
|
||||
const std::vector<Boxed_Value> ¶ms, const Type_Conversions_State *t_conversions)
|
||||
{
|
||||
return Boxed_Number(dispatch::dispatch(t_funcs, params, t_conversions)).get_as<Ret>();
|
||||
if (t_conversions) {
|
||||
return Boxed_Number(dispatch::dispatch(t_funcs, params, *t_conversions)).get_as<Ret>();
|
||||
} else {
|
||||
Type_Conversions conv;
|
||||
Type_Conversions_State state(conv, conv.conversion_saves());
|
||||
return Boxed_Number(dispatch::dispatch(t_funcs, params, state)).get_as<Ret>();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -58,9 +70,15 @@ namespace chaiscript
|
||||
struct Function_Caller_Ret<void, false>
|
||||
{
|
||||
static void call(const std::vector<Const_Proxy_Function> &t_funcs,
|
||||
const std::vector<Boxed_Value> ¶ms, const Type_Conversions &t_conversions)
|
||||
const std::vector<Boxed_Value> ¶ms, const Type_Conversions_State *t_conversions)
|
||||
{
|
||||
dispatch::dispatch(t_funcs, params, t_conversions);
|
||||
if (t_conversions) {
|
||||
dispatch::dispatch(t_funcs, params, *t_conversions);
|
||||
} else {
|
||||
Type_Conversions conv;
|
||||
Type_Conversions_State state(conv, conv.conversion_saves());
|
||||
dispatch::dispatch(t_funcs, params, state);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -70,31 +88,60 @@ namespace chaiscript
|
||||
template<typename Ret, typename ... Param>
|
||||
struct Build_Function_Caller_Helper
|
||||
{
|
||||
Build_Function_Caller_Helper(std::vector<Const_Proxy_Function> t_funcs, const Type_Conversions &t_conversions)
|
||||
Build_Function_Caller_Helper(std::vector<Const_Proxy_Function> t_funcs, const Type_Conversions *t_conversions)
|
||||
: m_funcs(std::move(t_funcs)),
|
||||
m_conversions(t_conversions)
|
||||
{
|
||||
}
|
||||
|
||||
Ret operator()(Param...param)
|
||||
template<typename ... P>
|
||||
Ret operator()(P&& ... param)
|
||||
{
|
||||
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)...
|
||||
}, m_conversions
|
||||
|
||||
);
|
||||
if (m_conversions) {
|
||||
Type_Conversions_State state(*m_conversions, m_conversions->conversion_saves());
|
||||
return Function_Caller_Ret<Ret, std::is_arithmetic<Ret>::value && !std::is_same<Ret, bool>::value>::call(m_funcs, {
|
||||
box<P>(std::forward<P>(param))...
|
||||
}, &state
|
||||
);
|
||||
} else {
|
||||
return Function_Caller_Ret<Ret, std::is_arithmetic<Ret>::value && !std::is_same<Ret, bool>::value>::call(m_funcs, {
|
||||
box<P>(std::forward<P>(param))...
|
||||
}, nullptr
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
template<typename P, typename Q>
|
||||
static auto box(Q&& q) -> typename std::enable_if<std::is_reference<P>::value&&!std::is_same<chaiscript::Boxed_Value, typename std::remove_const<typename std::remove_reference<P>::type>::type>::value, Boxed_Value>::type
|
||||
{
|
||||
return Boxed_Value(std::ref(std::forward<Q>(q)));
|
||||
}
|
||||
|
||||
template<typename P, typename Q>
|
||||
static auto box(Q&& q) -> typename std::enable_if<!std::is_reference<P>::value&&!std::is_same<chaiscript::Boxed_Value, typename std::remove_const<typename std::remove_reference<P>::type>::type>::value, Boxed_Value>::type
|
||||
{
|
||||
return Boxed_Value(std::forward<Q>(q));
|
||||
}
|
||||
|
||||
template<typename P>
|
||||
static Boxed_Value box(Boxed_Value bv)
|
||||
{
|
||||
return bv;
|
||||
}
|
||||
|
||||
|
||||
std::vector<Const_Proxy_Function> m_funcs;
|
||||
Type_Conversions m_conversions;
|
||||
const Type_Conversions *m_conversions;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/// \todo what happens if t_conversions is deleted out from under us?!
|
||||
template<typename Ret, typename ... Params>
|
||||
std::function<Ret (Params...)> build_function_caller_helper(Ret (Params...), const std::vector<Const_Proxy_Function> &funcs, const Type_Conversions *t_conversions)
|
||||
std::function<Ret (Params...)> build_function_caller_helper(Ret (Params...), const std::vector<Const_Proxy_Function> &funcs, const Type_Conversions_State *t_conversions)
|
||||
{
|
||||
/*
|
||||
if (funcs.size() == 1)
|
||||
{
|
||||
std::shared_ptr<const Proxy_Function_Impl<Ret (Params...)>> pfi =
|
||||
@@ -108,8 +155,9 @@ namespace chaiscript
|
||||
// looks like this either wasn't a Proxy_Function_Impl or the types didn't match
|
||||
// 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:Type_Conversions()));
|
||||
return std::function<Ret (Params...)>(Build_Function_Caller_Helper<Ret, Params...>(funcs, t_conversions?t_conversions->get():nullptr));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,7 +1,7 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
|
||||
// Copyright 2009-2016, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#ifndef CHAISCRIPT_HANDLE_RETURN_HPP_
|
||||
@@ -9,7 +9,6 @@
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
|
||||
#include "boxed_number.hpp"
|
||||
@@ -23,7 +22,7 @@ namespace chaiscript
|
||||
{
|
||||
namespace dispatch
|
||||
{
|
||||
template<class T> class Proxy_Function_Impl;
|
||||
template<class T, class U> class Proxy_Function_Callable_Impl;
|
||||
template<class T> class Assignable_Proxy_Function_Impl;
|
||||
|
||||
namespace detail
|
||||
@@ -54,9 +53,7 @@ namespace chaiscript
|
||||
{
|
||||
static Boxed_Value handle(const std::function<Ret> &f) {
|
||||
return Boxed_Value(
|
||||
std::shared_ptr<dispatch::Proxy_Function_Base>(
|
||||
new dispatch::Proxy_Function_Impl<Ret>(f)
|
||||
)
|
||||
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Ret, std::function<Ret>>>(f)
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -66,10 +63,8 @@ namespace chaiscript
|
||||
{
|
||||
static Boxed_Value handle(const std::function<Ret> &f) {
|
||||
return Boxed_Value(
|
||||
std::shared_ptr<dispatch::Proxy_Function_Base>(
|
||||
new Proxy_Function_Impl<Ret>(f)
|
||||
)
|
||||
);
|
||||
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Ret, std::function<Ret>>>(f)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -78,12 +73,7 @@ namespace chaiscript
|
||||
{
|
||||
static Boxed_Value handle(const std::shared_ptr<std::function<Ret>> &f) {
|
||||
return Boxed_Value(
|
||||
std::shared_ptr<Proxy_Function_Base>(
|
||||
new Assignable_Proxy_Function_Impl<Ret>(
|
||||
std::ref(*f),
|
||||
f
|
||||
)
|
||||
)
|
||||
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Assignable_Proxy_Function_Impl<Ret>>(std::ref(*f),f)
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -93,13 +83,8 @@ namespace chaiscript
|
||||
{
|
||||
static Boxed_Value handle(const std::shared_ptr<std::function<Ret>> &f) {
|
||||
return Boxed_Value(
|
||||
std::shared_ptr<Proxy_Function_Base>(
|
||||
new Assignable_Proxy_Function_Impl<Ret>(
|
||||
std::ref(*f),
|
||||
f
|
||||
)
|
||||
)
|
||||
);
|
||||
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Assignable_Proxy_Function_Impl<Ret>>(std::ref(*f),f)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -108,13 +93,8 @@ namespace chaiscript
|
||||
{
|
||||
static Boxed_Value handle(const std::shared_ptr<std::function<Ret>> &f) {
|
||||
return Boxed_Value(
|
||||
std::shared_ptr<Proxy_Function_Base>(
|
||||
new Assignable_Proxy_Function_Impl<Ret>(
|
||||
std::ref(*f),
|
||||
f
|
||||
)
|
||||
)
|
||||
);
|
||||
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Assignable_Proxy_Function_Impl<Ret>>(std::ref(*f),f)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -123,24 +103,36 @@ namespace chaiscript
|
||||
{
|
||||
static Boxed_Value handle(std::function<Ret> &f) {
|
||||
return Boxed_Value(
|
||||
std::shared_ptr<Proxy_Function_Base>(
|
||||
new Assignable_Proxy_Function_Impl<Ret>(
|
||||
std::ref(f),
|
||||
std::shared_ptr<std::function<Ret>>()
|
||||
)
|
||||
)
|
||||
);
|
||||
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Assignable_Proxy_Function_Impl<Ret>>(std::ref(f),
|
||||
std::shared_ptr<std::function<Ret>>())
|
||||
);
|
||||
}
|
||||
|
||||
static Boxed_Value handle(const std::function<Ret> &f) {
|
||||
return Boxed_Value(
|
||||
std::shared_ptr<dispatch::Proxy_Function_Base>(
|
||||
new dispatch::Proxy_Function_Impl<Ret>(f)
|
||||
)
|
||||
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Ret, std::function<Ret>>>(f)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Ret>
|
||||
struct Handle_Return<Ret *&>
|
||||
{
|
||||
static Boxed_Value handle(Ret *p)
|
||||
{
|
||||
return Boxed_Value(p, true);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Ret>
|
||||
struct Handle_Return<const Ret *&>
|
||||
{
|
||||
static Boxed_Value handle(const Ret *p)
|
||||
{
|
||||
return Boxed_Value(p, true);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Ret>
|
||||
struct Handle_Return<Ret *>
|
||||
{
|
||||
|
@@ -1,7 +1,7 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
|
||||
// Copyright 2009-2016, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#ifndef CHAISCRIPT_OPERATORS_HPP_
|
||||
|
@@ -1,7 +1,7 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
|
||||
// Copyright 2009-2016, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
|
||||
@@ -16,21 +16,14 @@ namespace chaiscript
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
/**
|
||||
* A constructor function, used for creating a new object
|
||||
* of a given type with a given set of params
|
||||
*/
|
||||
template<typename Class, typename ... Params>
|
||||
std::shared_ptr<Class> constructor_(Params ... params)
|
||||
{
|
||||
return std::make_shared<Class>(params...);
|
||||
}
|
||||
|
||||
template<typename Class, typename ... Params >
|
||||
Proxy_Function build_constructor_(Class (*)(Params...))
|
||||
{
|
||||
typedef std::shared_ptr<Class> (sig)(Params...);
|
||||
return Proxy_Function(static_cast<Proxy_Function_Impl_Base *>(new Proxy_Function_Impl<sig>(std::function<sig>(&(constructor_<Class, Params...>)))));
|
||||
auto call = dispatch::detail::Constructor<Class, Params...>();
|
||||
|
||||
return Proxy_Function(
|
||||
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<std::shared_ptr<Class> (Params...), decltype(call)>>(call));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,7 +1,7 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
|
||||
// Copyright 2009-2016, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
#include <iterator>
|
||||
|
||||
#include "../chaiscript_defines.hpp"
|
||||
#include "boxed_cast.hpp"
|
||||
@@ -42,7 +43,7 @@ namespace chaiscript
|
||||
namespace dispatch
|
||||
{
|
||||
template<typename FunctionType>
|
||||
std::function<FunctionType> functor(std::shared_ptr<const Proxy_Function_Base> func, const Type_Conversions *t_conversions);
|
||||
std::function<FunctionType> functor(std::shared_ptr<const Proxy_Function_Base> func, const Type_Conversions_State *t_conversions);
|
||||
|
||||
class Param_Types
|
||||
{
|
||||
@@ -71,7 +72,7 @@ namespace chaiscript
|
||||
return m_types == t_rhs.m_types;
|
||||
}
|
||||
|
||||
bool match(const std::vector<Boxed_Value> &vals, const Type_Conversions &t_conversions) const
|
||||
bool match(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const
|
||||
{
|
||||
if (!m_has_types) return true;
|
||||
if (vals.size() != m_types.size()) return false;
|
||||
@@ -146,9 +147,13 @@ namespace chaiscript
|
||||
public:
|
||||
virtual ~Proxy_Function_Base() {}
|
||||
|
||||
Boxed_Value operator()(const std::vector<Boxed_Value> ¶ms, const chaiscript::Type_Conversions &t_conversions) const
|
||||
Boxed_Value operator()(const std::vector<Boxed_Value> ¶ms, const chaiscript::Type_Conversions_State &t_conversions) const
|
||||
{
|
||||
return do_call(params, t_conversions);
|
||||
if (m_arity < 0 || size_t(m_arity) == params.size()) {
|
||||
return do_call(params, t_conversions);
|
||||
} else {
|
||||
throw exception::arity_error(static_cast<int>(params.size()), m_arity);
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a vector containing all of the types of the parameters the function returns/takes
|
||||
@@ -158,7 +163,7 @@ namespace chaiscript
|
||||
const std::vector<Type_Info> &get_param_types() const { return m_types; }
|
||||
|
||||
virtual bool operator==(const Proxy_Function_Base &) const = 0;
|
||||
virtual bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions &t_conversions) const = 0;
|
||||
virtual bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const = 0;
|
||||
|
||||
virtual bool is_attribute_function() const { return false; }
|
||||
|
||||
@@ -174,7 +179,7 @@ namespace chaiscript
|
||||
|
||||
//! Return true if the function is a possible match
|
||||
//! to the passed in values
|
||||
bool filter(const std::vector<Boxed_Value> &vals, const Type_Conversions &t_conversions) const
|
||||
bool filter(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const
|
||||
{
|
||||
if (m_arity < 0)
|
||||
{
|
||||
@@ -183,10 +188,10 @@ namespace chaiscript
|
||||
if (m_arity == 0)
|
||||
{
|
||||
return true;
|
||||
} else if (m_arity > 1 && m_types.size() > 1) {
|
||||
return compare_first_type(vals[0], t_conversions) && compare_type_to_param(m_types[2], vals[1], t_conversions);
|
||||
} else if (m_arity > 1) {
|
||||
return compare_type_to_param(m_types[1], vals[0], t_conversions) && compare_type_to_param(m_types[2], vals[1], t_conversions);
|
||||
} else {
|
||||
return compare_first_type(vals[0], t_conversions);
|
||||
return compare_type_to_param(m_types[1], vals[0], t_conversions);
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
@@ -201,15 +206,15 @@ namespace chaiscript
|
||||
|
||||
virtual std::string annotation() const = 0;
|
||||
|
||||
static bool compare_type_to_param(const Type_Info &ti, const Boxed_Value &bv, const Type_Conversions &t_conversions)
|
||||
static bool compare_type_to_param(const Type_Info &ti, const Boxed_Value &bv, const Type_Conversions_State &t_conversions)
|
||||
{
|
||||
if (ti.is_undef()
|
||||
|| ti.bare_equal(user_type<Boxed_Value>())
|
||||
|| (!bv.get_type_info().is_undef()
|
||||
&& (ti.bare_equal(user_type<Boxed_Number>())
|
||||
&& ( (ti.bare_equal(user_type<Boxed_Number>()) && bv.get_type_info().is_arithmetic())
|
||||
|| ti.bare_equal(bv.get_type_info())
|
||||
|| bv.get_type_info().bare_equal(user_type<std::shared_ptr<const Proxy_Function_Base> >())
|
||||
|| t_conversions.converts(ti, bv.get_type_info())
|
||||
|| t_conversions->converts(ti, bv.get_type_info())
|
||||
)
|
||||
)
|
||||
)
|
||||
@@ -220,13 +225,13 @@ namespace chaiscript
|
||||
}
|
||||
}
|
||||
|
||||
virtual bool compare_first_type(const Boxed_Value &bv, const Type_Conversions &t_conversions) const
|
||||
virtual bool compare_first_type(const Boxed_Value &bv, const Type_Conversions_State &t_conversions) const
|
||||
{
|
||||
return compare_type_to_param(m_types[1], bv, t_conversions);
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual Boxed_Value do_call(const std::vector<Boxed_Value> ¶ms, const Type_Conversions &t_conversions) const = 0;
|
||||
virtual Boxed_Value do_call(const std::vector<Boxed_Value> ¶ms, const Type_Conversions_State &t_conversions) const = 0;
|
||||
|
||||
Proxy_Function_Base(std::vector<Type_Info> t_types, int t_arity)
|
||||
: m_types(std::move(t_types)), m_arity(t_arity), m_has_arithmetic_param(false)
|
||||
@@ -243,7 +248,7 @@ namespace chaiscript
|
||||
}
|
||||
|
||||
|
||||
static bool compare_types(const std::vector<Type_Info> &tis, const std::vector<Boxed_Value> &bvs)
|
||||
static bool compare_types(const std::vector<Type_Info> &tis, const std::vector<Boxed_Value> &bvs, const Type_Conversions_State &t_conversions)
|
||||
{
|
||||
if (tis.size() - 1 != bvs.size())
|
||||
{
|
||||
@@ -252,10 +257,7 @@ namespace chaiscript
|
||||
const size_t size = bvs.size();
|
||||
for (size_t i = 0; i < size; ++i)
|
||||
{
|
||||
if (!(tis[i+1].bare_equal(bvs[i].get_type_info()) && tis[i+1].is_const() >= bvs[i].get_type_info().is_const() ))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (!compare_type_to_param(tis[i + 1], bvs[i], t_conversions)) { return false; }
|
||||
}
|
||||
}
|
||||
return true;
|
||||
@@ -301,7 +303,6 @@ namespace chaiscript
|
||||
{
|
||||
public:
|
||||
Dynamic_Proxy_Function(
|
||||
std::function<Boxed_Value (const std::vector<Boxed_Value> &)> t_f,
|
||||
int t_arity=-1,
|
||||
AST_NodePtr t_parsenode = AST_NodePtr(),
|
||||
Param_Types t_param_types = Param_Types(),
|
||||
@@ -309,8 +310,7 @@ namespace chaiscript
|
||||
Proxy_Function t_guard = Proxy_Function())
|
||||
: Proxy_Function_Base(build_param_type_list(t_param_types), t_arity),
|
||||
m_param_types(std::move(t_param_types)),
|
||||
m_guard(std::move(t_guard)), m_parsenode(std::move(t_parsenode)), m_description(std::move(t_description)),
|
||||
m_f(std::move(t_f))
|
||||
m_guard(std::move(t_guard)), m_parsenode(std::move(t_parsenode)), m_description(std::move(t_description))
|
||||
{
|
||||
}
|
||||
|
||||
@@ -327,7 +327,7 @@ namespace chaiscript
|
||||
&& this->m_param_types == prhs->m_param_types);
|
||||
}
|
||||
|
||||
virtual bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
|
||||
virtual bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const CHAISCRIPT_OVERRIDE
|
||||
{
|
||||
return (m_arity < 0 || (vals.size() == size_t(m_arity) && m_param_types.match(vals, t_conversions)))
|
||||
&& test_guard(vals, t_conversions);
|
||||
@@ -349,25 +349,9 @@ namespace chaiscript
|
||||
return m_description;
|
||||
}
|
||||
|
||||
|
||||
protected:
|
||||
virtual Boxed_Value do_call(const std::vector<Boxed_Value> ¶ms, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
|
||||
{
|
||||
if (m_arity < 0 || params.size() == size_t(m_arity))
|
||||
{
|
||||
if (call_match(params, t_conversions) && test_guard(params, t_conversions))
|
||||
{
|
||||
return m_f(params);
|
||||
} else {
|
||||
throw exception::guard_error();
|
||||
}
|
||||
|
||||
} else {
|
||||
throw exception::arity_error(static_cast<int>(params.size()), m_arity);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
bool test_guard(const std::vector<Boxed_Value> ¶ms, const Type_Conversions &t_conversions) const
|
||||
bool test_guard(const std::vector<Boxed_Value> ¶ms, const Type_Conversions_State &t_conversions) const
|
||||
{
|
||||
if (m_guard)
|
||||
{
|
||||
@@ -383,12 +367,11 @@ namespace chaiscript
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
static std::vector<Type_Info> build_param_type_list(const Param_Types &t_types)
|
||||
{
|
||||
std::vector<Type_Info> types;
|
||||
|
||||
// For the return type
|
||||
types.push_back(chaiscript::detail::Get_Type_Info<Boxed_Value>::get());
|
||||
std::vector<Type_Info> types{chaiscript::detail::Get_Type_Info<Boxed_Value>::get()};
|
||||
|
||||
for (const auto &t : t_types.types())
|
||||
{
|
||||
@@ -406,9 +389,58 @@ namespace chaiscript
|
||||
Proxy_Function m_guard;
|
||||
AST_NodePtr m_parsenode;
|
||||
std::string m_description;
|
||||
std::function<Boxed_Value (const std::vector<Boxed_Value> &)> m_f;
|
||||
};
|
||||
|
||||
|
||||
|
||||
template<typename Callable>
|
||||
class Dynamic_Proxy_Function_Impl : public Dynamic_Proxy_Function
|
||||
{
|
||||
public:
|
||||
Dynamic_Proxy_Function_Impl(
|
||||
Callable t_f,
|
||||
int t_arity=-1,
|
||||
AST_NodePtr t_parsenode = AST_NodePtr(),
|
||||
Param_Types t_param_types = Param_Types(),
|
||||
std::string t_description = "",
|
||||
Proxy_Function t_guard = Proxy_Function())
|
||||
: Dynamic_Proxy_Function(
|
||||
t_arity,
|
||||
std::move(t_parsenode),
|
||||
std::move(t_param_types),
|
||||
std::move(t_description),
|
||||
std::move(t_guard)
|
||||
),
|
||||
m_f(std::move(t_f))
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~Dynamic_Proxy_Function_Impl() {}
|
||||
|
||||
|
||||
protected:
|
||||
virtual Boxed_Value do_call(const std::vector<Boxed_Value> ¶ms, const Type_Conversions_State &t_conversions) const CHAISCRIPT_OVERRIDE
|
||||
{
|
||||
if (call_match(params, t_conversions) && test_guard(params, t_conversions))
|
||||
{
|
||||
return m_f(params);
|
||||
} else {
|
||||
throw exception::guard_error();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
Callable m_f;
|
||||
};
|
||||
|
||||
template<typename Callable, typename ... Arg>
|
||||
Proxy_Function make_dynamic_proxy_function(Callable &&c, Arg&& ... a)
|
||||
{
|
||||
return chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Dynamic_Proxy_Function_Impl<Callable>>(
|
||||
std::forward<Callable>(c), std::forward<Arg>(a)...);
|
||||
}
|
||||
|
||||
/// An object used by Bound_Function to represent "_" parameters
|
||||
/// of a binding. This allows for unbound parameters during bind.
|
||||
struct Placeholder_Object
|
||||
@@ -437,7 +469,7 @@ namespace chaiscript
|
||||
|
||||
virtual ~Bound_Function() {}
|
||||
|
||||
virtual bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
|
||||
virtual bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const CHAISCRIPT_OVERRIDE
|
||||
{
|
||||
return m_f->call_match(build_param_list(vals), t_conversions);
|
||||
}
|
||||
@@ -516,7 +548,7 @@ namespace chaiscript
|
||||
return retval;
|
||||
}
|
||||
|
||||
virtual Boxed_Value do_call(const std::vector<Boxed_Value> ¶ms, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
|
||||
virtual Boxed_Value do_call(const std::vector<Boxed_Value> ¶ms, const Type_Conversions_State &t_conversions) const CHAISCRIPT_OVERRIDE
|
||||
{
|
||||
return (*m_f)(build_param_list(params), t_conversions);
|
||||
}
|
||||
@@ -541,56 +573,52 @@ namespace chaiscript
|
||||
return "";
|
||||
}
|
||||
|
||||
virtual bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
|
||||
virtual bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const CHAISCRIPT_OVERRIDE
|
||||
{
|
||||
return static_cast<int>(vals.size()) == get_arity() && (compare_types(m_types, vals) || compare_types_with_cast(vals, t_conversions));
|
||||
return static_cast<int>(vals.size()) == get_arity() && (compare_types(m_types, vals, t_conversions) && 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;
|
||||
virtual bool compare_types_with_cast(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const = 0;
|
||||
};
|
||||
|
||||
/// The standard typesafe function call implementation of Proxy_Function
|
||||
/// It takes a std::function<> object and performs runtime
|
||||
/// type checking of Boxed_Value parameters, in a type safe manner
|
||||
template<typename Func>
|
||||
class Proxy_Function_Impl : public Proxy_Function_Impl_Base
|
||||
|
||||
|
||||
/// For any callable object
|
||||
template<typename Func, typename Callable>
|
||||
class Proxy_Function_Callable_Impl : public Proxy_Function_Impl_Base
|
||||
{
|
||||
public:
|
||||
Proxy_Function_Impl(std::function<Func> f)
|
||||
Proxy_Function_Callable_Impl(Callable f)
|
||||
: Proxy_Function_Impl_Base(detail::build_param_type_list(static_cast<Func *>(nullptr))),
|
||||
m_f(std::move(f)), m_dummy_func(nullptr)
|
||||
m_f(std::move(f))
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~Proxy_Function_Impl() {}
|
||||
virtual ~Proxy_Function_Callable_Impl() {}
|
||||
|
||||
virtual bool compare_types_with_cast(const std::vector<Boxed_Value> &vals, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
|
||||
virtual bool compare_types_with_cast(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const CHAISCRIPT_OVERRIDE
|
||||
{
|
||||
return detail::compare_types_cast(m_dummy_func, vals, t_conversions);
|
||||
return detail::compare_types_cast(static_cast<Func *>(nullptr), vals, t_conversions);
|
||||
}
|
||||
|
||||
virtual bool operator==(const Proxy_Function_Base &t_func) const CHAISCRIPT_OVERRIDE
|
||||
{
|
||||
return dynamic_cast<const Proxy_Function_Impl<Func> *>(&t_func) != nullptr;
|
||||
return dynamic_cast<const Proxy_Function_Callable_Impl<Func, Callable> *>(&t_func) != nullptr;
|
||||
}
|
||||
|
||||
std::function<Func> internal_function() const
|
||||
{
|
||||
return m_f;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual Boxed_Value do_call(const std::vector<Boxed_Value> ¶ms, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
|
||||
virtual Boxed_Value do_call(const std::vector<Boxed_Value> ¶ms, const Type_Conversions_State &t_conversions) const CHAISCRIPT_OVERRIDE
|
||||
{
|
||||
return detail::Do_Call<typename std::function<Func>::result_type>::go(m_f, params, t_conversions);
|
||||
typedef typename detail::Function_Signature<Func>::Return_Type Return_Type;
|
||||
return detail::Do_Call<Return_Type>::template go<Func>(m_f, params, t_conversions);
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
std::function<Func> m_f;
|
||||
Func *m_dummy_func;
|
||||
Callable m_f;
|
||||
};
|
||||
|
||||
|
||||
class Assignable_Proxy_Function : public Proxy_Function_Impl_Base
|
||||
{
|
||||
public:
|
||||
@@ -613,17 +641,16 @@ namespace chaiscript
|
||||
public:
|
||||
Assignable_Proxy_Function_Impl(std::reference_wrapper<std::function<Func>> t_f, std::shared_ptr<std::function<Func>> t_ptr)
|
||||
: Assignable_Proxy_Function(detail::build_param_type_list(static_cast<Func *>(nullptr))),
|
||||
m_f(std::move(t_f)), m_shared_ptr_holder(std::move(t_ptr)), m_dummy_func(nullptr)
|
||||
m_f(std::move(t_f)), m_shared_ptr_holder(std::move(t_ptr))
|
||||
{
|
||||
assert(!m_shared_ptr_holder || m_shared_ptr_holder.get() == &m_f.get());
|
||||
|
||||
}
|
||||
|
||||
virtual ~Assignable_Proxy_Function_Impl() {}
|
||||
|
||||
virtual bool compare_types_with_cast(const std::vector<Boxed_Value> &vals, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
|
||||
virtual bool compare_types_with_cast(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const CHAISCRIPT_OVERRIDE
|
||||
{
|
||||
return detail::compare_types_cast(m_dummy_func, vals, t_conversions);
|
||||
return detail::compare_types_cast(static_cast<Func *>(nullptr), vals, t_conversions);
|
||||
}
|
||||
|
||||
virtual bool operator==(const Proxy_Function_Base &t_func) const CHAISCRIPT_OVERRIDE
|
||||
@@ -641,16 +668,15 @@ namespace chaiscript
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual Boxed_Value do_call(const std::vector<Boxed_Value> ¶ms, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
|
||||
virtual Boxed_Value do_call(const std::vector<Boxed_Value> ¶ms, const Type_Conversions_State &t_conversions) const CHAISCRIPT_OVERRIDE
|
||||
{
|
||||
return detail::Do_Call<typename std::function<Func>::result_type>::go(m_f.get(), params, t_conversions);
|
||||
return detail::Do_Call<typename std::function<Func>::result_type>::template go<Func>(m_f.get(), params, t_conversions);
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
std::reference_wrapper<std::function<Func>> m_f;
|
||||
std::shared_ptr<std::function<Func>> m_shared_ptr_holder;
|
||||
Func *m_dummy_func;
|
||||
};
|
||||
/// Attribute getter Proxy_Function implementation
|
||||
template<typename T, typename Class>
|
||||
@@ -679,7 +705,7 @@ namespace chaiscript
|
||||
}
|
||||
}
|
||||
|
||||
virtual bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions &) const CHAISCRIPT_OVERRIDE
|
||||
virtual bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &) const CHAISCRIPT_OVERRIDE
|
||||
{
|
||||
if (vals.size() != 1)
|
||||
{
|
||||
@@ -695,21 +721,16 @@ namespace chaiscript
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual Boxed_Value do_call(const std::vector<Boxed_Value> ¶ms, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
|
||||
virtual Boxed_Value do_call(const std::vector<Boxed_Value> ¶ms, const Type_Conversions_State &t_conversions) const CHAISCRIPT_OVERRIDE
|
||||
{
|
||||
if (params.size() == 1)
|
||||
const Boxed_Value &bv = params[0];
|
||||
if (bv.is_const())
|
||||
{
|
||||
const Boxed_Value &bv = params[0];
|
||||
if (bv.is_const())
|
||||
{
|
||||
const Class *o = boxed_cast<const Class *>(bv, &t_conversions);
|
||||
return detail::Handle_Return<const typename std::add_lvalue_reference<T>::type>::handle(o->*m_attr);
|
||||
} else {
|
||||
Class *o = boxed_cast<Class *>(bv, &t_conversions);
|
||||
return detail::Handle_Return<typename std::add_lvalue_reference<T>::type>::handle(o->*m_attr);
|
||||
}
|
||||
const Class *o = boxed_cast<const Class *>(bv, &t_conversions);
|
||||
return detail::Handle_Return<const typename std::add_lvalue_reference<T>::type>::handle(o->*m_attr);
|
||||
} else {
|
||||
throw exception::arity_error(static_cast<int>(params.size()), 1);
|
||||
Class *o = boxed_cast<Class *>(bv, &t_conversions);
|
||||
return detail::Handle_Return<typename std::add_lvalue_reference<T>::type>::handle(o->*m_attr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -739,6 +760,14 @@ namespace chaiscript
|
||||
{
|
||||
}
|
||||
|
||||
dispatch_error(std::vector<Boxed_Value> t_parameters,
|
||||
std::vector<Const_Proxy_Function> t_functions,
|
||||
const std::string &t_desc)
|
||||
: std::runtime_error(t_desc), parameters(std::move(t_parameters)), functions(std::move(t_functions))
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
dispatch_error(const dispatch_error &) = default;
|
||||
virtual ~dispatch_error() CHAISCRIPT_NOEXCEPT {}
|
||||
|
||||
@@ -753,51 +782,40 @@ namespace chaiscript
|
||||
{
|
||||
template<typename FuncType>
|
||||
bool types_match_except_for_arithmetic(const FuncType &t_func, const std::vector<Boxed_Value> &plist,
|
||||
const Type_Conversions &t_conversions)
|
||||
const Type_Conversions_State &t_conversions)
|
||||
{
|
||||
if (t_func->get_arity() != static_cast<int>(plist.size()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const std::vector<Type_Info> &types = t_func->get_param_types();
|
||||
|
||||
if (t_func->get_arity() == -1) return false;
|
||||
|
||||
assert(plist.size() == types.size() - 1);
|
||||
|
||||
for (size_t i = 0; i < plist.size(); ++i)
|
||||
{
|
||||
if (Proxy_Function_Base::compare_type_to_param(types[i+1], plist[i], t_conversions)
|
||||
|| (types[i+1].is_arithmetic() && plist[i].get_type_info().is_arithmetic()))
|
||||
{
|
||||
// types continue to match
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// all types match
|
||||
return true;
|
||||
return std::mismatch(plist.begin(), plist.end(),
|
||||
types.begin()+1,
|
||||
[&](const Boxed_Value &bv, const Type_Info &ti) {
|
||||
return Proxy_Function_Base::compare_type_to_param(ti, bv, t_conversions)
|
||||
|| (bv.get_type_info().is_arithmetic() && ti.is_arithmetic());
|
||||
}
|
||||
) == std::make_pair(plist.end(), types.end());
|
||||
}
|
||||
|
||||
template<typename InItr>
|
||||
template<typename InItr, typename Funcs>
|
||||
Boxed_Value dispatch_with_conversions(InItr begin, const InItr &end, const std::vector<Boxed_Value> &plist,
|
||||
const Type_Conversions &t_conversions)
|
||||
const Type_Conversions_State &t_conversions, const Funcs &t_funcs)
|
||||
{
|
||||
InItr orig(begin);
|
||||
|
||||
InItr matching_func(end);
|
||||
|
||||
while (begin != end)
|
||||
{
|
||||
if (types_match_except_for_arithmetic(*begin, plist, t_conversions))
|
||||
if (types_match_except_for_arithmetic(begin->second, plist, t_conversions))
|
||||
{
|
||||
if (matching_func == end)
|
||||
{
|
||||
matching_func = begin;
|
||||
} else {
|
||||
// handle const members vs non-const member, which is not really ambiguous
|
||||
const auto &mat_fun_param_types = (*matching_func)->get_param_types();
|
||||
const auto &next_fun_param_types = (*begin)->get_param_types();
|
||||
const auto &mat_fun_param_types = matching_func->second->get_param_types();
|
||||
const auto &next_fun_param_types = begin->second->get_param_types();
|
||||
|
||||
if (plist[0].is_const() && !mat_fun_param_types[1].is_const() && next_fun_param_types[1].is_const()) {
|
||||
matching_func = begin; // keep the new one, the const/non-const matchup is correct
|
||||
@@ -805,7 +823,7 @@ namespace chaiscript
|
||||
// keep the old one, it has a better const/non-const matchup
|
||||
} else {
|
||||
// ambiguous function call
|
||||
throw exception::dispatch_error(plist, std::vector<Const_Proxy_Function>(orig, end));
|
||||
throw exception::dispatch_error(plist, std::vector<Const_Proxy_Function>(t_funcs.begin(), t_funcs.end()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -816,25 +834,29 @@ namespace chaiscript
|
||||
if (matching_func == end)
|
||||
{
|
||||
// no appropriate function to attempt arithmetic type conversion on
|
||||
throw exception::dispatch_error(plist, std::vector<Const_Proxy_Function>(orig, end));
|
||||
throw exception::dispatch_error(plist, std::vector<Const_Proxy_Function>(t_funcs.begin(), t_funcs.end()));
|
||||
}
|
||||
|
||||
|
||||
std::vector<Boxed_Value> newplist;
|
||||
const std::vector<Type_Info> &tis = (*matching_func)->get_param_types();
|
||||
newplist.reserve(plist.size());
|
||||
|
||||
for (size_t i = 0; i < plist.size(); ++i)
|
||||
{
|
||||
if (tis[i+1].is_arithmetic()
|
||||
&& plist[i].get_type_info().is_arithmetic()) {
|
||||
newplist.push_back(Boxed_Number(plist[i]).get_as(tis[i+1]).bv);
|
||||
} else {
|
||||
newplist.push_back(plist[i]);
|
||||
}
|
||||
}
|
||||
const std::vector<Type_Info> &tis = matching_func->second->get_param_types();
|
||||
std::transform(tis.begin() + 1, tis.end(),
|
||||
plist.begin(),
|
||||
std::back_inserter(newplist),
|
||||
[](const Type_Info &ti, const Boxed_Value ¶m) -> Boxed_Value {
|
||||
if (ti.is_arithmetic() && param.get_type_info().is_arithmetic()
|
||||
&& param.get_type_info() != ti) {
|
||||
return Boxed_Number(param).get_as(ti).bv;
|
||||
} else {
|
||||
return param;
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
try {
|
||||
return (*(*matching_func))(newplist, t_conversions);
|
||||
return (*(matching_func->second))(newplist, t_conversions);
|
||||
} catch (const exception::bad_boxed_cast &) {
|
||||
//parameter failed to cast
|
||||
} catch (const exception::arity_error &) {
|
||||
@@ -843,7 +865,7 @@ namespace chaiscript
|
||||
//guard failed to allow the function to execute
|
||||
}
|
||||
|
||||
throw exception::dispatch_error(plist, std::vector<Const_Proxy_Function>(orig, end));
|
||||
throw exception::dispatch_error(plist, std::vector<Const_Proxy_Function>(t_funcs.begin(), t_funcs.end()));
|
||||
|
||||
}
|
||||
}
|
||||
@@ -855,20 +877,20 @@ namespace chaiscript
|
||||
*/
|
||||
template<typename Funcs>
|
||||
Boxed_Value dispatch(const Funcs &funcs,
|
||||
const std::vector<Boxed_Value> &plist, const Type_Conversions &t_conversions)
|
||||
const std::vector<Boxed_Value> &plist, const Type_Conversions_State &t_conversions)
|
||||
{
|
||||
//std::cout << "starting dispatch: " << funcs.size() << '\n';
|
||||
std::multimap<size_t, const Proxy_Function_Base *> ordered_funcs;
|
||||
std::vector<std::pair<size_t, const Proxy_Function_Base *>> ordered_funcs;
|
||||
ordered_funcs.reserve(funcs.size());
|
||||
|
||||
for (const auto &func : funcs)
|
||||
{
|
||||
size_t numdiffs = 0;
|
||||
const auto arity = func->get_arity();
|
||||
|
||||
if (arity == -1)
|
||||
{
|
||||
numdiffs = plist.size();
|
||||
ordered_funcs.emplace_back(plist.size(), func.get());
|
||||
} else if (arity == static_cast<int>(plist.size())) {
|
||||
size_t numdiffs = 0;
|
||||
for (size_t i = 0; i < plist.size(); ++i)
|
||||
{
|
||||
if (!func->get_param_types()[i+1].bare_equal(plist[i].get_type_info()))
|
||||
@@ -876,31 +898,32 @@ namespace chaiscript
|
||||
++numdiffs;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
continue;
|
||||
ordered_funcs.emplace_back(numdiffs, func.get());
|
||||
}
|
||||
|
||||
ordered_funcs.insert(std::make_pair(numdiffs, func.get()));
|
||||
}
|
||||
|
||||
for (const auto &func : ordered_funcs )
|
||||
|
||||
for (size_t i = 0; i <= plist.size(); ++i)
|
||||
{
|
||||
try {
|
||||
if (func.first == 0 || func.second->filter(plist, t_conversions))
|
||||
{
|
||||
return (*(func.second))(plist, t_conversions);
|
||||
for (const auto &func : ordered_funcs )
|
||||
{
|
||||
try {
|
||||
if (func.first == i && func.second->filter(plist, t_conversions))
|
||||
{
|
||||
return (*(func.second))(plist, t_conversions);
|
||||
}
|
||||
} catch (const exception::bad_boxed_cast &) {
|
||||
//parameter failed to cast, try again
|
||||
} catch (const exception::arity_error &) {
|
||||
//invalid num params, try again
|
||||
} catch (const exception::guard_error &) {
|
||||
//guard failed to allow the function to execute,
|
||||
//try again
|
||||
}
|
||||
} catch (const exception::bad_boxed_cast &) {
|
||||
//parameter failed to cast, try again
|
||||
} catch (const exception::arity_error &) {
|
||||
//invalid num params, try again
|
||||
} catch (const exception::guard_error &) {
|
||||
//guard failed to allow the function to execute,
|
||||
//try again
|
||||
}
|
||||
}
|
||||
|
||||
return detail::dispatch_with_conversions(funcs.cbegin(), funcs.cend(), plist, t_conversions);
|
||||
return detail::dispatch_with_conversions(ordered_funcs.cbegin(), ordered_funcs.cend(), plist, t_conversions, funcs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,7 +1,7 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
|
||||
// Copyright 2009-2016, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#ifndef CHAISCRIPT_PROXY_FUNCTIONS_DETAIL_HPP_
|
||||
@@ -16,9 +16,10 @@
|
||||
#include "boxed_value.hpp"
|
||||
#include "handle_return.hpp"
|
||||
#include "type_info.hpp"
|
||||
#include "callable_traits.hpp"
|
||||
|
||||
namespace chaiscript {
|
||||
class Type_Conversions;
|
||||
class Type_Conversions_State;
|
||||
namespace exception {
|
||||
class bad_boxed_cast;
|
||||
} // namespace exception
|
||||
@@ -65,6 +66,10 @@ namespace chaiscript
|
||||
}
|
||||
|
||||
|
||||
#ifdef CHAISCRIPT_GCC_4_6
|
||||
/// \todo REMOVE THIS WHEN WE DROP G++4.6
|
||||
|
||||
|
||||
// Forward declaration
|
||||
template<typename ... Rest>
|
||||
struct Try_Cast;
|
||||
@@ -72,7 +77,7 @@ namespace chaiscript
|
||||
template<typename Param, typename ... Rest>
|
||||
struct Try_Cast<Param, Rest...>
|
||||
{
|
||||
static void do_try(const std::vector<Boxed_Value> ¶ms, size_t generation, const Type_Conversions &t_conversions)
|
||||
static void do_try(const std::vector<Boxed_Value> ¶ms, size_t generation, const Type_Conversions_State &t_conversions)
|
||||
{
|
||||
boxed_cast<Param>(params[generation], &t_conversions);
|
||||
Try_Cast<Rest...>::do_try(params, generation+1, t_conversions);
|
||||
@@ -83,7 +88,7 @@ namespace chaiscript
|
||||
template<>
|
||||
struct Try_Cast<>
|
||||
{
|
||||
static void do_try(const std::vector<Boxed_Value> &, size_t, const Type_Conversions &)
|
||||
static void do_try(const std::vector<Boxed_Value> &, size_t, const Type_Conversions_State &)
|
||||
{
|
||||
}
|
||||
};
|
||||
@@ -96,8 +101,8 @@ namespace chaiscript
|
||||
*/
|
||||
template<typename Ret, typename ... Params>
|
||||
bool compare_types_cast(Ret (*)(Params...),
|
||||
const std::vector<Boxed_Value> ¶ms, const Type_Conversions &t_conversions)
|
||||
{
|
||||
const std::vector<Boxed_Value> ¶ms, const Type_Conversions_State &t_conversions)
|
||||
{
|
||||
try {
|
||||
Try_Cast<Params...>::do_try(params, 0, t_conversions);
|
||||
} catch (const exception::bad_boxed_cast &) {
|
||||
@@ -111,9 +116,9 @@ namespace chaiscript
|
||||
struct Call_Func
|
||||
{
|
||||
|
||||
template<typename ... InnerParams>
|
||||
static Ret do_call(const std::function<Ret (Params...)> &f,
|
||||
const std::vector<Boxed_Value> ¶ms, const Type_Conversions &t_conversions, InnerParams &&... innerparams)
|
||||
template<typename Callable, typename ... InnerParams>
|
||||
static Ret do_call(const Callable &f,
|
||||
const std::vector<Boxed_Value> ¶ms, const Type_Conversions_State &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]);
|
||||
}
|
||||
@@ -126,9 +131,9 @@ namespace chaiscript
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4100) /// Disable unreferenced formal parameter warning, which only shows up in MSVC I don't think there's any way around it \todo evaluate this
|
||||
#endif
|
||||
template<typename ... InnerParams>
|
||||
static Ret do_call(const std::function<Ret (Params...)> &f,
|
||||
const std::vector<Boxed_Value> &, const Type_Conversions &t_conversions, InnerParams &&... innerparams)
|
||||
template<typename Callable, typename ... InnerParams>
|
||||
static Ret do_call(const Callable &f,
|
||||
const std::vector<Boxed_Value> &, const Type_Conversions_State &t_conversions, InnerParams &&... innerparams)
|
||||
{
|
||||
return f(boxed_cast<Params>(std::forward<InnerParams>(innerparams), &t_conversions)...);
|
||||
}
|
||||
@@ -143,9 +148,9 @@ namespace chaiscript
|
||||
* if any unboxing fails the execution of the function fails and
|
||||
* the bad_boxed_cast is passed up to the caller.
|
||||
*/
|
||||
template<typename Ret, typename ... Params>
|
||||
Ret call_func(const std::function<Ret (Params...)> &f,
|
||||
const std::vector<Boxed_Value> ¶ms, const Type_Conversions &t_conversions)
|
||||
template<typename Callable, typename Ret, typename ... Params>
|
||||
Ret call_func(const chaiscript::dispatch::detail::Function_Signature<Ret (Params...)> &, const Callable &f,
|
||||
const std::vector<Boxed_Value> ¶ms, const Type_Conversions_State &t_conversions)
|
||||
{
|
||||
if (params.size() == sizeof...(Params))
|
||||
{
|
||||
@@ -155,6 +160,82 @@ namespace chaiscript
|
||||
throw exception::arity_error(static_cast<int>(params.size()), sizeof...(Params));
|
||||
}
|
||||
|
||||
|
||||
|
||||
#else
|
||||
|
||||
template<size_t ... I>
|
||||
struct Indexes
|
||||
{
|
||||
};
|
||||
|
||||
template<size_t S, size_t ... I>
|
||||
struct Make_Indexes
|
||||
{
|
||||
typedef typename Make_Indexes<S-1, I..., sizeof...(I)>::indexes indexes;
|
||||
};
|
||||
|
||||
template<size_t ... I>
|
||||
struct Make_Indexes<0, I...>
|
||||
{
|
||||
typedef Indexes<I...> indexes;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Used by Proxy_Function_Impl to determine if it is equivalent to another
|
||||
* Proxy_Function_Impl object. This function is primarily used to prevent
|
||||
* registration of two functions with the exact same signatures
|
||||
*/
|
||||
template<typename Ret, typename ... Params, size_t ... I>
|
||||
bool compare_types_cast(Indexes<I...>, Ret (*)(Params...),
|
||||
const std::vector<Boxed_Value> ¶ms, const Type_Conversions_State &t_conversions)
|
||||
{
|
||||
try {
|
||||
(void)params; (void)t_conversions;
|
||||
(void)std::initializer_list<int>{(boxed_cast<Params>(params[I], &t_conversions), 0)...};
|
||||
return true;
|
||||
} catch (const exception::bad_boxed_cast &) {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
template<typename Ret, typename ... Params>
|
||||
bool compare_types_cast(Ret (*f)(Params...),
|
||||
const std::vector<Boxed_Value> ¶ms, const Type_Conversions_State &t_conversions)
|
||||
{
|
||||
typedef typename Make_Indexes<sizeof...(Params)>::indexes indexes;
|
||||
return compare_types_cast(indexes(), f, params, t_conversions);
|
||||
}
|
||||
|
||||
|
||||
template<typename Callable, typename Ret, typename ... Params, size_t ... I>
|
||||
Ret call_func(const chaiscript::dispatch::detail::Function_Signature<Ret (Params...)> &, Indexes<I...>, const Callable &f,
|
||||
const std::vector<Boxed_Value> ¶ms, const Type_Conversions_State &t_conversions)
|
||||
{
|
||||
(void)params; (void)t_conversions;
|
||||
return f(boxed_cast<Params>(params[I], &t_conversions)...);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Used by Proxy_Function_Impl to perform typesafe execution of a function.
|
||||
* The function attempts to unbox each parameter to the expected type.
|
||||
* if any unboxing fails the execution of the function fails and
|
||||
* the bad_boxed_cast is passed up to the caller.
|
||||
*/
|
||||
template<typename Callable, typename Ret, typename ... Params>
|
||||
Ret call_func(const chaiscript::dispatch::detail::Function_Signature<Ret (Params...)> &sig, const Callable &f,
|
||||
const std::vector<Boxed_Value> ¶ms, const Type_Conversions_State &t_conversions)
|
||||
{
|
||||
typedef typename Make_Indexes<sizeof...(Params)>::indexes indexes;
|
||||
return call_func(sig, indexes(), f, params, t_conversions);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -170,20 +251,20 @@ namespace chaiscript
|
||||
template<typename Ret>
|
||||
struct Do_Call
|
||||
{
|
||||
template<typename Fun>
|
||||
static Boxed_Value go(const std::function<Fun> &fun, const std::vector<Boxed_Value> ¶ms, const Type_Conversions &t_conversions)
|
||||
template<typename Signature, typename Callable>
|
||||
static Boxed_Value go(const Callable &fun, const std::vector<Boxed_Value> ¶ms, const Type_Conversions_State &t_conversions)
|
||||
{
|
||||
return Handle_Return<Ret>::handle(call_func(fun, params, t_conversions));
|
||||
return Handle_Return<Ret>::handle(call_func(Function_Signature<Signature>(), fun, params, t_conversions));
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct Do_Call<void>
|
||||
{
|
||||
template<typename Fun>
|
||||
static Boxed_Value go(const std::function<Fun> &fun, const std::vector<Boxed_Value> ¶ms, const Type_Conversions &t_conversions)
|
||||
template<typename Signature, typename Callable>
|
||||
static Boxed_Value go(const Callable &fun, const std::vector<Boxed_Value> ¶ms, const Type_Conversions_State &t_conversions)
|
||||
{
|
||||
call_func(fun, params, t_conversions);
|
||||
call_func(Function_Signature<Signature>(), fun, params, t_conversions);
|
||||
return Handle_Return<void>::handle();
|
||||
}
|
||||
};
|
||||
|
@@ -1,13 +1,12 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
|
||||
// Copyright 2009-2016, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#ifndef CHAISCRIPT_REGISTER_FUNCTION_HPP_
|
||||
#define CHAISCRIPT_REGISTER_FUNCTION_HPP_
|
||||
|
||||
#include <functional>
|
||||
#include <type_traits>
|
||||
|
||||
#include "bind_first.hpp"
|
||||
@@ -15,55 +14,6 @@
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
namespace dispatch
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
template<typename T>
|
||||
struct FunctionSignature
|
||||
{
|
||||
};
|
||||
|
||||
template<typename Sig>
|
||||
struct FunctionSignature<std::function<Sig> >
|
||||
{
|
||||
typedef Sig Signature;
|
||||
};
|
||||
|
||||
template<typename Ret, typename ... Args>
|
||||
std::function<Ret (Args...) > to_function(Ret (*func)(Args...))
|
||||
{
|
||||
return std::function<Ret (Args...)>(func);
|
||||
}
|
||||
|
||||
template<typename Ret, typename Class, typename ... Args>
|
||||
std::function<Ret (Class &, Args...) > to_function(Ret (Class::*func)(Args...))
|
||||
{
|
||||
#ifdef CHAISCRIPT_MSVC
|
||||
/// \todo this std::mem_fn wrap shouldn't be necessary but type conversions for
|
||||
/// std::function for member function pointers seems to be broken in MSVC
|
||||
return std::function<Ret(Class &, Args...)>(std::mem_fn(func));
|
||||
#else
|
||||
return std::function<Ret(Class &, Args...)>(func);
|
||||
#endif
|
||||
}
|
||||
|
||||
template<typename Ret, typename Class, typename ... Args>
|
||||
std::function<Ret (const Class &, Args...) > to_function(Ret (Class::*func)(Args...) const)
|
||||
{
|
||||
#if defined(CHAISCRIPT_MSVC) || defined(CHAISCRIPT_LIBCPP)
|
||||
/// \todo this std::mem_fn wrap shouldn't be necessary but type conversions for
|
||||
/// std::function for member function pointers seems to be broken in MSVC
|
||||
return std::function<Ret (const Class &, Args...)>([func](const Class &o, Args... args)->Ret {
|
||||
return (o.*func)(std::forward<Args>(args)...);
|
||||
});
|
||||
#else
|
||||
return std::function<Ret(const Class &, Args...)>(func);
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/// \brief Creates a new Proxy_Function object from a free function, member function or data member
|
||||
/// \param[in] t Function / member to expose
|
||||
@@ -88,22 +38,39 @@ namespace chaiscript
|
||||
template<typename T>
|
||||
Proxy_Function fun(const T &t)
|
||||
{
|
||||
typedef typename dispatch::detail::Callable_Traits<T>::Signature Signature;
|
||||
|
||||
return Proxy_Function(
|
||||
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Impl<typename dispatch::detail::FunctionSignature<decltype(dispatch::detail::to_function(t)) >::Signature>>(dispatch::detail::to_function(t)));
|
||||
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Signature, T>>(t));
|
||||
}
|
||||
|
||||
template<typename Ret, typename ... Param>
|
||||
Proxy_Function fun(Ret (*func)(Param...))
|
||||
{
|
||||
auto fun_call = dispatch::detail::Fun_Caller<Ret, Param...>(func);
|
||||
|
||||
return Proxy_Function(
|
||||
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Ret (Param...), decltype(fun_call)>>(fun_call));
|
||||
|
||||
}
|
||||
|
||||
template<typename Ret, typename Class, typename ... Param>
|
||||
Proxy_Function fun(Ret (Class::*func)(Param...) const)
|
||||
Proxy_Function fun(Ret (Class::*t_func)(Param...) const)
|
||||
{
|
||||
auto call = dispatch::detail::Const_Caller<Ret, Class, Param...>(t_func);
|
||||
|
||||
return Proxy_Function(
|
||||
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Impl<typename dispatch::detail::FunctionSignature<decltype(dispatch::detail::to_function(func)) >::Signature>>(dispatch::detail::to_function(func)));
|
||||
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Ret (const Class &, Param...), decltype(call)>>(call));
|
||||
}
|
||||
|
||||
template<typename Ret, typename Class, typename ... Param>
|
||||
Proxy_Function fun(Ret (Class::*func)(Param...))
|
||||
Proxy_Function fun(Ret (Class::*t_func)(Param...))
|
||||
{
|
||||
auto call = dispatch::detail::Caller<Ret, Class, Param...>(t_func);
|
||||
|
||||
return Proxy_Function(
|
||||
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Impl<typename dispatch::detail::FunctionSignature<decltype(dispatch::detail::to_function(func)) >::Signature>>(dispatch::detail::to_function(func)));
|
||||
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Ret (Class &, Param...), decltype(call)>>(call));
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -114,22 +81,6 @@ namespace chaiscript
|
||||
}
|
||||
|
||||
|
||||
/// \brief Creates a new Proxy_Function object from a std::function object
|
||||
/// \param[in] f std::function to expose to ChaiScript
|
||||
///
|
||||
/// \b Example:
|
||||
/// \code
|
||||
/// std::function<int (char, float, std::string)> f = get_some_function();
|
||||
/// chaiscript::ChaiScript chai;
|
||||
/// chai.add(fun(f), "some_function");
|
||||
/// \endcode
|
||||
///
|
||||
/// \sa \ref adding_functions
|
||||
template<typename T>
|
||||
Proxy_Function fun(const std::function<T> &f)
|
||||
{
|
||||
return Proxy_Function(chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Impl<T>>(f));
|
||||
}
|
||||
|
||||
|
||||
/// \brief Creates a new Proxy_Function object from a free function, member function or data member and binds the first parameter of it
|
||||
|
@@ -1,7 +1,7 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
|
||||
// Copyright 2009-2016, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#ifndef CHAISCRIPT_DYNAMIC_CAST_CONVERSION_HPP_
|
||||
@@ -92,6 +92,11 @@ namespace chaiscript
|
||||
return m_from;
|
||||
}
|
||||
|
||||
virtual bool bidir() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual ~Type_Conversion_Base() {}
|
||||
|
||||
protected:
|
||||
@@ -107,6 +112,62 @@ namespace chaiscript
|
||||
|
||||
};
|
||||
|
||||
template<typename From, typename To>
|
||||
class Static_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())
|
||||
{
|
||||
return Boxed_Value(
|
||||
[&]()->std::shared_ptr<const To>{
|
||||
if (auto data = std::static_pointer_cast<const To>(detail::Cast_Helper<std::shared_ptr<const From> >::cast(t_from, nullptr)))
|
||||
{
|
||||
return data;
|
||||
} else {
|
||||
throw std::bad_cast();
|
||||
}
|
||||
}()
|
||||
);
|
||||
} else {
|
||||
return Boxed_Value(
|
||||
[&]()->std::shared_ptr<To>{
|
||||
if (auto data = std::static_pointer_cast<To>(detail::Cast_Helper<std::shared_ptr<From> >::cast(t_from, nullptr)))
|
||||
{
|
||||
return data;
|
||||
} else {
|
||||
throw std::bad_cast();
|
||||
}
|
||||
}()
|
||||
);
|
||||
}
|
||||
} 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 = static_cast<const To &>(d);
|
||||
return Boxed_Value(std::cref(data));
|
||||
} else {
|
||||
From &d = detail::Cast_Helper<From &>::cast(t_from, nullptr);
|
||||
To &data = static_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 From, typename To>
|
||||
class Dynamic_Caster
|
||||
{
|
||||
@@ -168,8 +229,10 @@ namespace chaiscript
|
||||
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
|
||||
{
|
||||
@@ -186,10 +249,36 @@ namespace chaiscript
|
||||
|
||||
virtual Boxed_Value convert(const Boxed_Value &t_derived) const CHAISCRIPT_OVERRIDE
|
||||
{
|
||||
return Dynamic_Caster<Derived, Base>::cast(t_derived);
|
||||
return Static_Caster<Derived, Base>::cast(t_derived);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Base, typename Derived>
|
||||
class Static_Conversion_Impl : public Type_Conversion_Base
|
||||
{
|
||||
public:
|
||||
Static_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
|
||||
{
|
||||
throw chaiscript::exception::bad_boxed_dynamic_cast(t_base.get_type_info(), typeid(Derived), "Unable to cast down inheritance hierarchy with non-polymorphic types");
|
||||
}
|
||||
|
||||
virtual bool bidir() const CHAISCRIPT_OVERRIDE
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual Boxed_Value convert(const Boxed_Value &t_derived) const CHAISCRIPT_OVERRIDE
|
||||
{
|
||||
return Static_Caster<Derived, Base>::cast(t_derived);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
template<typename Callable>
|
||||
class Type_Conversion_Impl : public Type_Conversion_Base
|
||||
@@ -212,15 +301,30 @@ namespace chaiscript
|
||||
return m_func(t_from);
|
||||
}
|
||||
|
||||
virtual bool bidir() const CHAISCRIPT_OVERRIDE
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
Callable m_func;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
class Type_Conversions
|
||||
{
|
||||
public:
|
||||
struct Conversion_Saves
|
||||
{
|
||||
Conversion_Saves()
|
||||
: enabled(false)
|
||||
{}
|
||||
|
||||
bool enabled;
|
||||
std::vector<Boxed_Value> saves;
|
||||
};
|
||||
|
||||
struct Less_Than
|
||||
{
|
||||
bool operator()(const std::type_info *t_lhs, const std::type_info *t_rhs) const
|
||||
@@ -242,7 +346,7 @@ namespace chaiscript
|
||||
Type_Conversions(const Type_Conversions &t_other)
|
||||
: m_mutex(),
|
||||
m_conversions(t_other.get_conversions()),
|
||||
m_convertableTypes(),
|
||||
m_convertableTypes(t_other.m_convertableTypes),
|
||||
m_num_types(m_conversions.size()),
|
||||
m_thread_cache(this),
|
||||
m_conversion_saves(this)
|
||||
@@ -288,19 +392,18 @@ namespace chaiscript
|
||||
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);
|
||||
return has_conversion(to, from);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
template<typename To>
|
||||
Boxed_Value boxed_type_conversion(const Boxed_Value &from) const
|
||||
Boxed_Value boxed_type_conversion(Conversion_Saves &t_saves, 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);
|
||||
if (t_saves.enabled) t_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");
|
||||
@@ -310,11 +413,11 @@ namespace chaiscript
|
||||
}
|
||||
|
||||
template<typename From>
|
||||
Boxed_Value boxed_type_down_conversion(const Boxed_Value &to) const
|
||||
Boxed_Value boxed_type_down_conversion(Conversion_Saves &t_saves, 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);
|
||||
if (t_saves.enabled) t_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");
|
||||
@@ -323,22 +426,22 @@ namespace chaiscript
|
||||
}
|
||||
}
|
||||
|
||||
void enable_conversion_saves(bool t_val)
|
||||
static void enable_conversion_saves(Conversion_Saves &t_saves, bool t_val)
|
||||
{
|
||||
m_conversion_saves->enabled = t_val;
|
||||
t_saves.enabled = t_val;
|
||||
}
|
||||
|
||||
std::vector<Boxed_Value> take_saves()
|
||||
std::vector<Boxed_Value> take_saves(Conversion_Saves &t_saves)
|
||||
{
|
||||
std::vector<Boxed_Value> ret;
|
||||
std::swap(ret, m_conversion_saves->saves);
|
||||
std::swap(ret, t_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();
|
||||
return find_bidir(to, from) != m_conversions.end();
|
||||
}
|
||||
|
||||
std::shared_ptr<detail::Type_Conversion_Base> get_conversion(const Type_Info &to, const Type_Info &from) const
|
||||
@@ -355,7 +458,23 @@ namespace chaiscript
|
||||
}
|
||||
}
|
||||
|
||||
Conversion_Saves &conversion_saves() const {
|
||||
return *m_conversion_saves;
|
||||
}
|
||||
|
||||
private:
|
||||
std::set<std::shared_ptr<detail::Type_Conversion_Base> >::const_iterator find_bidir(
|
||||
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) -> bool
|
||||
{
|
||||
return (conversion->to().bare_equal(to) && conversion->from().bare_equal(from))
|
||||
|| (conversion->bidir() && conversion->from().bare_equal(to) && conversion->to().bare_equal(from));
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
std::set<std::shared_ptr<detail::Type_Conversion_Base> >::const_iterator find(
|
||||
const Type_Info &to, const Type_Info &from) const
|
||||
{
|
||||
@@ -375,15 +494,6 @@ namespace chaiscript
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
@@ -393,6 +503,33 @@ namespace chaiscript
|
||||
mutable chaiscript::detail::threading::Thread_Storage<Conversion_Saves> m_conversion_saves;
|
||||
};
|
||||
|
||||
class Type_Conversions_State
|
||||
{
|
||||
public:
|
||||
Type_Conversions_State(const Type_Conversions &t_conversions,
|
||||
Type_Conversions::Conversion_Saves &t_saves)
|
||||
: m_conversions(t_conversions),
|
||||
m_saves(t_saves)
|
||||
{
|
||||
}
|
||||
|
||||
const Type_Conversions *operator->() const {
|
||||
return &m_conversions.get();
|
||||
}
|
||||
|
||||
const Type_Conversions *get() const {
|
||||
return &m_conversions.get();
|
||||
}
|
||||
|
||||
Type_Conversions::Conversion_Saves &saves() const {
|
||||
return m_saves;
|
||||
}
|
||||
|
||||
private:
|
||||
std::reference_wrapper<const Type_Conversions> m_conversions;
|
||||
std::reference_wrapper<Type_Conversions::Conversion_Saves> m_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
|
||||
@@ -417,17 +554,26 @@ namespace chaiscript
|
||||
/// \endcode
|
||||
///
|
||||
template<typename Base, typename Derived>
|
||||
Type_Conversion base_class()
|
||||
Type_Conversion base_class(typename std::enable_if<std::is_polymorphic<Base>::value && std::is_polymorphic<Derived>::value>::type* = nullptr)
|
||||
{
|
||||
//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 chaiscript::make_shared<detail::Type_Conversion_Base, detail::Dynamic_Conversion_Impl<Base, Derived>>();
|
||||
}
|
||||
|
||||
template<typename Base, typename Derived>
|
||||
Type_Conversion base_class(typename std::enable_if<!std::is_polymorphic<Base>::value || !std::is_polymorphic<Derived>::value>::type* = nullptr)
|
||||
{
|
||||
//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");
|
||||
|
||||
return chaiscript::make_shared<detail::Type_Conversion_Base, detail::Static_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)
|
||||
@@ -458,6 +604,40 @@ namespace chaiscript
|
||||
return chaiscript::make_shared<detail::Type_Conversion_Base, detail::Type_Conversion_Impl<decltype(func)>>(user_type<From>(), user_type<To>(), func);
|
||||
}
|
||||
|
||||
template<typename To>
|
||||
Type_Conversion vector_conversion()
|
||||
{
|
||||
auto func = [](const Boxed_Value &t_bv) -> Boxed_Value {
|
||||
const std::vector<Boxed_Value> &from_vec = detail::Cast_Helper<const std::vector<Boxed_Value> &>::cast(t_bv, nullptr);
|
||||
|
||||
To vec;
|
||||
vec.reserve(from_vec.size());
|
||||
for (const Boxed_Value &bv : from_vec) {
|
||||
vec.push_back(detail::Cast_Helper<typename To::value_type>::cast(bv, nullptr));
|
||||
}
|
||||
|
||||
return Boxed_Value(std::move(vec));
|
||||
};
|
||||
|
||||
return chaiscript::make_shared<detail::Type_Conversion_Base, detail::Type_Conversion_Impl<decltype(func)>>(user_type<std::vector<Boxed_Value>>(), user_type<To>(), func);
|
||||
}
|
||||
|
||||
template<typename To>
|
||||
Type_Conversion map_conversion()
|
||||
{
|
||||
auto func = [](const Boxed_Value &t_bv) -> Boxed_Value {
|
||||
const std::map<std::string, Boxed_Value> &from_map = detail::Cast_Helper<const std::map<std::string, Boxed_Value> &>::cast(t_bv, nullptr);
|
||||
|
||||
To map;
|
||||
for (const std::pair<std::string, Boxed_Value> &p : from_map) {
|
||||
map.insert(std::make_pair(p.first, detail::Cast_Helper<typename To::mapped_type>::cast(p.second, nullptr)));
|
||||
}
|
||||
|
||||
return Boxed_Value(std::move(map));
|
||||
};
|
||||
|
||||
return chaiscript::make_shared<detail::Type_Conversion_Base, detail::Type_Conversion_Impl<decltype(func)>>(user_type<std::map<std::string, Boxed_Value>>(), user_type<To>(), func);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@@ -1,7 +1,7 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
|
||||
// Copyright 2009-2016, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#ifndef CHAISCRIPT_TYPE_INFO_HPP_
|
||||
@@ -32,17 +32,17 @@ namespace chaiscript
|
||||
CHAISCRIPT_CONSTEXPR Type_Info(bool t_is_const, bool t_is_reference, bool t_is_pointer, bool t_is_void,
|
||||
bool t_is_arithmetic, const std::type_info *t_ti, const std::type_info *t_bare_ti)
|
||||
: m_type_info(t_ti), m_bare_type_info(t_bare_ti),
|
||||
m_is_const(t_is_const), m_is_reference(t_is_reference), m_is_pointer(t_is_pointer),
|
||||
m_is_void(t_is_void), m_is_arithmetic(t_is_arithmetic),
|
||||
m_is_undef(false)
|
||||
m_flags((static_cast<unsigned int>(t_is_const) << is_const_flag)
|
||||
+ (static_cast<unsigned int>(t_is_reference) << is_reference_flag)
|
||||
+ (static_cast<unsigned int>(t_is_pointer) << is_pointer_flag)
|
||||
+ (static_cast<unsigned int>(t_is_void) << is_void_flag)
|
||||
+ (static_cast<unsigned int>(t_is_arithmetic) << is_arithmetic_flag))
|
||||
{
|
||||
}
|
||||
|
||||
CHAISCRIPT_CONSTEXPR Type_Info()
|
||||
: m_type_info(nullptr), m_bare_type_info(nullptr),
|
||||
m_is_const(false), m_is_reference(false), m_is_pointer(false),
|
||||
m_is_void(false), m_is_arithmetic(false),
|
||||
m_is_undef(true)
|
||||
m_flags(1 << is_undef_flag)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -60,6 +60,16 @@ namespace chaiscript
|
||||
return m_type_info < ti.m_type_info;
|
||||
}
|
||||
|
||||
CHAISCRIPT_CONSTEXPR bool operator!=(const Type_Info &ti) const CHAISCRIPT_NOEXCEPT
|
||||
{
|
||||
return !(operator==(ti));
|
||||
}
|
||||
|
||||
CHAISCRIPT_CONSTEXPR bool operator!=(const std::type_info &ti) const CHAISCRIPT_NOEXCEPT
|
||||
{
|
||||
return !(operator==(ti));
|
||||
}
|
||||
|
||||
CHAISCRIPT_CONSTEXPR bool operator==(const Type_Info &ti) const CHAISCRIPT_NOEXCEPT
|
||||
{
|
||||
return ti.m_type_info == m_type_info
|
||||
@@ -83,12 +93,12 @@ namespace chaiscript
|
||||
&& (*m_bare_type_info) == ti;
|
||||
}
|
||||
|
||||
CHAISCRIPT_CONSTEXPR bool is_const() const CHAISCRIPT_NOEXCEPT { return m_is_const; }
|
||||
CHAISCRIPT_CONSTEXPR bool is_reference() const CHAISCRIPT_NOEXCEPT { return m_is_reference; }
|
||||
CHAISCRIPT_CONSTEXPR bool is_void() const CHAISCRIPT_NOEXCEPT { return m_is_void; }
|
||||
CHAISCRIPT_CONSTEXPR bool is_arithmetic() const CHAISCRIPT_NOEXCEPT { return m_is_arithmetic; }
|
||||
CHAISCRIPT_CONSTEXPR bool is_undef() const CHAISCRIPT_NOEXCEPT { return m_is_undef || m_bare_type_info == nullptr; }
|
||||
CHAISCRIPT_CONSTEXPR bool is_pointer() const CHAISCRIPT_NOEXCEPT { return m_is_pointer; }
|
||||
CHAISCRIPT_CONSTEXPR bool is_const() const CHAISCRIPT_NOEXCEPT { return (m_flags & (1 << is_const_flag)) != 0; }
|
||||
CHAISCRIPT_CONSTEXPR bool is_reference() const CHAISCRIPT_NOEXCEPT { return (m_flags & (1 << is_reference_flag)) != 0; }
|
||||
CHAISCRIPT_CONSTEXPR bool is_void() const CHAISCRIPT_NOEXCEPT { return (m_flags & (1 << is_void_flag)) != 0; }
|
||||
CHAISCRIPT_CONSTEXPR bool is_arithmetic() const CHAISCRIPT_NOEXCEPT { return (m_flags & (1 << is_arithmetic_flag)) != 0; }
|
||||
CHAISCRIPT_CONSTEXPR bool is_undef() const CHAISCRIPT_NOEXCEPT { return (m_flags & (1 << is_undef_flag)) != 0; }
|
||||
CHAISCRIPT_CONSTEXPR bool is_pointer() const CHAISCRIPT_NOEXCEPT { return (m_flags & (1 << is_pointer_flag)) != 0; }
|
||||
|
||||
std::string name() const
|
||||
{
|
||||
@@ -118,12 +128,13 @@ namespace chaiscript
|
||||
private:
|
||||
const std::type_info *m_type_info;
|
||||
const std::type_info *m_bare_type_info;
|
||||
bool m_is_const;
|
||||
bool m_is_reference;
|
||||
bool m_is_pointer;
|
||||
bool m_is_void;
|
||||
bool m_is_arithmetic;
|
||||
bool m_is_undef;
|
||||
unsigned int m_flags;
|
||||
static const int is_const_flag = 0;
|
||||
static const int is_reference_flag = 1;
|
||||
static const int is_pointer_flag = 2;
|
||||
static const int is_void_flag = 3;
|
||||
static const int is_arithmetic_flag = 4;
|
||||
static const int is_undef_flag = 5;
|
||||
};
|
||||
|
||||
namespace detail
|
||||
@@ -134,11 +145,13 @@ namespace chaiscript
|
||||
{
|
||||
typedef T type;
|
||||
|
||||
CHAISCRIPT_CONSTEXPR static Type_Info get()
|
||||
static Type_Info get()
|
||||
{
|
||||
return Type_Info(std::is_const<typename std::remove_pointer<typename std::remove_reference<T>::type>::type>::value, std::is_reference<T>::value, std::is_pointer<T>::value,
|
||||
return Type_Info(std::is_const<typename std::remove_pointer<typename std::remove_reference<T>::type>::type>::value,
|
||||
std::is_reference<T>::value, std::is_pointer<T>::value,
|
||||
std::is_void<T>::value,
|
||||
std::is_arithmetic<T>::value && !std::is_same<typename std::remove_const<T>::type, bool>::value,
|
||||
(std::is_arithmetic<T>::value || std::is_arithmetic<typename std::remove_reference<T>::type>::value)
|
||||
&& !std::is_same<typename std::remove_const<typename std::remove_reference<T>::type>::type, bool>::value,
|
||||
&typeid(T),
|
||||
&typeid(typename Bare_Type<T>::type));
|
||||
}
|
||||
@@ -149,26 +162,31 @@ namespace chaiscript
|
||||
{
|
||||
typedef T type;
|
||||
|
||||
CHAISCRIPT_CONSTEXPR static Type_Info get()
|
||||
static Type_Info get()
|
||||
{
|
||||
return Type_Info(std::is_const<T>::value, std::is_reference<T>::value, std::is_pointer<T>::value,
|
||||
std::is_void<T>::value,
|
||||
std::is_arithmetic<T>::value && !std::is_same<typename std::remove_const<T>::type, bool>::value,
|
||||
std::is_arithmetic<T>::value && !std::is_same<typename std::remove_const<typename std::remove_reference<T>::type>::type, bool>::value,
|
||||
&typeid(std::shared_ptr<T> ),
|
||||
&typeid(typename Bare_Type<T>::type));
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct Get_Type_Info<std::shared_ptr<T> &> : Get_Type_Info<std::shared_ptr<T>>
|
||||
{
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct Get_Type_Info<const std::shared_ptr<T> &>
|
||||
{
|
||||
typedef T type;
|
||||
|
||||
CHAISCRIPT_CONSTEXPR static Type_Info get()
|
||||
static Type_Info get()
|
||||
{
|
||||
return Type_Info(std::is_const<T>::value, std::is_reference<T>::value, std::is_pointer<T>::value,
|
||||
std::is_void<T>::value,
|
||||
std::is_arithmetic<T>::value && !std::is_same<typename std::remove_const<T>::type, bool>::value,
|
||||
std::is_arithmetic<T>::value && !std::is_same<typename std::remove_const<typename std::remove_reference<T>::type>::type, bool>::value,
|
||||
&typeid(const std::shared_ptr<T> &),
|
||||
&typeid(typename Bare_Type<T>::type));
|
||||
}
|
||||
@@ -179,11 +197,11 @@ namespace chaiscript
|
||||
{
|
||||
typedef T type;
|
||||
|
||||
CHAISCRIPT_CONSTEXPR static Type_Info get()
|
||||
static Type_Info get()
|
||||
{
|
||||
return Type_Info(std::is_const<T>::value, std::is_reference<T>::value, std::is_pointer<T>::value,
|
||||
std::is_void<T>::value,
|
||||
std::is_arithmetic<T>::value && !std::is_same<typename std::remove_const<T>::type, bool>::value,
|
||||
std::is_arithmetic<T>::value && !std::is_same<typename std::remove_const<typename std::remove_reference<T>::type>::type, bool>::value,
|
||||
&typeid(std::reference_wrapper<T> ),
|
||||
&typeid(typename Bare_Type<T>::type));
|
||||
}
|
||||
@@ -194,11 +212,11 @@ namespace chaiscript
|
||||
{
|
||||
typedef T type;
|
||||
|
||||
CHAISCRIPT_CONSTEXPR static Type_Info get()
|
||||
static Type_Info get()
|
||||
{
|
||||
return Type_Info(std::is_const<T>::value, std::is_reference<T>::value, std::is_pointer<T>::value,
|
||||
std::is_void<T>::value,
|
||||
std::is_arithmetic<T>::value && !std::is_same<typename std::remove_const<T>::type, bool>::value,
|
||||
std::is_arithmetic<T>::value && !std::is_same<typename std::remove_const<typename std::remove_reference<T>::type>::type, bool>::value,
|
||||
&typeid(const std::reference_wrapper<T> &),
|
||||
&typeid(typename Bare_Type<T>::type));
|
||||
}
|
||||
@@ -216,7 +234,7 @@ namespace chaiscript
|
||||
/// chaiscript::Type_Info ti = chaiscript::user_type(i);
|
||||
/// \endcode
|
||||
template<typename T>
|
||||
CHAISCRIPT_CONSTEXPR Type_Info user_type(const T &/*t*/)
|
||||
Type_Info user_type(const T &/*t*/)
|
||||
{
|
||||
return detail::Get_Type_Info<T>::get();
|
||||
}
|
||||
@@ -231,7 +249,7 @@ namespace chaiscript
|
||||
/// chaiscript::Type_Info ti = chaiscript::user_type<int>();
|
||||
/// \endcode
|
||||
template<typename T>
|
||||
CHAISCRIPT_CONSTEXPR Type_Info user_type()
|
||||
Type_Info user_type()
|
||||
{
|
||||
return detail::Get_Type_Info<T>::get();
|
||||
}
|
||||
|
@@ -1,7 +1,7 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
|
||||
// Copyright 2009-2016, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#ifndef CHAISCRIPT_ALGEBRAIC_HPP_
|
||||
|
@@ -1,7 +1,7 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
|
||||
// Copyright 2009-2016, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#ifndef CHAISCRIPT_COMMON_HPP_
|
||||
@@ -34,7 +34,7 @@ namespace chaiscript
|
||||
/// Types of AST nodes available to the parser and eval
|
||||
class AST_Node_Type {
|
||||
public:
|
||||
enum Type { Error, Int, Float, Id, Char, Str, Eol, Fun_Call, Inplace_Fun_Call, Arg_List, Variable, Equation, Var_Decl,
|
||||
enum Type { Error, Int, Float, Id, Char, Str, Eol, Fun_Call, Arg_List, Variable, Equation, Var_Decl,
|
||||
Comparison, Addition, Subtraction, Multiplication, Division, Modulus, Array_Call, Dot_Access, Quoted_String, Single_Quoted_String,
|
||||
Lambda, Block, Def, While, If, For, Inline_Array, Inline_Map, Return, File, Prefix, Break, Continue, Map_Pair, Value_Range,
|
||||
Inline_Range, Annotation, Try, Catch, Finally, Method, Attr_Decl, Shift, Equality, Bitwise_And, Bitwise_Xor, Bitwise_Or,
|
||||
@@ -47,7 +47,7 @@ namespace chaiscript
|
||||
|
||||
/// Helper lookup to get the name of each node type
|
||||
const char *ast_node_type_to_string(int ast_node_type) {
|
||||
const char *ast_node_types[] = { "Internal Parser Error", "Int", "Float", "Id", "Char", "Str", "Eol", "Fun_Call", "Inplace_Fun_Call", "Arg_List", "Variable", "Equation", "Var_Decl",
|
||||
const char *ast_node_types[] = { "Internal Parser Error", "Int", "Float", "Id", "Char", "Str", "Eol", "Fun_Call", "Arg_List", "Variable", "Equation", "Var_Decl",
|
||||
"Comparison", "Addition", "Subtraction", "Multiplication", "Division", "Modulus", "Array_Call", "Dot_Access", "Quoted_String", "Single_Quoted_String",
|
||||
"Lambda", "Block", "Def", "While", "If", "For", "Inline_Array", "Inline_Map", "Return", "File", "Prefix", "Break", "Continue", "Map_Pair", "Value_Range",
|
||||
"Inline_Range", "Annotation", "Try", "Catch", "Finally", "Method", "Attr_Decl", "Shift", "Equality", "Bitwise_And", "Bitwise_Xor", "Bitwise_Or",
|
||||
@@ -276,10 +276,13 @@ namespace chaiscript
|
||||
template<typename T>
|
||||
static std::string format_location(const T &t)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << "(" << t->filename() << " " << t->start().line << ", " << t->start().column << ")";
|
||||
|
||||
return oss.str();
|
||||
if (t) {
|
||||
std::ostringstream oss;
|
||||
oss << "(" << t->filename() << " " << t->start().line << ", " << t->start().column << ")";
|
||||
return oss.str();
|
||||
} else {
|
||||
return "(internal)";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -470,13 +473,13 @@ namespace chaiscript
|
||||
oss << t_prepend << "(" << ast_node_type_to_string(this->identifier) << ") "
|
||||
<< this->text << " : " << this->location.start.line << ", " << this->location.start.column << '\n';
|
||||
|
||||
for (size_t j = 0; j < this->children.size(); ++j) {
|
||||
oss << this->children[j]->to_string(t_prepend + " ");
|
||||
for (auto & elem : this->children) {
|
||||
oss << elem->to_string(t_prepend + " ");
|
||||
}
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
Boxed_Value eval(chaiscript::detail::Dispatch_Engine &t_e) const
|
||||
Boxed_Value eval(const chaiscript::detail::Dispatch_State &t_e) const
|
||||
{
|
||||
try {
|
||||
return eval_internal(t_e);
|
||||
@@ -486,9 +489,9 @@ namespace chaiscript
|
||||
}
|
||||
}
|
||||
|
||||
static bool get_bool_condition(const Boxed_Value &t_bv) {
|
||||
static bool get_bool_condition(const Boxed_Value &t_bv, const chaiscript::detail::Dispatch_State &t_ss) {
|
||||
try {
|
||||
return boxed_cast<bool>(t_bv);
|
||||
return t_ss->boxed_cast<bool>(t_bv);
|
||||
}
|
||||
catch (const exception::bad_boxed_cast &) {
|
||||
throw exception::eval_error("Condition not boolean");
|
||||
@@ -512,7 +515,7 @@ namespace chaiscript
|
||||
{
|
||||
}
|
||||
|
||||
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &) const
|
||||
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &) const
|
||||
{
|
||||
throw std::runtime_error("Undispatched ast_node (internal error)");
|
||||
}
|
||||
@@ -554,21 +557,20 @@ namespace chaiscript
|
||||
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)
|
||||
: m_de(t_de)
|
||||
Scope_Push_Pop(const chaiscript::detail::Dispatch_State &t_ds)
|
||||
: m_ds(t_ds)
|
||||
{
|
||||
m_de.new_scope();
|
||||
m_ds.get()->new_scope(m_ds.get().stack_holder());
|
||||
}
|
||||
|
||||
~Scope_Push_Pop()
|
||||
{
|
||||
m_de.pop_scope();
|
||||
m_ds.get()->pop_scope(m_ds.get().stack_holder());
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
|
||||
chaiscript::detail::Dispatch_Engine &m_de;
|
||||
std::reference_wrapper<const chaiscript::detail::Dispatch_State> m_ds;
|
||||
};
|
||||
|
||||
/// Creates a new function call and pops it on destruction
|
||||
@@ -577,31 +579,30 @@ namespace chaiscript
|
||||
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)
|
||||
: m_de(t_de)
|
||||
Function_Push_Pop(const chaiscript::detail::Dispatch_State &t_ds)
|
||||
: m_ds(t_ds)
|
||||
{
|
||||
m_de.new_function_call();
|
||||
m_ds.get()->new_function_call(m_ds.get().stack_holder(), m_ds.get().conversion_saves());
|
||||
}
|
||||
|
||||
~Function_Push_Pop()
|
||||
{
|
||||
m_de.pop_function_call();
|
||||
m_ds.get()->pop_function_call(m_ds.get().stack_holder(), m_ds.get().conversion_saves());
|
||||
}
|
||||
|
||||
void save_params(const std::vector<Boxed_Value> &t_params)
|
||||
{
|
||||
m_de.save_function_params(t_params);
|
||||
m_ds.get()->save_function_params(t_params);
|
||||
}
|
||||
|
||||
void save_params(std::initializer_list<Boxed_Value> t_params)
|
||||
{
|
||||
m_de.save_function_params(std::move(t_params));
|
||||
m_ds.get()->save_function_params(std::move(t_params));
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
|
||||
chaiscript::detail::Dispatch_Engine &m_de;
|
||||
std::reference_wrapper<const chaiscript::detail::Dispatch_State> m_ds;
|
||||
};
|
||||
|
||||
/// Creates a new scope then pops it on destruction
|
||||
@@ -610,21 +611,20 @@ namespace chaiscript
|
||||
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)
|
||||
: m_de(t_de)
|
||||
Stack_Push_Pop(const chaiscript::detail::Dispatch_State &t_ds)
|
||||
: m_ds(t_ds)
|
||||
{
|
||||
m_de.new_stack();
|
||||
m_ds.get()->new_stack(m_ds.get().stack_holder());
|
||||
}
|
||||
|
||||
~Stack_Push_Pop()
|
||||
{
|
||||
m_de.pop_stack();
|
||||
m_ds.get()->pop_stack(m_ds.get().stack_holder());
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
|
||||
chaiscript::detail::Dispatch_Engine &m_de;
|
||||
std::reference_wrapper<const chaiscript::detail::Dispatch_State> m_ds;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@@ -1,7 +1,7 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
|
||||
// Copyright 2009-2016, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#ifndef CHAISCRIPT_ENGINE_HPP_
|
||||
@@ -36,15 +36,16 @@
|
||||
#else
|
||||
#ifdef CHAISCRIPT_WINDOWS
|
||||
#define VC_EXTRA_LEAN
|
||||
#if !defined(WIN32_LEAN_AND_MEAN)
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <Windows.h>
|
||||
#endif
|
||||
#include <windows.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#include "../dispatchkit/exception_specification.hpp"
|
||||
#include "chaiscript_parser.hpp"
|
||||
#include "chaiscript_prelude.chai"
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
@@ -176,11 +177,11 @@ namespace chaiscript
|
||||
FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
||||
FORMAT_MESSAGE_FROM_SYSTEM |
|
||||
FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
NULL,
|
||||
nullptr,
|
||||
t_err,
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
reinterpret_cast<StringType>(&lpMsgBuf),
|
||||
0, NULL ) != 0 && lpMsgBuf)
|
||||
0, nullptr ) != 0 && lpMsgBuf)
|
||||
{
|
||||
retval = lpMsgBuf;
|
||||
LocalFree(lpMsgBuf);
|
||||
@@ -285,14 +286,7 @@ namespace chaiscript
|
||||
|
||||
|
||||
|
||||
const Boxed_Value internal_eval_ast(const AST_NodePtr &t_ast)
|
||||
{
|
||||
try {
|
||||
return t_ast->eval(m_engine);
|
||||
} catch (const exception::eval_error &t_ee) {
|
||||
throw Boxed_Value(t_ee);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Evaluates the given file and looks in the 'use' paths
|
||||
const Boxed_Value internal_eval_file(const std::string &t_filename) {
|
||||
@@ -348,6 +342,7 @@ namespace chaiscript
|
||||
m_engine.add_reserved_word("class");
|
||||
m_engine.add_reserved_word("attr");
|
||||
m_engine.add_reserved_word("var");
|
||||
m_engine.add_reserved_word("global");
|
||||
m_engine.add_reserved_word("GLOBAL");
|
||||
m_engine.add_reserved_word("_");
|
||||
|
||||
@@ -356,57 +351,66 @@ namespace chaiscript
|
||||
add(t_lib);
|
||||
}
|
||||
|
||||
m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::dump_system, std::ref(m_engine)), "dump_system");
|
||||
m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::dump_object, std::ref(m_engine)), "dump_object");
|
||||
m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::is_type, std::ref(m_engine)), "is_type");
|
||||
m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::type_name, std::ref(m_engine)), "type_name");
|
||||
m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::function_exists, std::ref(m_engine)), "function_exists");
|
||||
m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::get_function_objects, std::ref(m_engine)), "get_functions");
|
||||
m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::get_scripting_objects, std::ref(m_engine)), "get_objects");
|
||||
m_engine.add(chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Dynamic_Proxy_Function>(
|
||||
m_engine.add(fun([this](){ m_engine.dump_system(); }), "dump_system");
|
||||
m_engine.add(fun([this](const Boxed_Value &t_bv){ m_engine.dump_object(t_bv); }), "dump_object");
|
||||
m_engine.add(fun([this](const Boxed_Value &t_bv, const std::string &t_type){ return m_engine.is_type(t_bv, t_type); }), "is_type");
|
||||
m_engine.add(fun([this](const Boxed_Value &t_bv){ return m_engine.type_name(t_bv); }), "type_name");
|
||||
m_engine.add(fun([this](const std::string &t_f){ return m_engine.function_exists(t_f); }), "function_exists");
|
||||
m_engine.add(fun([this](){ return m_engine.get_function_objects(); }), "get_functions");
|
||||
m_engine.add(fun([this](){ return m_engine.get_scripting_objects(); }), "get_objects");
|
||||
|
||||
m_engine.add(
|
||||
dispatch::make_dynamic_proxy_function(
|
||||
[this](const std::vector<Boxed_Value> &t_params) {
|
||||
return m_engine.call_exists(t_params);
|
||||
}), "call_exists");
|
||||
})
|
||||
, "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> &)>(
|
||||
[=](const dispatch::Proxy_Function_Base &t_fun, const std::vector<Boxed_Value> &t_params) {
|
||||
return t_fun(t_params, this->m_engine.conversions());
|
||||
//
|
||||
|
||||
m_engine.add(fun(
|
||||
[=](const dispatch::Proxy_Function_Base &t_fun, const std::vector<Boxed_Value> &t_params) -> Boxed_Value {
|
||||
Type_Conversions_State s(this->m_engine.conversions(), this->m_engine.conversions().conversion_saves());
|
||||
return t_fun(t_params, s);
|
||||
}), "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, std::ref(m_engine)), "type");
|
||||
m_engine.add(fun<chaiscript::Type_Info (const std::string &)>([this](const std::string &t_type_name){ return this->m_engine.get_type(t_type_name, true); }), "type");
|
||||
m_engine.add(fun([this](const Type_Info &t_ti){ return m_engine.get_type_name(t_ti); }), "name");
|
||||
|
||||
m_engine.add(fun<void(const Type_Info &, const Type_Info &, const std::function<Boxed_Value(const Boxed_Value &)> &)>(
|
||||
m_engine.add(fun([this](const std::string &t_type_name, bool t_throw){ return m_engine.get_type(t_type_name, t_throw); }), "type");
|
||||
m_engine.add(fun([this](const std::string &t_type_name){ return m_engine.get_type(t_type_name, true); }), "type");
|
||||
|
||||
m_engine.add(fun(
|
||||
[=](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 void (ChaiScript::*load_mod_2)(const std::string&, const std::string&);
|
||||
|
||||
m_engine.add(fun(static_cast<load_mod_1>(&ChaiScript::load_module), this), "load_module");
|
||||
m_engine.add(fun(static_cast<load_mod_2>(&ChaiScript::load_module), this), "load_module");
|
||||
m_engine.add(fun([this](const std::string &t_module, const std::string &t_file){ return load_module(t_module, t_file); }), "load_module");
|
||||
m_engine.add(fun([this](const std::string &t_module){ return load_module(t_module); }), "load_module");
|
||||
|
||||
m_engine.add(fun(&ChaiScript::use, this), "use");
|
||||
m_engine.add(fun(&ChaiScript::internal_eval_file, this), "eval_file");
|
||||
m_engine.add(fun(&ChaiScript::internal_eval, this), "eval");
|
||||
m_engine.add(fun(&ChaiScript::internal_eval_ast, this), "eval");
|
||||
m_engine.add(fun([this](const std::string &t_file){ return use(t_file); }), "use");
|
||||
m_engine.add(fun([this](const std::string &t_file){ return internal_eval_file(t_file); }), "eval_file");
|
||||
m_engine.add(fun([this](const std::string &t_str){ return internal_eval(t_str); }), "eval");
|
||||
m_engine.add(fun([this](const AST_NodePtr &t_ast){ return eval(t_ast); }), "eval");
|
||||
m_engine.add(fun(&parse), "parse");
|
||||
|
||||
m_engine.add(fun(&ChaiScript::version_major), "version_major");
|
||||
m_engine.add(fun(&ChaiScript::version_minor), "version_minor");
|
||||
m_engine.add(fun(&ChaiScript::version_patch), "version_patch");
|
||||
m_engine.add(fun(&ChaiScript::version), "version");
|
||||
m_engine.add(fun(&ChaiScript::compiler_version), "compiler_version");
|
||||
m_engine.add(fun(&ChaiScript::compiler_name), "compiler_name");
|
||||
m_engine.add(fun(&ChaiScript::compiler_id), "compiler_id");
|
||||
m_engine.add(fun(&ChaiScript::debug_build), "debug_build");
|
||||
|
||||
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");
|
||||
m_engine.add(fun([this](const Boxed_Value &t_bv, const std::string &t_name){ add_global_const(t_bv, t_name); }), "add_global_const");
|
||||
m_engine.add(fun([this](const Boxed_Value &t_bv, const std::string &t_name){ add_global(t_bv, t_name); }), "add_global");
|
||||
m_engine.add(fun([this](const Boxed_Value &t_bv, const std::string &t_name){ set_global(t_bv, t_name); }), "set_global");
|
||||
}
|
||||
|
||||
|
||||
@@ -501,10 +505,10 @@ namespace chaiscript
|
||||
|
||||
// Let's see if this is a link that we should expand
|
||||
std::vector<char> buf(2048);
|
||||
const size_t pathlen = readlink(dllpath.c_str(), &buf.front(), buf.size());
|
||||
if (pathlen > 0 && pathlen < buf.size())
|
||||
const auto pathlen = readlink(dllpath.c_str(), &buf.front(), buf.size());
|
||||
if (pathlen > 0 && static_cast<size_t>(pathlen) < buf.size())
|
||||
{
|
||||
dllpath = std::string(&buf.front(), pathlen);
|
||||
dllpath = std::string(&buf.front(), static_cast<size_t>(pathlen));
|
||||
}
|
||||
|
||||
m_module_paths.insert(m_module_paths.begin(), dllpath+"/");
|
||||
@@ -518,6 +522,28 @@ namespace chaiscript
|
||||
build_eval_system(ModulePtr());
|
||||
}
|
||||
|
||||
|
||||
const Boxed_Value eval(const AST_NodePtr &t_ast)
|
||||
{
|
||||
try {
|
||||
return t_ast->eval(m_engine);
|
||||
} catch (const exception::eval_error &t_ee) {
|
||||
throw Boxed_Value(t_ee);
|
||||
}
|
||||
}
|
||||
|
||||
static AST_NodePtr parse(const std::string &t_input)
|
||||
{
|
||||
parser::ChaiScript_Parser parser;
|
||||
if (parser.parse(t_input, "PARSE")) {
|
||||
//parser.show_match_stack();
|
||||
return parser.optimized_ast();
|
||||
} else {
|
||||
throw chaiscript::exception::eval_error("Unknown error while parsing");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int version_major()
|
||||
{
|
||||
return chaiscript::version_major;
|
||||
@@ -535,11 +561,36 @@ namespace chaiscript
|
||||
|
||||
static std::string version()
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << version_major() << "." << version_minor() << "." << version_patch();
|
||||
return ss.str();
|
||||
return std::to_string(version_major()) + '.' + std::to_string(version_minor()) + '.' + std::to_string(version_patch());
|
||||
}
|
||||
|
||||
static std::string compiler_id()
|
||||
{
|
||||
return compiler_name() + '-' + compiler_version();
|
||||
}
|
||||
|
||||
static std::string build_id()
|
||||
{
|
||||
return compiler_id() + (debug_build()?"-Debug":"-Release");
|
||||
}
|
||||
|
||||
static std::string compiler_version()
|
||||
{
|
||||
return chaiscript::compiler_version;
|
||||
}
|
||||
|
||||
static std::string compiler_name()
|
||||
{
|
||||
return chaiscript::compiler_name;
|
||||
}
|
||||
|
||||
static bool debug_build()
|
||||
{
|
||||
return chaiscript::debug_build;
|
||||
}
|
||||
|
||||
|
||||
|
||||
std::string get_type_name(const Type_Info &ti) const
|
||||
{
|
||||
return m_engine.get_type_name(ti);
|
||||
@@ -609,6 +660,12 @@ namespace chaiscript
|
||||
return *this;
|
||||
}
|
||||
|
||||
ChaiScript &set_global(const Boxed_Value &t_bv, const std::string &t_name)
|
||||
{
|
||||
m_engine.set_global(t_bv, t_name);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// \brief Represents the current state of the ChaiScript system. State and be saved and restored
|
||||
/// \warning State object does not contain the user defined type conversions of the engine. They
|
||||
/// are left out due to performance considerations involved in tracking the state
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -41,25 +41,25 @@ def new(x) {
|
||||
}
|
||||
|
||||
def clone(double x) {
|
||||
double(x).copy_var_attrs(x)
|
||||
double(x).clone_var_attrs(x)
|
||||
}
|
||||
|
||||
def clone(string x) {
|
||||
string(x).copy_var_attrs(x)
|
||||
string(x).clone_var_attrs(x)
|
||||
}
|
||||
|
||||
def clone(vector x) {
|
||||
vector(x).copy_var_attrs(x)
|
||||
vector(x).clone_var_attrs(x)
|
||||
}
|
||||
|
||||
|
||||
def clone(int x) {
|
||||
int(x).copy_var_attrs(x)
|
||||
int(x).clone_var_attrs(x)
|
||||
}
|
||||
|
||||
def clone(x) : function_exists(type_name(x)) && call_exists(eval(type_name(x)), x)
|
||||
{
|
||||
eval(type_name(x))(x).copy_var_attrs(x);
|
||||
eval(type_name(x))(x).clone_var_attrs(x);
|
||||
}
|
||||
|
||||
|
||||
@@ -127,18 +127,6 @@ def even(x)
|
||||
}
|
||||
|
||||
|
||||
# Pushes the second value onto the container first value while making a clone of the value
|
||||
def push_back(container, x) : call_exists(push_back_ref, container, x)
|
||||
{
|
||||
container.push_back_ref(clone(x))
|
||||
}
|
||||
|
||||
# Pushes the second value onto the front of the container first value while making a clone of the value
|
||||
def push_front(container, x) : call_exists(push_front_ref, container, x)
|
||||
{
|
||||
container.push_front_ref(clone(x))
|
||||
}
|
||||
|
||||
# Inserts the third value at the position of the second value into the container of the first
|
||||
# while making a clone.
|
||||
def insert_at(container, pos, x)
|
||||
@@ -157,11 +145,6 @@ def reverse(container) {
|
||||
retval;
|
||||
}
|
||||
|
||||
# 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)
|
||||
{
|
||||
clone(r);
|
||||
}
|
||||
|
||||
def range(r) : call_exists(range_internal, r)
|
||||
{
|
||||
@@ -170,6 +153,13 @@ def range(r) : call_exists(range_internal, r)
|
||||
ri;
|
||||
}
|
||||
|
||||
# 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)
|
||||
{
|
||||
clone(r);
|
||||
}
|
||||
|
||||
|
||||
# The retro attribute that contains the underlying range
|
||||
attr retro::m_range;
|
||||
|
||||
|
@@ -718,14 +718,14 @@ Object drop_while(Range c, Function f);
|
||||
Object reduce(Range c, Function f);
|
||||
|
||||
|
||||
/// \brief Takes elements from Range c that match function f, return them.
|
||||
/// \brief Takes elements from Container c that match function f, return them.
|
||||
///
|
||||
/// Example:
|
||||
/// \code
|
||||
/// eval> filter([1, 2, 3, 4], odd)
|
||||
/// [1, 3]
|
||||
/// \endcode
|
||||
Object filter(Range c, Function f);
|
||||
Object filter(Container c, Function f);
|
||||
|
||||
|
||||
/// \brief Joins the elements of the Range c into a string, delimiting each with the delim string.
|
||||
|
663
include/chaiscript/utility/json.hpp
Normal file
663
include/chaiscript/utility/json.hpp
Normal file
@@ -0,0 +1,663 @@
|
||||
// From github.com/nbsdx/SimpleJSON.
|
||||
// Released under the DWTFYW PL
|
||||
//
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef SIMPLEJSON_HPP
|
||||
#define SIMPLEJSON_HPP
|
||||
|
||||
|
||||
#include <cstdint>
|
||||
#include <cmath>
|
||||
#include <cctype>
|
||||
#include <string>
|
||||
#include <deque>
|
||||
#include <map>
|
||||
#include <type_traits>
|
||||
#include <initializer_list>
|
||||
#include <ostream>
|
||||
#include <iostream>
|
||||
#include "../chaiscript_defines.hpp"
|
||||
|
||||
namespace json {
|
||||
|
||||
using std::map;
|
||||
using std::deque;
|
||||
using std::string;
|
||||
using std::enable_if;
|
||||
using std::initializer_list;
|
||||
using std::is_same;
|
||||
using std::is_convertible;
|
||||
using std::is_integral;
|
||||
using std::is_floating_point;
|
||||
|
||||
namespace {
|
||||
string json_escape( const string &str ) {
|
||||
string output;
|
||||
for( unsigned i = 0; i < str.length(); ++i )
|
||||
switch( str[i] ) {
|
||||
case '\"': output += "\\\""; break;
|
||||
case '\\': output += "\\\\"; break;
|
||||
case '\b': output += "\\b"; break;
|
||||
case '\f': output += "\\f"; break;
|
||||
case '\n': output += "\\n"; break;
|
||||
case '\r': output += "\\r"; break;
|
||||
case '\t': output += "\\t"; break;
|
||||
default : output += str[i]; break;
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
bool isspace(const char c)
|
||||
{
|
||||
#ifdef CHAISCRIPT_MSVC
|
||||
// MSVC warns on these line in some circumstances
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 6330)
|
||||
#endif
|
||||
return ::isspace(c) != 0;
|
||||
#ifdef CHAISCRIPT_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
class JSON
|
||||
{
|
||||
union BackingData {
|
||||
BackingData( double d ) : Float( d ){}
|
||||
BackingData( long l ) : Int( l ){}
|
||||
BackingData( bool b ) : Bool( b ){}
|
||||
BackingData( string s ) : String( new string( s ) ){}
|
||||
BackingData() : Int( 0 ){}
|
||||
|
||||
deque<JSON> *List;
|
||||
map<string,JSON> *Map;
|
||||
string *String;
|
||||
double Float;
|
||||
long Int;
|
||||
bool Bool;
|
||||
} Internal;
|
||||
|
||||
public:
|
||||
enum class Class {
|
||||
Null,
|
||||
Object,
|
||||
Array,
|
||||
String,
|
||||
Floating,
|
||||
Integral,
|
||||
Boolean
|
||||
};
|
||||
|
||||
template <typename Container>
|
||||
class JSONWrapper {
|
||||
Container *object;
|
||||
|
||||
public:
|
||||
JSONWrapper( Container *val ) : object( val ) {}
|
||||
JSONWrapper( std::nullptr_t ) : object( nullptr ) {}
|
||||
|
||||
typename Container::iterator begin() { return object ? object->begin() : typename Container::iterator(); }
|
||||
typename Container::iterator end() { return object ? object->end() : typename Container::iterator(); }
|
||||
typename Container::const_iterator begin() const { return object ? object->begin() : typename Container::iterator(); }
|
||||
typename Container::const_iterator end() const { return object ? object->end() : typename Container::iterator(); }
|
||||
};
|
||||
|
||||
template <typename Container>
|
||||
class JSONConstWrapper {
|
||||
const Container *object;
|
||||
|
||||
public:
|
||||
JSONConstWrapper( const Container *val ) : object( val ) {}
|
||||
JSONConstWrapper( std::nullptr_t ) : object( nullptr ) {}
|
||||
|
||||
typename Container::const_iterator begin() const { return object ? object->begin() : typename Container::const_iterator(); }
|
||||
typename Container::const_iterator end() const { return object ? object->end() : typename Container::const_iterator(); }
|
||||
};
|
||||
|
||||
JSON() : Internal(), Type( Class::Null ){}
|
||||
|
||||
explicit JSON(Class type)
|
||||
: Internal(), Type(Class::Null)
|
||||
{
|
||||
SetType( type );
|
||||
}
|
||||
|
||||
JSON( initializer_list<JSON> list )
|
||||
: Internal(), Type(Class::Null)
|
||||
{
|
||||
SetType( Class::Object );
|
||||
for( auto i = list.begin(), e = list.end(); i != e; ++i, ++i )
|
||||
operator[]( i->ToString() ) = *std::next( i );
|
||||
}
|
||||
|
||||
JSON( JSON&& other )
|
||||
: Internal( other.Internal )
|
||||
, Type( other.Type )
|
||||
{ other.Type = Class::Null; other.Internal.Map = nullptr; }
|
||||
|
||||
JSON& operator=( JSON&& other ) {
|
||||
Internal = other.Internal;
|
||||
Type = other.Type;
|
||||
other.Internal.Map = nullptr;
|
||||
other.Type = Class::Null;
|
||||
return *this;
|
||||
}
|
||||
|
||||
JSON( const JSON &other ) {
|
||||
switch( other.Type ) {
|
||||
case Class::Object:
|
||||
Internal.Map =
|
||||
new map<string,JSON>( other.Internal.Map->begin(),
|
||||
other.Internal.Map->end() );
|
||||
break;
|
||||
case Class::Array:
|
||||
Internal.List =
|
||||
new deque<JSON>( other.Internal.List->begin(),
|
||||
other.Internal.List->end() );
|
||||
break;
|
||||
case Class::String:
|
||||
Internal.String =
|
||||
new string( *other.Internal.String );
|
||||
break;
|
||||
default:
|
||||
Internal = other.Internal;
|
||||
}
|
||||
Type = other.Type;
|
||||
}
|
||||
|
||||
JSON& operator=( const JSON &other ) {
|
||||
if (&other == this) return *this;
|
||||
|
||||
switch( other.Type ) {
|
||||
case Class::Object:
|
||||
Internal.Map =
|
||||
new map<string,JSON>( other.Internal.Map->begin(),
|
||||
other.Internal.Map->end() );
|
||||
break;
|
||||
case Class::Array:
|
||||
Internal.List =
|
||||
new deque<JSON>( other.Internal.List->begin(),
|
||||
other.Internal.List->end() );
|
||||
break;
|
||||
case Class::String:
|
||||
Internal.String =
|
||||
new string( *other.Internal.String );
|
||||
break;
|
||||
default:
|
||||
Internal = other.Internal;
|
||||
}
|
||||
Type = other.Type;
|
||||
return *this;
|
||||
}
|
||||
|
||||
~JSON() {
|
||||
switch( Type ) {
|
||||
case Class::Array:
|
||||
delete Internal.List;
|
||||
break;
|
||||
case Class::Object:
|
||||
delete Internal.Map;
|
||||
break;
|
||||
case Class::String:
|
||||
delete Internal.String;
|
||||
break;
|
||||
default:;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
JSON( T b, typename enable_if<is_same<T,bool>::value>::type* = nullptr ) : Internal( b ), Type( Class::Boolean ){}
|
||||
|
||||
template <typename T>
|
||||
JSON( T i, typename enable_if<is_integral<T>::value && !is_same<T,bool>::value>::type* = nullptr ) : Internal( long(i) ), Type( Class::Integral ){}
|
||||
|
||||
template <typename T>
|
||||
JSON( T f, typename enable_if<is_floating_point<T>::value>::type* = nullptr ) : Internal( double(f) ), Type( Class::Floating ){}
|
||||
|
||||
template <typename T>
|
||||
JSON( T s, typename enable_if<is_convertible<T,string>::value>::type* = nullptr ) : Internal( string( s ) ), Type( Class::String ){}
|
||||
|
||||
JSON( std::nullptr_t ) : Internal(), Type( Class::Null ){}
|
||||
|
||||
static JSON Make( Class type ) {
|
||||
return JSON(type);
|
||||
}
|
||||
|
||||
static JSON Load( const string & );
|
||||
|
||||
template <typename T>
|
||||
void append( T arg ) {
|
||||
SetType( Class::Array ); Internal.List->emplace_back( arg );
|
||||
}
|
||||
|
||||
template <typename T, typename... U>
|
||||
void append( T arg, U... args ) {
|
||||
append( arg ); append( args... );
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename enable_if<is_same<T,bool>::value, JSON&>::type operator=( T b ) {
|
||||
SetType( Class::Boolean ); Internal.Bool = b; return *this;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename enable_if<is_integral<T>::value && !is_same<T,bool>::value, JSON&>::type operator=( T i ) {
|
||||
SetType( Class::Integral ); Internal.Int = i; return *this;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename enable_if<is_floating_point<T>::value, JSON&>::type operator=( T f ) {
|
||||
SetType( Class::Floating ); Internal.Float = f; return *this;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename enable_if<is_convertible<T,string>::value, JSON&>::type operator=( T s ) {
|
||||
SetType( Class::String ); *Internal.String = string( s ); return *this;
|
||||
}
|
||||
|
||||
JSON& operator[]( const string &key ) {
|
||||
SetType( Class::Object ); return Internal.Map->operator[]( key );
|
||||
}
|
||||
|
||||
JSON& operator[]( const size_t index ) {
|
||||
SetType( Class::Array );
|
||||
if( index >= Internal.List->size() ) Internal.List->resize( index + 1 );
|
||||
return Internal.List->operator[]( index );
|
||||
}
|
||||
|
||||
JSON &at( const string &key ) {
|
||||
return operator[]( key );
|
||||
}
|
||||
|
||||
const JSON &at( const string &key ) const {
|
||||
return Internal.Map->at( key );
|
||||
}
|
||||
|
||||
JSON &at( unsigned index ) {
|
||||
return operator[]( index );
|
||||
}
|
||||
|
||||
const JSON &at( unsigned index ) const {
|
||||
return Internal.List->at( index );
|
||||
}
|
||||
|
||||
int length() const {
|
||||
if( Type == Class::Array )
|
||||
return static_cast<int>(Internal.List->size());
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool hasKey( const string &key ) const {
|
||||
if( Type == Class::Object )
|
||||
return Internal.Map->find( key ) != Internal.Map->end();
|
||||
return false;
|
||||
}
|
||||
|
||||
int size() const {
|
||||
if( Type == Class::Object )
|
||||
return static_cast<int>(Internal.Map->size());
|
||||
else if( Type == Class::Array )
|
||||
return static_cast<int>(Internal.List->size());
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
Class JSONType() const { return Type; }
|
||||
|
||||
/// Functions for getting primitives from the JSON object.
|
||||
bool IsNull() const { return Type == Class::Null; }
|
||||
|
||||
string ToString() const { bool b; return ToString( b ); }
|
||||
string ToString( bool &ok ) const {
|
||||
ok = (Type == Class::String);
|
||||
return ok ? *Internal.String : string("");
|
||||
}
|
||||
|
||||
double ToFloat() const { bool b; return ToFloat( b ); }
|
||||
double ToFloat( bool &ok ) const {
|
||||
ok = (Type == Class::Floating);
|
||||
return ok ? Internal.Float : 0.0;
|
||||
}
|
||||
|
||||
long ToInt() const { bool b; return ToInt( b ); }
|
||||
long ToInt( bool &ok ) const {
|
||||
ok = (Type == Class::Integral);
|
||||
return ok ? Internal.Int : 0;
|
||||
}
|
||||
|
||||
bool ToBool() const { bool b; return ToBool( b ); }
|
||||
bool ToBool( bool &ok ) const {
|
||||
ok = (Type == Class::Boolean);
|
||||
return ok ? Internal.Bool : false;
|
||||
}
|
||||
|
||||
JSONWrapper<map<string,JSON>> ObjectRange() {
|
||||
if( Type == Class::Object )
|
||||
return JSONWrapper<map<string,JSON>>( Internal.Map );
|
||||
return JSONWrapper<map<string,JSON>>( nullptr );
|
||||
}
|
||||
|
||||
JSONWrapper<deque<JSON>> ArrayRange() {
|
||||
if( Type == Class::Array )
|
||||
return JSONWrapper<deque<JSON>>( Internal.List );
|
||||
return JSONWrapper<deque<JSON>>( nullptr );
|
||||
}
|
||||
|
||||
JSONConstWrapper<map<string,JSON>> ObjectRange() const {
|
||||
if( Type == Class::Object )
|
||||
return JSONConstWrapper<map<string,JSON>>( Internal.Map );
|
||||
return JSONConstWrapper<map<string,JSON>>( nullptr );
|
||||
}
|
||||
|
||||
|
||||
JSONConstWrapper<deque<JSON>> ArrayRange() const {
|
||||
if( Type == Class::Array )
|
||||
return JSONConstWrapper<deque<JSON>>( Internal.List );
|
||||
return JSONConstWrapper<deque<JSON>>( nullptr );
|
||||
}
|
||||
|
||||
string dump( int depth = 1, string tab = " ") const {
|
||||
switch( Type ) {
|
||||
case Class::Null:
|
||||
return "null";
|
||||
case Class::Object: {
|
||||
string pad = "";
|
||||
for( int i = 0; i < depth; ++i, pad += tab );
|
||||
|
||||
string s = "{\n";
|
||||
bool skip = true;
|
||||
for( auto &p : *Internal.Map ) {
|
||||
if( !skip ) s += ",\n";
|
||||
s += ( pad + "\"" + p.first + "\" : " + p.second.dump( depth + 1, tab ) );
|
||||
skip = false;
|
||||
}
|
||||
s += ( "\n" + pad.erase( 0, 2 ) + "}" ) ;
|
||||
return s;
|
||||
}
|
||||
case Class::Array: {
|
||||
string s = "[";
|
||||
bool skip = true;
|
||||
for( auto &p : *Internal.List ) {
|
||||
if( !skip ) s += ", ";
|
||||
s += p.dump( depth + 1, tab );
|
||||
skip = false;
|
||||
}
|
||||
s += "]";
|
||||
return s;
|
||||
}
|
||||
case Class::String:
|
||||
return "\"" + json_escape( *Internal.String ) + "\"";
|
||||
case Class::Floating:
|
||||
return std::to_string( Internal.Float );
|
||||
case Class::Integral:
|
||||
return std::to_string( Internal.Int );
|
||||
case Class::Boolean:
|
||||
return Internal.Bool ? "true" : "false";
|
||||
}
|
||||
|
||||
throw std::runtime_error("Unhandled JSON type");
|
||||
}
|
||||
|
||||
friend std::ostream& operator<<( std::ostream&, const JSON & );
|
||||
|
||||
private:
|
||||
void SetType( Class type ) {
|
||||
if( type == Type )
|
||||
return;
|
||||
|
||||
switch( Type ) {
|
||||
case Class::Object: delete Internal.Map; break;
|
||||
case Class::Array: delete Internal.List; break;
|
||||
case Class::String: delete Internal.String; break;
|
||||
default:;
|
||||
}
|
||||
|
||||
switch( type ) {
|
||||
case Class::Null: Internal.Map = nullptr; break;
|
||||
case Class::Object: Internal.Map = new map<string,JSON>(); break;
|
||||
case Class::Array: Internal.List = new deque<JSON>(); break;
|
||||
case Class::String: Internal.String = new string(); break;
|
||||
case Class::Floating: Internal.Float = 0.0; break;
|
||||
case Class::Integral: Internal.Int = 0; break;
|
||||
case Class::Boolean: Internal.Bool = false; break;
|
||||
}
|
||||
|
||||
Type = type;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
Class Type;
|
||||
};
|
||||
|
||||
inline JSON Array() {
|
||||
return JSON::Make( JSON::Class::Array );
|
||||
}
|
||||
|
||||
template <typename... T>
|
||||
inline JSON Array( T... args ) {
|
||||
JSON arr = JSON::Make( JSON::Class::Array );
|
||||
arr.append( args... );
|
||||
return arr;
|
||||
}
|
||||
|
||||
inline JSON Object() {
|
||||
return JSON::Make( JSON::Class::Object );
|
||||
}
|
||||
|
||||
inline std::ostream& operator<<( std::ostream &os, const JSON &json ) {
|
||||
os << json.dump();
|
||||
return os;
|
||||
}
|
||||
|
||||
namespace {
|
||||
JSON parse_next( const string &, size_t & );
|
||||
|
||||
void consume_ws( const string &str, size_t &offset ) {
|
||||
while( isspace( str[offset] ) ) ++offset;
|
||||
}
|
||||
|
||||
JSON parse_object( const string &str, size_t &offset ) {
|
||||
JSON Object = JSON::Make( JSON::Class::Object );
|
||||
|
||||
++offset;
|
||||
consume_ws( str, offset );
|
||||
if( str[offset] == '}' ) {
|
||||
++offset; return Object;
|
||||
}
|
||||
|
||||
for (;offset<str.size();) {
|
||||
JSON Key = parse_next( str, offset );
|
||||
consume_ws( str, offset );
|
||||
if( str[offset] != ':' ) {
|
||||
throw std::runtime_error(std::string("JSON ERROR: Object: Expected colon, found '") + str[offset] + "'\n");
|
||||
}
|
||||
consume_ws( str, ++offset );
|
||||
JSON Value = parse_next( str, offset );
|
||||
Object[Key.ToString()] = Value;
|
||||
|
||||
consume_ws( str, offset );
|
||||
if( str[offset] == ',' ) {
|
||||
++offset; continue;
|
||||
}
|
||||
else if( str[offset] == '}' ) {
|
||||
++offset; break;
|
||||
}
|
||||
else {
|
||||
throw std::runtime_error(std::string("JSON ERROR: Object: Expected comma, found '") + str[offset] + "'\n");
|
||||
}
|
||||
}
|
||||
|
||||
return Object;
|
||||
}
|
||||
|
||||
JSON parse_array( const string &str, size_t &offset ) {
|
||||
JSON Array = JSON::Make( JSON::Class::Array );
|
||||
unsigned index = 0;
|
||||
|
||||
++offset;
|
||||
consume_ws( str, offset );
|
||||
if( str[offset] == ']' ) {
|
||||
++offset; return Array;
|
||||
}
|
||||
|
||||
for (;offset < str.size();) {
|
||||
Array[index++] = parse_next( str, offset );
|
||||
consume_ws( str, offset );
|
||||
|
||||
if( str[offset] == ',' ) {
|
||||
++offset; continue;
|
||||
}
|
||||
else if( str[offset] == ']' ) {
|
||||
++offset; break;
|
||||
}
|
||||
else {
|
||||
throw std::runtime_error(std::string("JSON ERROR: Array: Expected ',' or ']', found '") + str[offset] + "'\n");
|
||||
}
|
||||
}
|
||||
|
||||
return Array;
|
||||
}
|
||||
|
||||
JSON parse_string( const string &str, size_t &offset ) {
|
||||
string val;
|
||||
for( char c = str[++offset]; c != '\"' ; c = str[++offset] ) {
|
||||
if( c == '\\' ) {
|
||||
switch( str[ ++offset ] ) {
|
||||
case '\"': val += '\"'; break;
|
||||
case '\\': val += '\\'; break;
|
||||
case '/' : val += '/' ; break;
|
||||
case 'b' : val += '\b'; break;
|
||||
case 'f' : val += '\f'; break;
|
||||
case 'n' : val += '\n'; break;
|
||||
case 'r' : val += '\r'; break;
|
||||
case 't' : val += '\t'; break;
|
||||
case 'u' : {
|
||||
val += "\\u" ;
|
||||
for( unsigned i = 1; i <= 4; ++i ) {
|
||||
c = str[offset+i];
|
||||
if( (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F') )
|
||||
val += c;
|
||||
else {
|
||||
throw std::runtime_error(std::string("JSON ERROR: String: Expected hex character in unicode escape, found '") + c + "'");
|
||||
}
|
||||
}
|
||||
offset += 4;
|
||||
} break;
|
||||
default : val += '\\'; break;
|
||||
}
|
||||
}
|
||||
else
|
||||
val += c;
|
||||
}
|
||||
++offset;
|
||||
return JSON(val);
|
||||
}
|
||||
|
||||
JSON parse_number( const string &str, size_t &offset ) {
|
||||
JSON Number;
|
||||
string val, exp_str;
|
||||
char c = '\0';
|
||||
bool isDouble = false;
|
||||
long exp = 0;
|
||||
for (; offset < str.size() ;) {
|
||||
c = str[offset++];
|
||||
if( (c == '-') || (c >= '0' && c <= '9') )
|
||||
val += c;
|
||||
else if( c == '.' ) {
|
||||
val += c;
|
||||
isDouble = true;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
if( offset < str.size() && (c == 'E' || c == 'e' )) {
|
||||
c = str[ offset++ ];
|
||||
if( c == '-' ) { exp_str += '-';}
|
||||
else if( c == '+' ) { }
|
||||
else --offset;
|
||||
|
||||
for (; offset < str.size() ;) {
|
||||
c = str[ offset++ ];
|
||||
if( c >= '0' && c <= '9' )
|
||||
exp_str += c;
|
||||
else if( !isspace( c ) && c != ',' && c != ']' && c != '}' ) {
|
||||
throw std::runtime_error(std::string("JSON ERROR: Number: Expected a number for exponent, found '") + c + "'");
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
exp = std::stol( exp_str );
|
||||
}
|
||||
else if( offset < str.size() && (!isspace( c ) && c != ',' && c != ']' && c != '}' )) {
|
||||
throw std::runtime_error(std::string("JSON ERROR: Number: unexpected character '") + c + "'");
|
||||
}
|
||||
--offset;
|
||||
|
||||
if( isDouble )
|
||||
Number = std::stod( val ) * std::pow( 10, exp );
|
||||
else {
|
||||
if( !exp_str.empty() )
|
||||
Number = static_cast<double>(std::stol( val )) * std::pow( 10, exp );
|
||||
else
|
||||
Number = std::stol( val );
|
||||
}
|
||||
return Number;
|
||||
}
|
||||
|
||||
JSON parse_bool( const string &str, size_t &offset ) {
|
||||
JSON Bool;
|
||||
if( str.substr( offset, 4 ) == "true" ) {
|
||||
offset += 4;
|
||||
Bool = true;
|
||||
} else if( str.substr( offset, 5 ) == "false" ) {
|
||||
offset += 5;
|
||||
Bool = false;
|
||||
} else {
|
||||
throw std::runtime_error(std::string("JSON ERROR: Bool: Expected 'true' or 'false', found '") + str.substr( offset, 5 ) + "'");
|
||||
}
|
||||
return Bool;
|
||||
}
|
||||
|
||||
JSON parse_null( const string &str, size_t &offset ) {
|
||||
if( str.substr( offset, 4 ) != "null" ) {
|
||||
throw std::runtime_error(std::string("JSON ERROR: Null: Expected 'null', found '") + str.substr( offset, 4 ) + "'");
|
||||
}
|
||||
offset += 4;
|
||||
return JSON();
|
||||
}
|
||||
|
||||
JSON parse_next( const string &str, size_t &offset ) {
|
||||
char value;
|
||||
consume_ws( str, offset );
|
||||
value = str[offset];
|
||||
switch( value ) {
|
||||
case '[' : return parse_array( str, offset );
|
||||
case '{' : return parse_object( str, offset );
|
||||
case '\"': return parse_string( str, offset );
|
||||
case 't' :
|
||||
case 'f' : return parse_bool( str, offset );
|
||||
case 'n' : return parse_null( str, offset );
|
||||
default : if( ( value <= '9' && value >= '0' ) || value == '-' )
|
||||
return parse_number( str, offset );
|
||||
}
|
||||
throw std::runtime_error(std::string("JSON ERROR: Parse: Unexpected starting character '") + value + "'");
|
||||
}
|
||||
}
|
||||
|
||||
inline JSON JSON::Load( const string &str ) {
|
||||
size_t offset = 0;
|
||||
return parse_next( str, offset );
|
||||
}
|
||||
|
||||
} // End Namespace json
|
||||
|
||||
|
||||
#endif
|
158
include/chaiscript/utility/json_wrap.hpp
Normal file
158
include/chaiscript/utility/json_wrap.hpp
Normal file
@@ -0,0 +1,158 @@
|
||||
#ifndef CHAISCRIPT_SIMPLEJSON_WRAP_HPP
|
||||
#define CHAISCRIPT_SIMPLEJSON_WRAP_HPP
|
||||
|
||||
#include "json.hpp"
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
class json_wrap
|
||||
{
|
||||
public:
|
||||
|
||||
static ModulePtr library(ModulePtr m = std::make_shared<Module>())
|
||||
{
|
||||
|
||||
m->add(chaiscript::fun([](const std::string &t_str) { return from_json(t_str); }), "from_json");
|
||||
m->add(chaiscript::fun(&json_wrap::to_json), "to_json");
|
||||
|
||||
return m;
|
||||
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
static Boxed_Value from_json(const json::JSON &t_json)
|
||||
{
|
||||
switch( t_json.JSONType() ) {
|
||||
case json::JSON::Class::Null:
|
||||
return Boxed_Value();
|
||||
case json::JSON::Class::Object:
|
||||
{
|
||||
std::map<std::string, Boxed_Value> m;
|
||||
|
||||
for (const auto &p : t_json.ObjectRange())
|
||||
{
|
||||
m.insert(std::make_pair(p.first, from_json(p.second)));
|
||||
}
|
||||
|
||||
return Boxed_Value(m);
|
||||
}
|
||||
case json::JSON::Class::Array:
|
||||
{
|
||||
std::vector<Boxed_Value> vec;
|
||||
|
||||
for (const auto &p : t_json.ArrayRange())
|
||||
{
|
||||
vec.emplace_back(from_json(p));
|
||||
}
|
||||
|
||||
return Boxed_Value(vec);
|
||||
}
|
||||
case json::JSON::Class::String:
|
||||
return Boxed_Value(t_json.ToString());
|
||||
case json::JSON::Class::Floating:
|
||||
return Boxed_Value(t_json.ToFloat());
|
||||
case json::JSON::Class::Integral:
|
||||
return Boxed_Value(t_json.ToInt());
|
||||
case json::JSON::Class::Boolean:
|
||||
return Boxed_Value(t_json.ToBool());
|
||||
}
|
||||
|
||||
throw std::runtime_error("Unknown JSON type");
|
||||
}
|
||||
|
||||
static Boxed_Value from_json(const std::string &t_json)
|
||||
{
|
||||
return from_json( json::JSON::Load(t_json) );
|
||||
}
|
||||
|
||||
static std::string to_json(const Boxed_Value &t_bv)
|
||||
{
|
||||
return to_json_object(t_bv).dump();
|
||||
}
|
||||
|
||||
static json::JSON to_json_object(const Boxed_Value &t_bv)
|
||||
{
|
||||
try {
|
||||
const std::map<std::string, Boxed_Value> m = chaiscript::boxed_cast<const std::map<std::string, Boxed_Value> &>(t_bv);
|
||||
|
||||
json::JSON obj;
|
||||
for (const auto &o : m)
|
||||
{
|
||||
obj[o.first] = to_json_object(o.second);
|
||||
}
|
||||
return obj;
|
||||
} catch (const chaiscript::exception::bad_boxed_cast &) {
|
||||
// not a map
|
||||
}
|
||||
|
||||
try {
|
||||
const std::vector<Boxed_Value> v = chaiscript::boxed_cast<const std::vector<Boxed_Value> &>(t_bv);
|
||||
|
||||
json::JSON obj;
|
||||
for (size_t i = 0; i < v.size(); ++i)
|
||||
{
|
||||
obj[i] = to_json_object(v[i]);
|
||||
}
|
||||
return obj;
|
||||
} catch (const chaiscript::exception::bad_boxed_cast &) {
|
||||
// not a vector
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
Boxed_Number bn(t_bv);
|
||||
json::JSON obj;
|
||||
if (Boxed_Number::is_floating_point(t_bv))
|
||||
{
|
||||
obj = bn.get_as<double>();
|
||||
} else {
|
||||
obj = bn.get_as<long>();
|
||||
}
|
||||
return obj;
|
||||
} catch (const chaiscript::detail::exception::bad_any_cast &) {
|
||||
// not a number
|
||||
}
|
||||
|
||||
try {
|
||||
bool b = boxed_cast<bool>(t_bv);
|
||||
json::JSON obj;
|
||||
obj = b;
|
||||
return obj;
|
||||
} catch (const chaiscript::exception::bad_boxed_cast &) {
|
||||
// not a bool
|
||||
}
|
||||
|
||||
try {
|
||||
std::string s = boxed_cast<std::string>(t_bv);
|
||||
json::JSON obj;
|
||||
obj = s;
|
||||
return obj;
|
||||
} catch (const chaiscript::exception::bad_boxed_cast &) {
|
||||
// not a string
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
const chaiscript::dispatch::Dynamic_Object &o = boxed_cast<const dispatch::Dynamic_Object &>(t_bv);
|
||||
|
||||
json::JSON obj;
|
||||
for (const auto &attr : o.get_attrs())
|
||||
{
|
||||
obj[attr.first] = to_json_object(attr.second);
|
||||
}
|
||||
return obj;
|
||||
} catch (const chaiscript::exception::bad_boxed_cast &) {
|
||||
// not a dynamic object
|
||||
}
|
||||
|
||||
throw std::runtime_error("Unknown object type to convert to JSON");
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@@ -1,19 +1,21 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
|
||||
// Copyright 2009-2016, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#ifndef CHAISCRIPT_UTILITY_UTILITY_HPP_
|
||||
#define CHAISCRIPT_UTILITY_UTILITY_HPP_
|
||||
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "../chaiscript.hpp"
|
||||
#include "../dispatchkit/proxy_functions.hpp"
|
||||
#include "../dispatchkit/type_info.hpp"
|
||||
#include "../dispatchkit/operators.hpp"
|
||||
|
||||
|
||||
namespace chaiscript
|
||||
@@ -62,6 +64,42 @@ namespace chaiscript
|
||||
t_module.add(fun.first, fun.second);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Enum, typename ModuleType>
|
||||
typename std::enable_if<std::is_enum<Enum>::value, void>::type
|
||||
add_class(ModuleType &t_module,
|
||||
const std::string &t_class_name,
|
||||
#ifdef CHAISCRIPT_GCC_4_6
|
||||
const std::vector<std::pair<int, std::string>> &t_constants
|
||||
#else
|
||||
const std::vector<std::pair<typename std::underlying_type<Enum>::type, std::string>> &t_constants
|
||||
#endif
|
||||
)
|
||||
{
|
||||
t_module.add(chaiscript::user_type<Enum>(), t_class_name);
|
||||
|
||||
t_module.add(chaiscript::constructor<Enum ()>(), t_class_name);
|
||||
t_module.add(chaiscript::constructor<Enum (const Enum &)>(), t_class_name);
|
||||
|
||||
using namespace chaiscript::bootstrap::operators;
|
||||
t_module.add([](){
|
||||
// add some comparison and assignment operators
|
||||
return assign<Enum>(not_equal<Enum>(equal<Enum>()));
|
||||
}());
|
||||
|
||||
#ifdef CHAISCRIPT_GCC_4_6
|
||||
t_module.add(chaiscript::fun([](const Enum &e, const int &i) { return e == i; }), "==");
|
||||
t_module.add(chaiscript::fun([](const int &i, const Enum &e) { return i == e; }), "==");
|
||||
#else
|
||||
t_module.add(chaiscript::fun([](const Enum &e, const typename std::underlying_type<Enum>::type &i) { return e == i; }), "==");
|
||||
t_module.add(chaiscript::fun([](const typename std::underlying_type<Enum>::type &i, const Enum &e) { return i == e; }), "==");
|
||||
#endif
|
||||
|
||||
for (const auto &constant : t_constants)
|
||||
{
|
||||
t_module.add_global_const(chaiscript::const_var(Enum(constant.first)), constant.second);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -1,4 +1,4 @@
|
||||
Copyright 2009-2015 Jason Turner
|
||||
Copyright 2009-2016 Jason Turner
|
||||
Copyright 2009-2012 Jonathan Turner.
|
||||
|
||||
All Rights Reserved.
|
||||
|
26
performance_tests/profile_cpp_calls.chai
Normal file
26
performance_tests/profile_cpp_calls.chai
Normal file
@@ -0,0 +1,26 @@
|
||||
|
||||
var test_str = "bob was a string";
|
||||
|
||||
for( var i = 0; i < 200000; ++i)
|
||||
{
|
||||
test_str.size();
|
||||
// test_str.find("a", i);
|
||||
test_str.c_str();
|
||||
test_str.erase_at(1);
|
||||
test_str.erase_at(1);
|
||||
test_str.erase_at(1);
|
||||
test_str.erase_at(1);
|
||||
test_str.erase_at(1);
|
||||
test_str.erase_at(1);
|
||||
|
||||
size(test_str);
|
||||
// test_str.find("a", i);
|
||||
c_str(test_str);
|
||||
erase_at(test_str, 1);
|
||||
erase_at(test_str, 1);
|
||||
erase_at(test_str, 1);
|
||||
erase_at(test_str, 1);
|
||||
erase_at(test_str, 1);
|
||||
erase_at(test_str, 1);
|
||||
test_str = "bob was a string";
|
||||
}
|
20
performance_tests/profile_cpp_calls_2.cpp
Normal file
20
performance_tests/profile_cpp_calls_2.cpp
Normal file
@@ -0,0 +1,20 @@
|
||||
#include <chaiscript/chaiscript.hpp>
|
||||
#include <chaiscript/chaiscript_stdlib.hpp>
|
||||
|
||||
double f(const std::string &, double, bool) noexcept {
|
||||
return .0;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
chaiscript::ChaiScript chai(chaiscript::Std_Lib::library());
|
||||
|
||||
chai.add(chaiscript::fun(&f), "f");
|
||||
|
||||
chai.eval(R"(
|
||||
for (var i = 0; i < 100000; ++i) {
|
||||
f("str", 1.2, false);
|
||||
}
|
||||
)");
|
||||
|
||||
}
|
20
performance_tests/profile_fun_wrappers.cpp
Normal file
20
performance_tests/profile_fun_wrappers.cpp
Normal file
@@ -0,0 +1,20 @@
|
||||
#include <chaiscript/chaiscript.hpp>
|
||||
#include <chaiscript/chaiscript_stdlib.hpp>
|
||||
|
||||
double f(const std::string &, double, bool) noexcept {
|
||||
return .0;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
chaiscript::ChaiScript chai(chaiscript::Std_Lib::library());
|
||||
|
||||
chai.add(chaiscript::fun(&f), "f");
|
||||
|
||||
const auto f = chai.eval<std::function<void ()>>(R"(fun(){ f("str", 1.2, false); })");
|
||||
|
||||
for (int i = 0; i < 100000; ++i) {
|
||||
f();
|
||||
}
|
||||
|
||||
}
|
10
readme.md
10
readme.md
@@ -1,14 +1,18 @@
|
||||
Master Status: [](https://travis-ci.org/ChaiScript/ChaiScript) [](https://coveralls.io/r/ChaiScript/ChaiScript?branch=master)
|
||||
Master Status: [](https://travis-ci.org/ChaiScript/ChaiScript) [](https://ci.appveyor.com/project/lefticus/chaiscript) [](http://codecov.io/github/ChaiScript/ChaiScript?branch=master)
|
||||
|
||||
Develop Status: [](https://travis-ci.org/ChaiScript/ChaiScript) [](https://coveralls.io/r/ChaiScript/ChaiScript?branch=develop)
|
||||
Develop Status: [](https://travis-ci.org/ChaiScript/ChaiScript) [](https://ci.appveyor.com/project/lefticus/chaiscript/branch/develop) [](http://codecov.io/github/ChaiScript/ChaiScript?branch=develop)
|
||||
|
||||
<a href="https://scan.coverity.com/projects/5297">
|
||||
<img alt="Coverity Scan Build Status"
|
||||
src="https://img.shields.io/coverity/scan/5297.svg"/>
|
||||
</a>
|
||||
|
||||
ChaiScript
|
||||
|
||||
http://www.chaiscript.com
|
||||
|
||||
(c) 2009-2012 Jonathan Turner
|
||||
(c) 2009-2015 Jason Turner
|
||||
(c) 2009-2016 Jason Turner
|
||||
|
||||
Release under the BSD license, see "license.txt" for details.
|
||||
|
||||
|
@@ -1,6 +1,83 @@
|
||||
Notes:
|
||||
=======
|
||||
Current Version: 5.7.0
|
||||
|
||||
Current Version: 5.8.6
|
||||
|
||||
### Changes since 5.8.5
|
||||
* Optimize away `return` statements in lambdas also
|
||||
* Allow conversions to bool in conditionals
|
||||
* Don't allow `class` statements inside of scopes
|
||||
* Properly error when a dynamic object non-function member is called
|
||||
|
||||
### Changes since 5.8.4
|
||||
* Fix order of operations for prefix operators
|
||||
* Make sure atomics are initialized properly
|
||||
* Remove parsing of unused prefix `&` operator
|
||||
|
||||
### Changes since 5.8.3
|
||||
* Fix case with some numeric conversions mixed with numerics that do not need conversion
|
||||
|
||||
### Changes since 5.8.2
|
||||
* Add support for reference of pointer return types
|
||||
|
||||
### Changes since 5.8.1
|
||||
* Allow casting to non-const & std::shared_ptr<T>
|
||||
|
||||
|
||||
### Changes since 5.8.0
|
||||
* Fix parsing of floats to be locale independent #250
|
||||
* Various warning fixes on various platforms
|
||||
|
||||
|
||||
### Changes since 5.7.1
|
||||
* Make all parser iterator operations range checked
|
||||
* Parse in-string eval statements once, not once for each execution
|
||||
* Fix parsing of operators (ie 1<-1 now parses)
|
||||
* Fix variable scoping for functors
|
||||
* Exception reduction
|
||||
* Various object lifetime fixes
|
||||
* Add JSON support for load / save #207
|
||||
* Numeric overload resolution fixes #209
|
||||
* Fix long long #208
|
||||
* Add octal escapes in strings #211
|
||||
* Fixed sizing of binary literals #213
|
||||
* Added support for != with bool values #217
|
||||
* Various value assignment vector fixes
|
||||
* Fixed broken hex escape sequences from @ChristianKaeser
|
||||
* Multiply defined symbols fixes #232 @RaptorFactor
|
||||
* Add add_class<Enum> helper #233 @vrennert
|
||||
* Cheatsheet fixes #235 @mlamby
|
||||
* Fix parsing of strings inside of in-string eval statements
|
||||
* Allow lower-case global keyword
|
||||
* Enable thread-local on MSVC (should be significant performance boost)
|
||||
|
||||
|
||||
### Changes since 5.7.0
|
||||
* Build time reduction
|
||||
* Build size reduction
|
||||
* Performance increases
|
||||
* Fixed ~20 crash-bugs found with fuzzy testing #194
|
||||
* Let unhandled exceptions propogate to user
|
||||
* Report eval_error when break statement is not in loop
|
||||
* Fix handling of 0 length scripts closes #193
|
||||
* Don't crash on arity mismatch - Specifically affects the case where no overloads exist for a given function
|
||||
* Fix error printing for `bind` calls
|
||||
* Handle unexpected continue statement
|
||||
* Check arity during bind
|
||||
* Don't allow arith conversion on variadic function
|
||||
* Correct `bind` parameter match count
|
||||
* Add in expected Boxed_Value exception cases
|
||||
* Check access to AST, don't allow `;` in func def
|
||||
* Don't attempt arithmetic unary & call
|
||||
* Don't crash on 0 param call to `bind`
|
||||
* Catch errors during member function dispatch
|
||||
* Properly handle type of const bool &
|
||||
* Automatic deduction of lambda type signatures
|
||||
* Work with non-polymorphic parent/child conversions
|
||||
* Move to codecov for coverage reporting
|
||||
* Add `.at` method for Map objects
|
||||
* Various corrections for support of move-only objects
|
||||
|
||||
|
||||
### Changes since 5.6.0
|
||||
|
||||
|
103
samples/factory.cpp
Normal file
103
samples/factory.cpp
Normal file
@@ -0,0 +1,103 @@
|
||||
#include <chaiscript/chaiscript.hpp>
|
||||
#include <chaiscript/chaiscript_stdlib.hpp>
|
||||
|
||||
class Entity
|
||||
{
|
||||
public:
|
||||
int width;
|
||||
int height;
|
||||
int x;
|
||||
int y;
|
||||
std::string name;
|
||||
|
||||
std::function<void (Entity &)> updater;
|
||||
|
||||
Entity(const int t_width, const int t_height, const int t_x, const int t_y, std::string t_name)
|
||||
: width(t_width), height(t_height), x(t_x), y(t_y), name(std::move(t_name))
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class Factory
|
||||
{
|
||||
public:
|
||||
// we may as well pass the parameters for the entity to the factory method, this does the initialization
|
||||
// in one step.
|
||||
Entity *make_entity(const int width, const int height, const int x, const int y, const std::string &name)
|
||||
{
|
||||
auto entity = entities.insert({name, Entity{width, height, x, y, name}});
|
||||
return &(entity.first->second);
|
||||
}
|
||||
|
||||
Entity *get_entity(const std::string &name)
|
||||
{
|
||||
return &entities.at(name);
|
||||
}
|
||||
|
||||
|
||||
// loop over all entities and all their updater function (if it exists)
|
||||
void update_entities()
|
||||
{
|
||||
for (auto &entity : entities)
|
||||
{
|
||||
if (entity.second.updater) {
|
||||
entity.second.updater(entity.second);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
// we cannot store the entities in a std::vector if we want to return a pointer to them,
|
||||
// because a vector automatically resizing itself can invalidate the pointer that was returned.
|
||||
// using a map guarantees that the memory assigned to the entity will never change, plus
|
||||
// lets us easily look up an entity by name
|
||||
std::map<std::string, Entity> entities;
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
chaiscript::ChaiScript chai(chaiscript::Std_Lib::library());
|
||||
|
||||
chai.add(chaiscript::fun(&Entity::width), "width");
|
||||
chai.add(chaiscript::fun(&Entity::height), "height");
|
||||
chai.add(chaiscript::fun(&Entity::x), "x");
|
||||
chai.add(chaiscript::fun(&Entity::y), "y");
|
||||
chai.add(chaiscript::fun(&Entity::name), "name");
|
||||
chai.add(chaiscript::fun(&Entity::updater), "updater");
|
||||
chai.add(chaiscript::user_type<Entity>(), "Entity"); // this isn't strictly necessary but makes error messages nicer
|
||||
|
||||
chai.add(chaiscript::fun(&Factory::make_entity), "make_entity");
|
||||
chai.add(chaiscript::fun(&Factory::get_entity), "get_entity");
|
||||
chai.add(chaiscript::fun(&Factory::update_entities), "update_entities");
|
||||
chai.add(chaiscript::user_type<Factory>(), "Factory"); // this isn't strictly necessary but makes error messages nicer
|
||||
|
||||
|
||||
Factory f;
|
||||
chai.add(chaiscript::var(&f), "f");
|
||||
|
||||
std::string script = R""(
|
||||
f.make_entity(10,10,1,1,"entity1").updater = fun(e){ e.x += 1; e.y += 1 };
|
||||
f.make_entity(10,10,10,10,"entity2").updater = fun(e){ e.x += 2; e.y += 2 };
|
||||
f.make_entity(10,10,20,20,"entity3");
|
||||
|
||||
print(f.get_entity("entity1").x == 1)
|
||||
print(f.get_entity("entity2").x == 10)
|
||||
print(f.get_entity("entity3").x == 20)
|
||||
|
||||
f.update_entities(); // this runs the function objects we set in the previous lines
|
||||
// we should now see the updated values
|
||||
|
||||
print(f.get_entity("entity1").x == 2)
|
||||
print(f.get_entity("entity2").x == 12)
|
||||
print(f.get_entity("entity3").x == 20) // this one has no updater, so it stays the same
|
||||
)"";
|
||||
|
||||
|
||||
chai.eval(script);
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
@@ -1,7 +1,7 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
|
||||
// Copyright 2009-2016, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#include <iostream>
|
||||
@@ -89,24 +89,24 @@ std::vector<std::string> default_search_paths()
|
||||
std::vector<char> buf(2048);
|
||||
ssize_t size = -1;
|
||||
|
||||
if ((size = readlink("/proc/self/exe", &buf.front(), buf.size())) != -1)
|
||||
if ((size = readlink("/proc/self/exe", &buf.front(), buf.size())) > 0)
|
||||
{
|
||||
exepath = std::string(&buf.front(), size);
|
||||
exepath = std::string(&buf.front(), static_cast<size_t>(size));
|
||||
}
|
||||
|
||||
if (exepath.empty())
|
||||
{
|
||||
if ((size = readlink("/proc/curproc/file", &buf.front(), buf.size())) != -1)
|
||||
if ((size = readlink("/proc/curproc/file", &buf.front(), buf.size())) > 0)
|
||||
{
|
||||
exepath = std::string(&buf.front(), size);
|
||||
exepath = std::string(&buf.front(), static_cast<size_t>(size));
|
||||
}
|
||||
}
|
||||
|
||||
if (exepath.empty())
|
||||
{
|
||||
if ((size = readlink("/proc/self/path/a.out", &buf.front(), buf.size())) != -1)
|
||||
if ((size = readlink("/proc/self/path/a.out", &buf.front(), buf.size())) > 0)
|
||||
{
|
||||
exepath = std::string(&buf.front(), size);
|
||||
exepath = std::string(&buf.front(), static_cast<size_t>(size));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -316,7 +316,7 @@ int main(int argc, char *argv[])
|
||||
|
||||
////for (int i = 0; i < 1000; i++)
|
||||
////{
|
||||
//// chai.eval("puts(helloWorld(\"Bob12345\"));");
|
||||
//// chai.eval("puts(helloWorld(\"Bob12345\"));");
|
||||
////}
|
||||
//chai.eval_file("E:\\C++\\ChaiScript - 5.4.0\\samples\forx.chai");
|
||||
|
||||
|
34
samples/test_num_exceptions.cpp
Normal file
34
samples/test_num_exceptions.cpp
Normal file
@@ -0,0 +1,34 @@
|
||||
#include <chaiscript/chaiscript.hpp>
|
||||
#include <chaiscript/chaiscript_stdlib.hpp>
|
||||
#include <chaiscript/dispatchkit/bootstrap_stl.hpp>
|
||||
#include <chaiscript/dispatchkit/function_call.hpp>
|
||||
|
||||
int main( int /*argc*/ , char * /*argv*/[] )
|
||||
{
|
||||
chaiscript::ChaiScript ch( chaiscript::Std_Lib::library( ) );
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
static const char script[ ] =
|
||||
R""(
|
||||
|
||||
class Rectangle
|
||||
{
|
||||
def Rectangle() { }
|
||||
}
|
||||
|
||||
var rect = Rectangle( );
|
||||
|
||||
)"";
|
||||
|
||||
|
||||
ch.eval( script );
|
||||
}
|
||||
catch ( const std::exception &e )
|
||||
{
|
||||
printf( " >>> Exception thrown: %s \n" , e.what( ) );
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
50
src/main.cpp
50
src/main.cpp
@@ -1,7 +1,7 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
|
||||
// Copyright 2009-2016, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#include <iostream>
|
||||
@@ -66,7 +66,7 @@ std::vector<std::string> default_search_paths()
|
||||
|
||||
#ifdef CHAISCRIPT_WINDOWS // force no unicode
|
||||
CHAR path[4096];
|
||||
int size = GetModuleFileNameA(0, path, sizeof(path)-1);
|
||||
int size = GetModuleFileNameA(nullptr, path, sizeof(path)-1);
|
||||
|
||||
std::string exepath(path, size);
|
||||
|
||||
@@ -88,24 +88,24 @@ std::vector<std::string> default_search_paths()
|
||||
std::vector<char> buf(2048);
|
||||
ssize_t size = -1;
|
||||
|
||||
if ((size = readlink("/proc/self/exe", &buf.front(), buf.size())) != -1)
|
||||
if ((size = readlink("/proc/self/exe", &buf.front(), buf.size())) >= 0)
|
||||
{
|
||||
exepath = std::string(&buf.front(), size);
|
||||
exepath = std::string(&buf.front(), static_cast<size_t>(size));
|
||||
}
|
||||
|
||||
if (exepath.empty())
|
||||
{
|
||||
if ((size = readlink("/proc/curproc/file", &buf.front(), buf.size())) != -1)
|
||||
if ((size = readlink("/proc/curproc/file", &buf.front(), buf.size())) >= 0)
|
||||
{
|
||||
exepath = std::string(&buf.front(), size);
|
||||
exepath = std::string(&buf.front(), static_cast<size_t>(size));
|
||||
}
|
||||
}
|
||||
|
||||
if (exepath.empty())
|
||||
{
|
||||
if ((size = readlink("/proc/self/path/a.out", &buf.front(), buf.size())) != -1)
|
||||
if ((size = readlink("/proc/self/path/a.out", &buf.front(), buf.size())) >= 0)
|
||||
{
|
||||
exepath = std::string(&buf.front(), size);
|
||||
exepath = std::string(&buf.front(), static_cast<size_t>(size));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -297,6 +297,8 @@ int main(int argc, char *argv[])
|
||||
chai.add(chaiscript::fun(&get_eval_error), "get_eval_error");
|
||||
chai.add(chaiscript::fun(&now), "now");
|
||||
|
||||
bool eval_error_ok = false;
|
||||
bool boxed_exception_ok = false;
|
||||
|
||||
for (int i = 0; i < argc; ++i) {
|
||||
if ( i == 0 && argc > 1 ) {
|
||||
@@ -324,9 +326,15 @@ int main(int argc, char *argv[])
|
||||
arg += line + '\n' ;
|
||||
}
|
||||
} else if ( arg == "-v" || arg == "--version" ) {
|
||||
arg = "version()" ;
|
||||
arg = "print(version())" ;
|
||||
} else if ( arg == "-h" || arg == "--help" ) {
|
||||
arg = "help(-1)";
|
||||
} else if ( arg == "-e" || arg == "--evalerrorok" ) {
|
||||
eval_error_ok = true;
|
||||
continue;
|
||||
} else if ( arg == "--exception" ) {
|
||||
boxed_exception_ok = true;
|
||||
continue;
|
||||
} else if ( arg == "-i" || arg == "--interactive" ) {
|
||||
mode = eInteractive ;
|
||||
} else if ( arg.find('-') == 0 ) {
|
||||
@@ -336,28 +344,38 @@ int main(int argc, char *argv[])
|
||||
mode = eFile;
|
||||
}
|
||||
|
||||
chaiscript::Boxed_Value val ;
|
||||
try {
|
||||
switch ( mode ) {
|
||||
case eInteractive:
|
||||
interactive(chai);
|
||||
break;
|
||||
case eCommand:
|
||||
val = chai.eval(arg);
|
||||
chai.eval(arg);
|
||||
break;
|
||||
case eFile:
|
||||
val = chai.eval_file(arg);
|
||||
chai.eval_file(arg);
|
||||
}
|
||||
}
|
||||
catch (const chaiscript::exception::eval_error &ee) {
|
||||
std::cout << ee.pretty_print();
|
||||
std::cout << '\n';
|
||||
return EXIT_FAILURE;
|
||||
|
||||
if (!eval_error_ok) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
catch (std::exception &e) {
|
||||
std::cout << e.what() << '\n';
|
||||
return EXIT_FAILURE;
|
||||
catch (const chaiscript::Boxed_Value &e) {
|
||||
std::cout << "Unhandled exception thrown of type " << e.get_type_info().name() << '\n';
|
||||
|
||||
if (!boxed_exception_ok) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
// catch (std::exception &e) {
|
||||
// std::cout << e.what() << '\n';
|
||||
// return EXIT_FAILURE;
|
||||
// }
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
|
@@ -1,7 +1,7 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
|
||||
// Copyright 2009-2016, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#include <chaiscript/chaiscript.hpp>
|
||||
@@ -23,7 +23,11 @@
|
||||
|
||||
CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_stl_extra()
|
||||
{
|
||||
return chaiscript::bootstrap::standard_library::list_type<std::list<chaiscript::Boxed_Value> >("List");
|
||||
|
||||
auto module = chaiscript::bootstrap::standard_library::list_type<std::list<chaiscript::Boxed_Value> >("List");
|
||||
module->add(chaiscript::bootstrap::standard_library::vector_type<std::vector<uint16_t> >("u16vector"));
|
||||
module->add(chaiscript::vector_conversion<std::vector<uint16_t>>());
|
||||
return module;
|
||||
}
|
||||
|
||||
#ifdef __llvm__
|
||||
|
@@ -34,6 +34,11 @@ class TestBaseType
|
||||
int mdarray[2][3][5];
|
||||
std::function<int (int)> func_member;
|
||||
|
||||
void set_string_val(std::string &t_str)
|
||||
{
|
||||
t_str = "42";
|
||||
}
|
||||
|
||||
private:
|
||||
TestBaseType &operator=(const TestBaseType &) = delete;
|
||||
};
|
||||
@@ -52,6 +57,7 @@ class Type2
|
||||
return m_bt.val;
|
||||
}
|
||||
|
||||
|
||||
const char *get_str() const
|
||||
{
|
||||
return m_str.c_str();
|
||||
@@ -108,6 +114,16 @@ std::shared_ptr<TestBaseType> null_factory()
|
||||
return std::shared_ptr<TestBaseType>();
|
||||
}
|
||||
|
||||
void update_shared_ptr(std::shared_ptr<TestBaseType> &ptr)
|
||||
{
|
||||
ptr = std::make_shared<TestDerivedType>();
|
||||
}
|
||||
|
||||
void nullify_shared_ptr(std::shared_ptr<TestBaseType> &ptr)
|
||||
{
|
||||
ptr = nullptr;
|
||||
}
|
||||
|
||||
std::string hello_world()
|
||||
{
|
||||
return "Hello World";
|
||||
@@ -171,6 +187,7 @@ CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_test_mo
|
||||
m->add(chaiscript::fun(&TestBaseType::val), "val");
|
||||
m->add(chaiscript::fun(&TestBaseType::const_val), "const_val");
|
||||
m->add(chaiscript::fun(&TestBaseType::base_only_func), "base_only_func");
|
||||
m->add(chaiscript::fun(&TestBaseType::set_string_val), "set_string_val");
|
||||
|
||||
#ifndef CHAISCRIPT_MSVC_12
|
||||
// we cannot support these in MSVC_12 because of a bug in the implementation of
|
||||
@@ -202,6 +219,10 @@ CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_test_mo
|
||||
m->add(chaiscript::type_conversion<const char *, std::string>());
|
||||
m->add(chaiscript::constructor<Type2 (const TestBaseType &)>(), "Type2");
|
||||
|
||||
m->add(chaiscript::fun(&update_shared_ptr), "update_shared_ptr");
|
||||
m->add(chaiscript::fun(&nullify_shared_ptr), "nullify_shared_ptr");
|
||||
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
|
3
unittests/array_access.chai
Normal file
3
unittests/array_access.chai
Normal file
@@ -0,0 +1,3 @@
|
||||
var v = [[[15]]]
|
||||
|
||||
assert_true(v[0][0][0] == 15)
|
12
unittests/bool_comparisons.chai
Normal file
12
unittests/bool_comparisons.chai
Normal file
@@ -0,0 +1,12 @@
|
||||
|
||||
assert_true(true == true)
|
||||
assert_false(true == false)
|
||||
assert_true(true != false)
|
||||
assert_true(false != true)
|
||||
assert_true(false || true)
|
||||
assert_true(true || false)
|
||||
assert_false(true && false)
|
||||
assert_false(false && true)
|
||||
assert_true(!false)
|
||||
assert_false(!true)
|
||||
|
@@ -13,9 +13,9 @@ bool run_test_type_conversion(const Boxed_Value &bv, bool expectedpass)
|
||||
try {
|
||||
To ret = chaiscript::boxed_cast<To>(bv);
|
||||
use(ret);
|
||||
} catch (const chaiscript::exception::bad_boxed_cast &/*e*/) {
|
||||
} catch (const chaiscript::exception::bad_boxed_cast &e) {
|
||||
if (expectedpass) {
|
||||
// std::cerr << "Failure in run_test_type_conversion: " << e.what() << '\n';
|
||||
std::cerr << "Failure in run_test_type_conversion: " << e.what() << '\n';
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
@@ -54,12 +54,13 @@ bool test_type_conversion(const Boxed_Value &bv, bool expectedpass)
|
||||
}
|
||||
|
||||
template<typename Type>
|
||||
bool do_test(const Boxed_Value &bv, bool T, bool ConstT, bool TRef, bool ConstTRef, bool TPtr, bool ConstTPtr, bool TPtrConst,
|
||||
bool ConstTPtrConst, bool SharedPtrT, bool SharedConstPtrT,
|
||||
bool ConstSharedPtrT, bool ConstSharedConstPtrT, bool ConstSharedPtrTRef, bool ConstSharedPtrTConstRef,
|
||||
bool WrappedRef, bool WrappedConstRef, bool ConstWrappedRef, bool ConstWrappedConstRef,
|
||||
bool ConstWrappedRefRef, bool ConstWrappedConstRefRef, bool Number,
|
||||
bool ConstNumber, bool ConstNumberRef, bool TPtrConstRef, bool ConstTPtrConstRef)
|
||||
bool do_test(const Boxed_Value &bv,
|
||||
bool T, bool ConstT, bool TRef, bool ConstTRef, bool TPtr,
|
||||
bool ConstTPtr, bool TPtrConst, bool ConstTPtrConst, bool SharedPtrT, bool SharedConstPtrT,
|
||||
bool SharedPtrTRef, bool ConstSharedPtrT, bool ConstSharedConstPtrT, bool ConstSharedPtrTRef, bool ConstSharedPtrTConstRef,
|
||||
bool WrappedRef, bool WrappedConstRef, bool ConstWrappedRef, bool ConstWrappedConstRef, bool ConstWrappedRefRef,
|
||||
bool ConstWrappedConstRefRef, bool Number, bool ConstNumber, bool ConstNumberRef, bool TPtrConstRef,
|
||||
bool ConstTPtrConstRef)
|
||||
{
|
||||
bool passed = true;
|
||||
passed &= test_type_conversion<Type>(bv, T);
|
||||
@@ -72,8 +73,8 @@ bool do_test(const Boxed_Value &bv, bool T, bool ConstT, bool TRef, bool ConstTR
|
||||
passed &= test_type_conversion<const Type * const>(bv, ConstTPtrConst);
|
||||
passed &= test_type_conversion<std::shared_ptr<Type> >(bv, SharedPtrT);
|
||||
passed &= test_type_conversion<std::shared_ptr<const Type> >(bv, SharedConstPtrT);
|
||||
passed &= test_type_conversion<std::shared_ptr<Type> &>(bv, false);
|
||||
passed &= test_type_conversion<std::shared_ptr<const Type> &>(bv, false);
|
||||
passed &= test_type_conversion<std::shared_ptr<Type> &>(bv, SharedPtrTRef);
|
||||
//passed &= test_type_conversion<std::shared_ptr<const Type> &>(bv, false);
|
||||
passed &= test_type_conversion<const std::shared_ptr<Type> >(bv, ConstSharedPtrT);
|
||||
passed &= test_type_conversion<const std::shared_ptr<const Type> >(bv, ConstSharedConstPtrT);
|
||||
passed &= test_type_conversion<const std::shared_ptr<Type> &>(bv, ConstSharedPtrTRef);
|
||||
@@ -115,37 +116,37 @@ bool built_in_type_test(const T &initial, bool ispod)
|
||||
T i = T(initial);
|
||||
passed &= do_test<T>(var(i), true, true, true, true, true,
|
||||
true, true, true, true, true,
|
||||
true, true, true, true, true,
|
||||
true, true, true, true, true, true,
|
||||
true, true, true, true, true,
|
||||
ispod, ispod, ispod, true, true);
|
||||
|
||||
passed &= do_test<T>(const_var(i), true, true, false, true, false,
|
||||
true, false, true, false, true,
|
||||
false, true, false, true, false,
|
||||
false, false, true, false, true, false,
|
||||
true, false, true, false, true,
|
||||
ispod, ispod, ispod, false, true);
|
||||
|
||||
passed &= do_test<T>(var(&i), true, true, true, true, true,
|
||||
true, true, true, false, false,
|
||||
false, false, false, false, true,
|
||||
false, false, false, false, false, true,
|
||||
true, true, true, true, true,
|
||||
ispod, ispod, ispod, true, true);
|
||||
|
||||
passed &= do_test<T>(const_var(&i), true, true, false, true, false,
|
||||
true, false, true, false, false,
|
||||
false, false, false, false, false,
|
||||
false, false, false, false, false, false,
|
||||
true, false, true, false, true,
|
||||
ispod, ispod, ispod, false, true);
|
||||
|
||||
passed &= do_test<T>(var(std::ref(i)), true, true, true, true, true,
|
||||
true, true, true, false, false,
|
||||
false, false, false, false, true,
|
||||
false, false, false, false, false, true,
|
||||
true, true, true, true, true,
|
||||
ispod, ispod, ispod, true, true);
|
||||
|
||||
passed &= do_test<T>(var(std::cref(i)), true, true, false, true, false,
|
||||
true, false, true, false, false,
|
||||
false, false, false, false, false,
|
||||
false, false, false, false, false, false,
|
||||
true, false, true, false, true,
|
||||
ispod, ispod, ispod, false, true);
|
||||
|
||||
@@ -156,33 +157,33 @@ bool built_in_type_test(const T &initial, bool ispod)
|
||||
|
||||
passed &= do_test<T>(var(i), true, true, true, true, true,
|
||||
true, true, true, true, true,
|
||||
true, true, true, true, true,
|
||||
true, true, true, true, true, true,
|
||||
true, true, true, true, true,
|
||||
ispod, ispod, ispod, true, true);
|
||||
|
||||
// But a pointer or reference to it should be necessarily const
|
||||
passed &= do_test<T>(var(&ir), true, true, false, true, false,
|
||||
true, false, true, false, false,
|
||||
false, false, false, false, false,
|
||||
false, false, false, false, false, false,
|
||||
true, false, true, false, true,
|
||||
ispod, ispod, ispod, false, true);
|
||||
|
||||
passed &= do_test<T>(var(std::ref(ir)), true, true, false, true, false,
|
||||
true, false, true, false, false,
|
||||
false, false, false, false, false,
|
||||
false, false, false, false, false, false,
|
||||
true, false, true, false, true,
|
||||
ispod, ispod, ispod, false, true);
|
||||
|
||||
// Make sure const of const works too
|
||||
passed &= do_test<T>(const_var(&ir), true, true, false, true, false,
|
||||
true, false, true, false, false,
|
||||
false, false, false, false, false,
|
||||
false, false, false, false, false, false,
|
||||
true, false, true, false, true,
|
||||
ispod, ispod, ispod, false, true);
|
||||
|
||||
passed &= do_test<T>(const_var(std::ref(ir)), true, true, false, true, false,
|
||||
true, false, true, false, false,
|
||||
false, false, false, false, false,
|
||||
false, false, false, false, false, false,
|
||||
true, false, true, false, true,
|
||||
ispod, ispod, ispod, false, true);
|
||||
|
||||
@@ -192,14 +193,14 @@ bool built_in_type_test(const T &initial, bool ispod)
|
||||
const T*cip = &i;
|
||||
passed &= do_test<T>(var(cip), true, true, false, true, false,
|
||||
true, false, true, false, false,
|
||||
false, false, false, false, false,
|
||||
false, false, false, false, false, false,
|
||||
true, false, true, false, true,
|
||||
ispod, ispod, ispod, false, true);
|
||||
|
||||
// make sure const of const works
|
||||
passed &= do_test<T>(const_var(cip), true, true, false, true, false,
|
||||
true, false, true, false, false,
|
||||
false, false, false, false, false,
|
||||
false, false, false, false, false, false,
|
||||
true, false, true, false, true,
|
||||
ispod, ispod, ispod, false, true);
|
||||
|
||||
@@ -209,13 +210,13 @@ bool built_in_type_test(const T &initial, bool ispod)
|
||||
|
||||
passed &= do_test<T>(var(ip), true, true, true, true, true,
|
||||
true, true, true, true, true,
|
||||
true, true, true, true, true,
|
||||
true, true, true, true, true, true,
|
||||
true, true, true, true, true,
|
||||
ispod, ispod, ispod, true, true);
|
||||
|
||||
passed &= do_test<T>(const_var(ip), true, true, false, true, false,
|
||||
true, false, true, false, true,
|
||||
false, true, false, true, false,
|
||||
false, false, true, false, true, false,
|
||||
true, false, true, false, true,
|
||||
ispod, ispod, ispod, false, true);
|
||||
|
||||
@@ -224,14 +225,14 @@ bool built_in_type_test(const T &initial, bool ispod)
|
||||
|
||||
passed &= do_test<T>(var(ipc), true, true, false, true, false,
|
||||
true, false, true, false, true,
|
||||
false, true, false, true, false,
|
||||
false, false, true, false, true, false,
|
||||
true, false, true, false, true,
|
||||
ispod, ispod, ispod, false, true);
|
||||
|
||||
// const of this should be the same, making sure it compiles
|
||||
passed &= do_test<T>(const_var(ipc), true, true, false, true, false,
|
||||
true, false, true, false, true,
|
||||
false, true, false, true, false,
|
||||
false, false, true, false, true, false,
|
||||
true, false, true, false, true,
|
||||
ispod, ispod, ispod, false, true);
|
||||
|
||||
|
3223
unittests/catch.hpp
3223
unittests/catch.hpp
File diff suppressed because it is too large
Load Diff
8
unittests/class_inside_scope.chai
Normal file
8
unittests/class_inside_scope.chai
Normal file
@@ -0,0 +1,8 @@
|
||||
|
||||
|
||||
try {
|
||||
parse("{ class C { var data; def C() {} } }")
|
||||
assert_false(true)
|
||||
} catch (e) {
|
||||
assert_true(true)
|
||||
}
|
@@ -1,32 +1,31 @@
|
||||
// All of these are necessary because of catch.hpp. It's OK, they'll be
|
||||
// caught in other cpp files if chaiscript causes them
|
||||
|
||||
#include <chaiscript/utility/utility.hpp>
|
||||
|
||||
#ifdef CHAISCRIPT_MSVC
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4190 4640 28251 4702 6330)
|
||||
#pragma warning(disable : 4062 4242 4640 4702 6330 28251)
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wshadow"
|
||||
#pragma GCC diagnostic ignored "-Wold-style-cast"
|
||||
#pragma GCC diagnostic ignored "-Wunknown-pragmas"
|
||||
#pragma GCC diagnostic ignored "-Wparentheses"
|
||||
#endif
|
||||
|
||||
#ifdef __llvm__
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wreturn-type-c-linkage"
|
||||
#pragma clang diagnostic ignored "-Wold-style-cast"
|
||||
#pragma clang diagnostic ignored "-Wexit-time-destructors"
|
||||
#pragma clang diagnostic ignored "-Wfloat-equal"
|
||||
#pragma clang diagnostic ignored "-Wunreachable-code"
|
||||
#endif
|
||||
|
||||
#include <chaiscript/chaiscript.hpp>
|
||||
#include <chaiscript/utility/utility.hpp>
|
||||
#include <chaiscript/dispatchkit/bootstrap_stl.hpp>
|
||||
|
||||
|
||||
|
||||
|
||||
#define CATCH_CONFIG_MAIN
|
||||
|
||||
#include <clocale>
|
||||
|
||||
#include "catch.hpp"
|
||||
|
||||
// lambda_tests
|
||||
@@ -37,8 +36,7 @@ TEST_CASE("C++11 Lambdas Can Be Registered")
|
||||
// in an std::function or provide the signature
|
||||
chaiscript::ChaiScript chai;
|
||||
|
||||
// provide the signature
|
||||
chai.add(chaiscript::fun<std::string ()>([] { return "hello"; } ), "f1");
|
||||
chai.add(chaiscript::fun([]()->std::string { return "hello"; } ), "f1");
|
||||
|
||||
// wrap
|
||||
chai.add(chaiscript::fun(std::function<std::string ()>([] { return "world"; } )), "f2");
|
||||
@@ -397,7 +395,7 @@ class Short_Comparison_Test {
|
||||
public:
|
||||
Short_Comparison_Test() : value_(5) {}
|
||||
|
||||
short get_value() { return value_; }
|
||||
short get_value() const { return value_; }
|
||||
|
||||
short value_;
|
||||
};
|
||||
@@ -519,6 +517,65 @@ TEST_CASE("Utility_Test utility class wrapper")
|
||||
}
|
||||
|
||||
|
||||
enum Utility_Test_Numbers
|
||||
{
|
||||
ONE,
|
||||
TWO,
|
||||
THREE
|
||||
};
|
||||
|
||||
void do_something_with_enum_vector(const std::vector<Utility_Test_Numbers> &v)
|
||||
{
|
||||
CHECK(v.size() == 3);
|
||||
CHECK(v[0] == ONE);
|
||||
CHECK(v[1] == THREE);
|
||||
CHECK(v[2] == TWO);
|
||||
}
|
||||
|
||||
TEST_CASE("Utility_Test utility class wrapper for enum")
|
||||
{
|
||||
|
||||
chaiscript::ModulePtr m = chaiscript::ModulePtr(new chaiscript::Module());
|
||||
|
||||
using namespace chaiscript;
|
||||
|
||||
chaiscript::utility::add_class<Utility_Test_Numbers>(*m,
|
||||
"Utility_Test_Numbers",
|
||||
{ { ONE, "ONE" },
|
||||
{ TWO, "TWO" },
|
||||
{ THREE, "THREE" }
|
||||
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
chaiscript::ChaiScript chai;
|
||||
chai.add(m);
|
||||
|
||||
CHECK(chai.eval<Utility_Test_Numbers>("ONE ") == 0);
|
||||
CHECK(chai.eval<Utility_Test_Numbers>("TWO ") == 1);
|
||||
CHECK(chai.eval<Utility_Test_Numbers>("THREE ") == 2);
|
||||
|
||||
CHECK(chai.eval<bool>("ONE == 0"));
|
||||
|
||||
chai.add(chaiscript::fun(&do_something_with_enum_vector), "do_something_with_enum_vector");
|
||||
chai.add(chaiscript::vector_conversion<std::vector<Utility_Test_Numbers>>());
|
||||
CHECK_NOTHROW(chai.eval("var a = [ONE, TWO, THREE]"));
|
||||
CHECK_NOTHROW(chai.eval("do_something_with_enum_vector([ONE, THREE, TWO])"));
|
||||
CHECK_NOTHROW(chai.eval("[ONE]"));
|
||||
|
||||
const auto v = chai.eval<std::vector<Utility_Test_Numbers>>("a");
|
||||
CHECK(v.size() == 3);
|
||||
CHECK(v.at(1) == TWO);
|
||||
|
||||
CHECK(chai.eval<bool>("ONE == ONE"));
|
||||
CHECK(chai.eval<bool>("ONE != TWO"));
|
||||
CHECK_NOTHROW(chai.eval("var o = ONE; o = TWO"));
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
////// Object copy count test
|
||||
|
||||
class Object_Copy_Count_Test
|
||||
@@ -723,3 +780,204 @@ TEST_CASE("Object lifetime test 2")
|
||||
CHECK(_script.eval<std::string>("to_string(test2.x)") == "10");
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
///// Non-polymorphic base class conversions
|
||||
class Non_Poly_Base {};
|
||||
class Non_Poly_Derived : public Non_Poly_Base {};
|
||||
int myfunction(Non_Poly_Base *)
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
||||
TEST_CASE("Test Derived->Base with non-polymorphic classes")
|
||||
{
|
||||
chaiscript::ChaiScript chai;
|
||||
chai.add(chaiscript::base_class<Non_Poly_Base, Non_Poly_Derived>());
|
||||
Non_Poly_Derived d;
|
||||
chai.add(chaiscript::var(&d), "d");
|
||||
chai.add(chaiscript::fun(&myfunction), "myfunction");
|
||||
CHECK(chai.eval<int>("myfunction(d)") == 2);
|
||||
}
|
||||
|
||||
|
||||
struct TestCppVariableScope
|
||||
{
|
||||
void print()
|
||||
{
|
||||
std::cout << "Printed" << std::endl;
|
||||
}
|
||||
};
|
||||
|
||||
TEST_CASE("Variable Scope When Calling From C++")
|
||||
{
|
||||
chaiscript::ChaiScript chai;
|
||||
chai.add(chaiscript::user_type<TestCppVariableScope>(), "Test");
|
||||
chai.add(chaiscript::constructor<TestCppVariableScope()>(), "Test");
|
||||
chai.add(chaiscript::fun(&TestCppVariableScope::print), "print");
|
||||
chai.eval(R"(var t := Test();
|
||||
|
||||
def func()
|
||||
{
|
||||
t.print();
|
||||
}
|
||||
|
||||
)");
|
||||
|
||||
CHECK_THROWS(chai.eval("func()"));
|
||||
|
||||
chai.eval("dump_object(t)");
|
||||
|
||||
auto func = chai.eval<std::function<void()>>("func");
|
||||
CHECK_THROWS(func());
|
||||
}
|
||||
|
||||
TEST_CASE("Variable Scope When Calling From C++ 2")
|
||||
{
|
||||
chaiscript::ChaiScript chai;
|
||||
chai.eval("var obj = 2;");
|
||||
auto func = chai.eval<std::function<void()>>("fun(){ return obj; }");
|
||||
CHECK_THROWS(func());
|
||||
}
|
||||
|
||||
void ulonglong(unsigned long long i) {
|
||||
std::cout << i << '\n';
|
||||
}
|
||||
|
||||
|
||||
void longlong(long long i) {
|
||||
std::cout << i << '\n';
|
||||
}
|
||||
|
||||
TEST_CASE("Test long long dispatch")
|
||||
{
|
||||
chaiscript::ChaiScript chai;
|
||||
chai.add(chaiscript::fun(&longlong), "longlong");
|
||||
chai.add(chaiscript::fun(&ulonglong), "ulonglong");
|
||||
chai.eval("longlong(15)");
|
||||
chai.eval("ulonglong(15)");
|
||||
}
|
||||
|
||||
|
||||
struct Returned_Converted_Config
|
||||
{
|
||||
int num_iterations;
|
||||
int something_else;
|
||||
std::string a_string;
|
||||
std::function<int (const std::string &)> a_function;
|
||||
};
|
||||
|
||||
|
||||
|
||||
TEST_CASE("Return of converted type from script")
|
||||
{
|
||||
chaiscript::ChaiScript chai;
|
||||
|
||||
chai.add(chaiscript::constructor<Returned_Converted_Config ()>(), "Returned_Converted_Config");
|
||||
chai.add(chaiscript::fun(&Returned_Converted_Config::num_iterations), "num_iterations");
|
||||
chai.add(chaiscript::fun(&Returned_Converted_Config::something_else), "something_else");
|
||||
chai.add(chaiscript::fun(&Returned_Converted_Config::a_string), "a_string");
|
||||
chai.add(chaiscript::fun(&Returned_Converted_Config::a_function), "a_function");
|
||||
chai.add(chaiscript::vector_conversion<std::vector<Returned_Converted_Config>>());
|
||||
|
||||
auto c = chai.eval<std::vector<Returned_Converted_Config>>(R"(
|
||||
var c = Returned_Converted_Config();
|
||||
|
||||
c.num_iterations = 5;
|
||||
c.something_else = c.num_iterations * 2;
|
||||
c.a_string = "string";
|
||||
c.a_function = fun(s) { s.size(); }
|
||||
|
||||
print("making vector");
|
||||
var v = [];
|
||||
print("adding config item");
|
||||
v.push_back_ref(c);
|
||||
print("returning vector");
|
||||
v;
|
||||
|
||||
)");
|
||||
|
||||
|
||||
std::cout << typeid(decltype(c)).name() << std::endl;
|
||||
|
||||
std::cout << "Info: " << c.size() << " " << &c[0] << std::endl;
|
||||
|
||||
std::cout << "num_iterations " << c[0].num_iterations << '\n'
|
||||
<< "something_else " << c[0].something_else << '\n'
|
||||
<< "a_string " << c[0].a_string << '\n'
|
||||
<< "a_function " << c[0].a_function("bob") << '\n';
|
||||
|
||||
chai.add(chaiscript::user_type<Returned_Converted_Config>(), "Returned_Converted_Config");
|
||||
}
|
||||
|
||||
|
||||
int get_value_a(const std::map<std::string, int> &t_m)
|
||||
{
|
||||
return t_m.at("a");
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE("Map conversions")
|
||||
{
|
||||
chaiscript::ChaiScript chai;
|
||||
chai.add(chaiscript::map_conversion<std::map<std::string, int>>());
|
||||
chai.add(chaiscript::fun(&get_value_a), "get_value_a");
|
||||
|
||||
const auto c = chai.eval<int>(R"(
|
||||
var m = ["a": 42];
|
||||
get_value_a(m);
|
||||
)");
|
||||
|
||||
CHECK(c == 42);
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE("Parse floats with non-posix locale")
|
||||
{
|
||||
#ifdef CHAISCRIPT_MSVC
|
||||
std::setlocale(LC_ALL, "en-ZA");
|
||||
#else
|
||||
std::setlocale(LC_ALL, "en_ZA.utf8");
|
||||
#endif
|
||||
chaiscript::ChaiScript chai;
|
||||
const double parsed = chai.eval<double>("print(1.3); 1.3");
|
||||
CHECK(parsed == Approx(1.3));
|
||||
const std::string str = chai.eval<std::string>("to_string(1.3)");
|
||||
CHECK(str == "1.3");
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool FindBitmap(int &ox, int &oy, long) {
|
||||
ox = 1;
|
||||
oy = 2;
|
||||
return true;
|
||||
}
|
||||
|
||||
TEST_CASE("Mismatched numeric types only convert necessary params")
|
||||
{
|
||||
chaiscript::ChaiScript chai;
|
||||
|
||||
chai.add(chaiscript::fun(&FindBitmap), "FindBitmap");
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
chai.add(chaiscript::var(&x), "x");
|
||||
chai.add(chaiscript::var(&y), "y");
|
||||
chai.eval( "if ( FindBitmap ( x, y, 0) ) { print(\"found at \" + to_string(x) + \", \" + to_string(y))}" );
|
||||
CHECK(x == 1);
|
||||
CHECK(y == 2);
|
||||
|
||||
}
|
||||
|
||||
TEST_CASE("type_conversion to bool")
|
||||
{
|
||||
auto module = std::make_shared<chaiscript::Module>();
|
||||
struct T {
|
||||
operator bool() const { return true; }
|
||||
};
|
||||
module->add(chaiscript::type_conversion<T, bool>());
|
||||
}
|
||||
|
||||
|
||||
|
17
unittests/conversion_to_bool.chai
Normal file
17
unittests/conversion_to_bool.chai
Normal file
@@ -0,0 +1,17 @@
|
||||
|
||||
// all we care is that this executes, really
|
||||
|
||||
add_type_conversion(type("int"), type("bool"), fun(int i) { return i != 0; });
|
||||
|
||||
if (0) {
|
||||
assert_true(false);
|
||||
}
|
||||
|
||||
while (0) {
|
||||
assert_true(false);
|
||||
}
|
||||
|
||||
for (; 0; ) {
|
||||
assert_true(false);
|
||||
}
|
||||
|
14
unittests/dynamic_object_dynamic_attrs_explicit.chai
Normal file
14
unittests/dynamic_object_dynamic_attrs_explicit.chai
Normal file
@@ -0,0 +1,14 @@
|
||||
|
||||
class MyClass {
|
||||
def MyClass()
|
||||
{
|
||||
this.set_explicit(true);
|
||||
}
|
||||
};
|
||||
|
||||
var o = MyClass();
|
||||
|
||||
assert_true(o.is_explicit());
|
||||
|
||||
assert_throws("error", fun[o](){o.x = 2})
|
||||
|
BIN
unittests/fuzzy_tests-2015-07-16.tar.bz2
Normal file
BIN
unittests/fuzzy_tests-2015-07-16.tar.bz2
Normal file
Binary file not shown.
@@ -8,3 +8,17 @@ def myFun()
|
||||
}
|
||||
|
||||
myFun();
|
||||
|
||||
|
||||
def myFun2()
|
||||
{
|
||||
assert_equal(j, 7)
|
||||
}
|
||||
|
||||
set_global(7, "j")
|
||||
|
||||
myFun2();
|
||||
|
||||
set_global(5, "j")
|
||||
|
||||
myFun();
|
||||
|
18
unittests/global_lcase.chai
Normal file
18
unittests/global_lcase.chai
Normal file
@@ -0,0 +1,18 @@
|
||||
// Test global
|
||||
|
||||
global g = 3;
|
||||
assert_true(g == 3);
|
||||
|
||||
var v := g;
|
||||
assert_true(v == 3);
|
||||
|
||||
global g = 2;
|
||||
assert_true(g == 2);
|
||||
assert_true(v == 2);
|
||||
|
||||
def f() {
|
||||
assert_true(g == 2);
|
||||
}
|
||||
|
||||
f();
|
||||
|
7
unittests/hex_escapes.chai
Normal file
7
unittests/hex_escapes.chai
Normal file
@@ -0,0 +1,7 @@
|
||||
|
||||
assert_equal("\x39", "9")
|
||||
assert_equal("\x39ec", "9ec")
|
||||
assert_equal("\x39g", "9g")
|
||||
assert_equal("b\x39g", "b9g")
|
||||
assert_equal("\x39\x38g", "98g")
|
||||
|
1
unittests/instring_eval_with_string.chai
Normal file
1
unittests/instring_eval_with_string.chai
Normal file
@@ -0,0 +1 @@
|
||||
assert_equal("a string", "${"a string"}")
|
@@ -5,9 +5,10 @@
|
||||
template<typename T>
|
||||
bool test_literal(T val, const std::string &str)
|
||||
{
|
||||
std::cout << "Comparing : " << val;
|
||||
chaiscript::ChaiScript chai;
|
||||
T val2 = chai.eval<T>(str);
|
||||
std::cout << "Comparing : " << val << " " << val2 << '\n';
|
||||
std::cout << " " << val2 << '\n';
|
||||
return val == val2;
|
||||
}
|
||||
|
||||
@@ -74,6 +75,39 @@ int main()
|
||||
&& TEST_LITERAL(177777777777777777)
|
||||
&& TEST_LITERAL(1777777777777777777)
|
||||
|
||||
&& test_literal(0xF, "0b1111")
|
||||
&& test_literal(0xFF, "0b11111111")
|
||||
&& test_literal(0xFFF, "0b111111111111")
|
||||
&& test_literal(0xFFFF, "0b1111111111111111")
|
||||
&& test_literal(0xFFFFF, "0b11111111111111111111")
|
||||
&& test_literal(0xFFFFFF, "0b111111111111111111111111")
|
||||
&& test_literal(0xFFFFFFF, "0b1111111111111111111111111111")
|
||||
&& test_literal(0xFFFFFFFF, "0b11111111111111111111111111111111")
|
||||
&& test_literal(0xFFFFFFFFF, "0b111111111111111111111111111111111111")
|
||||
&& test_literal(0xFFFFFFFFFF, "0b1111111111111111111111111111111111111111")
|
||||
&& test_literal(0xFFFFFFFFFFF, "0b11111111111111111111111111111111111111111111")
|
||||
&& test_literal(0xFFFFFFFFFFFF, "0b111111111111111111111111111111111111111111111111")
|
||||
&& test_literal(0xFFFFFFFFFFFFF, "0b1111111111111111111111111111111111111111111111111111")
|
||||
&& test_literal(0xFFFFFFFFFFFFFF, "0b11111111111111111111111111111111111111111111111111111111")
|
||||
&& test_literal(0xFFFFFFFFFFFFFFF, "0b111111111111111111111111111111111111111111111111111111111111")
|
||||
&& test_literal(0xFFFFFFFFFFFFFFFF, "0b1111111111111111111111111111111111111111111111111111111111111111")
|
||||
|
||||
&& test_literal(0x7, "0b111")
|
||||
&& test_literal(0x7F, "0b1111111")
|
||||
&& test_literal(0x7FF, "0b11111111111")
|
||||
&& test_literal(0x7FFF, "0b111111111111111")
|
||||
&& test_literal(0x7FFFF, "0b1111111111111111111")
|
||||
&& test_literal(0x7FFFFF, "0b11111111111111111111111")
|
||||
&& test_literal(0x7FFFFFF, "0b111111111111111111111111111")
|
||||
&& test_literal(0x7FFFFFFF, "0b1111111111111111111111111111111")
|
||||
&& test_literal(0x7FFFFFFFF, "0b11111111111111111111111111111111111")
|
||||
&& test_literal(0x7FFFFFFFFF, "0b111111111111111111111111111111111111111")
|
||||
&& test_literal(0x7FFFFFFFFFF, "0b1111111111111111111111111111111111111111111")
|
||||
&& test_literal(0x7FFFFFFFFFFF, "0b11111111111111111111111111111111111111111111111")
|
||||
&& test_literal(0x7FFFFFFFFFFFF, "0b111111111111111111111111111111111111111111111111111")
|
||||
&& test_literal(0x7FFFFFFFFFFFFF, "0b1111111111111111111111111111111111111111111111111111111")
|
||||
&& test_literal(0x7FFFFFFFFFFFFFF, "0b11111111111111111111111111111111111111111111111111111111111")
|
||||
&& test_literal(0x7FFFFFFFFFFFFFFF, "0b111111111111111111111111111111111111111111111111111111111111111")
|
||||
)
|
||||
{
|
||||
return EXIT_SUCCESS;
|
||||
|
3
unittests/json_1.chai
Normal file
3
unittests/json_1.chai
Normal file
@@ -0,0 +1,3 @@
|
||||
|
||||
|
||||
assert_true(from_json("null").is_var_null())
|
1
unittests/json_10.chai
Normal file
1
unittests/json_10.chai
Normal file
@@ -0,0 +1 @@
|
||||
assert_equal(from_json("\"This is a\\n\\nMultiline string\""), "This is a\n\nMultiline string")
|
14
unittests/json_11.chai
Normal file
14
unittests/json_11.chai
Normal file
@@ -0,0 +1,14 @@
|
||||
assert_equal(from_json(
|
||||
"{\n" +
|
||||
" \"T1\" : \"Value With a Quote : \\\"\",\n" +
|
||||
" \"T2\" : \"Value With a Rev Solidus : \\/\",\n" +
|
||||
" \"T3\" : \"Value with a Solidus : \\\\\",\n" +
|
||||
" \"T4\" : \"Value with a Backspace : \\b\",\n" +
|
||||
" \"T5\" : \"Value with a Formfeed : \\f\",\n" +
|
||||
" \"T6\" : \"Value with a Newline : \\n\",\n" +
|
||||
" \"T7\" : \"Value with a Carriage Return : \\r\",\n" +
|
||||
" \"T8\" : \"Value with a Horizontal Tab : \\t\"\n" +
|
||||
"}"), [ "T1" : "Value With a Quote : \"", "T2" : "Value With a Rev Solidus : /", "T3" : "Value with a Solidus : \\", "T4" : "Value with a Backspace : \b", "T5" : "Value with a Formfeed : \f", "T6" : "Value with a Newline : \n", "T7" : "Value with a Carriage Return : \r", "T8" : "Value with a Horizontal Tab : \t" ]);
|
||||
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user