Compare commits

..

204 Commits

Author SHA1 Message Date
Jason Turner
7ba7b81a5c Implement option explicit for dynamic objects.
Closes #218
2015-10-16 21:41:54 -06:00
Jason Turner
882cbf2dfb Add option explicit code, but don't throw yet
Work towards #218
2015-10-16 18:47:26 -06:00
Jason Turner
38b98c55cc Add test for dynamic object option explicit 2015-10-16 18:37:02 -06:00
Jason Turner
3a675bf379 Add config option for compiling with gprof output 2015-10-16 18:21:49 -06:00
Jason Turner
985b62705f Add support for != bools
closes #217
2015-10-15 22:06:06 -06:00
Jason Turner
5aecb7f17b Add boolean comparison tests #217 2015-10-15 21:59:46 -06:00
Jason Turner
ad69bf7d38 Get vector push_back_ref working as expected 2015-10-15 21:42:25 -06:00
Jason Turner
84554ed0a5 Add another vector assignment test 2015-10-15 21:32:16 -06:00
Jason Turner
36765df3c0 Fix vector element assignment issues 2015-10-15 21:20:12 -06:00
Jason Turner
b11ebf9e8f Add failing test for vector assignment operations 2015-10-15 21:13:17 -06:00
Jason Turner
84e2d449b9 Support default case in the non-last position 2015-10-15 15:02:49 -06:00
Jason Turner
64dd349e32 Merge pull request #213 from ChaiScript/fix_binary_literal_sizing
Fix binary literal sizing
2015-10-04 20:38:37 -06:00
Jason Turner
1add4c4b0f Fix issues with integer parsing on MSVC
See #212
2015-10-04 14:32:23 -06:00
Jason Turner
14b3870efb Fix integer overflow and bad numeric parses 2015-10-04 08:53:22 -06:00
Jason Turner
d2cf12f948 Add tests for binary literals 2015-10-03 21:01:52 -06:00
Jason Turner
e221ceaa4c Greatly simplify integer sizing code 2015-10-03 17:11:03 -06:00
Jason Turner
beedf13d01 Make binary literals sized like other integer types 2015-10-03 16:38:41 -06:00
Jason Turner
9d18360333 Older compiler backport issues 2015-10-02 12:46:50 -06:00
Jason Turner
18e5ee0ba2 Wrap up generic string escape support
Closes #211
2015-10-02 12:16:44 -06:00
Jason Turner
41e9027d9a Octal escape codes supported #211 2015-10-02 11:45:28 -06:00
Jason Turner
8d9dc2b0a3 Reduce redundant escape code parsing #211 2015-10-02 10:35:37 -06:00
Jason Turner
6a4647af43 Add last test for json support
Closes #207
2015-10-02 08:12:50 -06:00
Jason Turner
5a651e2b8a Fix numeric overload resolution
Closes #209
2015-10-01 09:56:53 -06:00
Jason Turner
d9fa5605ac Add operator overload tests 2015-10-01 09:39:03 -06:00
Jason Turner
3a8cb581cc Merge branch 'add_json_support' into develop 2015-09-30 14:39:21 -06:00
Jason Turner
b434d26a5d Add json tests 2015-09-30 14:24:56 -06:00
Jason Turner
ba30d4f483 Add support for == for Map 2015-09-30 08:57:36 -06:00
Jason Turner
b4ffcd594d Fix long long type usage
Closes #208
2015-09-30 06:49:03 -06:00
Jason Turner
ca35128503 Add failing test for long long conversions 2015-09-30 06:32:34 -06:00
Jason Turner
681f18ee62 backport JSON for G++4.6 2015-09-21 12:27:33 -06:00
Jason Turner
e62a38b39f JSON output working 2015-09-21 09:27:23 -06:00
Jason Turner
85ac1052dd Initial support for export to JSON 2015-09-20 16:19:11 -06:00
Jason Turner
8024edeadf Fix some JSON parsing bug with short strings 2015-09-20 15:46:05 -06:00
Jason Turner
f9f1d5807a Basic support for parsing of JSON objects 2015-09-20 15:35:53 -06:00
Jason Turner
14227475b2 Merge remote-tracking branch 'origin/cpp_fun_call_performance' into develop 2015-09-18 13:41:44 -06:00
Jason Turner
e1a80fb5ce A couple of MSVC fixes 2015-09-16 10:28:05 -06:00
Jason Turner
aabe53c934 Make var work with move-only types 2015-09-12 22:21:05 -06:00
Jason Turner
f3dbb7ed87 Control how fast global vectors grow 2015-08-31 11:09:03 -06:00
Jason Turner
52e11bf001 Fun location caching phase2
This shows ~25% performance over develop
2015-08-31 11:00:56 -06:00
Jason Turner
f06e5cdcd6 Cache function lookups 2015-08-31 09:44:47 -06:00
Jason Turner
15eb78bd8f Move to indexed function storage 2015-08-31 08:41:47 -06:00
Jason Turner
9f362608b7 Eliminate extra unneeded scope 2015-08-28 21:19:00 -06:00
Jason Turner
e21c8f87b4 Add profile test for cpp call perf 2015-08-28 10:33:26 -06:00
Jason Turner
0a143d1cd3 Make push_* consistant with inplace vector 2015-08-27 15:30:02 -06:00
Jason Turner
08935beaf3 Add tests for pushing move only values 2015-08-27 15:23:36 -06:00
Jason Turner
c9625b09b0 Fix magic 'this' values 2015-08-26 18:41:46 -06:00
Jason Turner
800c7fb37b Fix functor scope - break magic 'this' 2015-08-26 13:18:42 -06:00
Jason Turner
179eaefafe Add failing test for functor scope 2015-08-25 17:10:45 -06:00
Jason Turner
28f5a74e98 Merge branch 'develop' of github.com:ChaiScript/ChaiScript into develop 2015-08-15 19:28:45 -06:00
Jason Turner
781d62d3a5 Make result of dynamic constructor marked as return value 2015-08-15 07:29:07 -06:00
Jason Turner
8ed2158709 Merge pull request #203 from msbroadf/develop
Update chaiscript_engine.hpp
2015-08-13 14:12:38 -06:00
Jason Turner
8f98e16e5e Reset return value flag on reference assignment 2015-08-13 13:45:31 -06:00
msbroadf
3a595ef912 Update chaiscript_engine.hpp 2015-08-13 13:45:33 +10:00
Jason Turner
5aa0bfcea4 Add some convenience functions for parsing 2015-08-11 19:20:18 -06:00
Jason Turner
04e2256c92 Fix error caused by last fix 2015-08-02 18:21:48 -06:00
Jason Turner
38ba00e55c Get MSVC2015 quieted down on warnings
re @arBmind
2015-08-02 16:52:43 -06:00
Jason Turner
8931346230 Eradicate internal exceptions during object clone 2015-08-01 13:47:25 -06:00
Jason Turner
8bdd2deb19 Add exceptions test to cmakelist 2015-08-01 12:47:43 -06:00
Jason Turner
535055eff8 Add test to see how many exceptions are during simple use 2015-08-01 12:44:22 -06:00
Jason Turner
913d2fd20f Add test for variable scope in functor calls
For bug #191
2015-08-01 11:03:55 -06:00
Jason Turner
0c4951d742 Fix parsing of operators
* Only parse valid operators
 * Don't swallow a symbol if it would produce an invalid operator

Closes #198
2015-08-01 10:05:38 -06:00
Jason Turner
9d17b18f26 add failing tests for #198
1<-1 fails to parse
2015-08-01 10:04:42 -06:00
Jason Turner
31b3195c17 Don't allow conversion to std::function on arity mismatch 2015-07-30 20:23:34 -06:00
Jason Turner
0d4e4090a0 Massive reorg of file position tracking
- Should make iterator errors almost impossible in the future
 - Fixes tracking of current line number
2015-07-30 16:53:27 -06:00
Jason Turner
b946af42cc Update fuzzy_tests to take into acount parsing fixes 2015-07-24 12:09:20 -06:00
Jason Turner
22339d10db Make order of params eval well defined 2015-07-24 12:07:46 -06:00
Jason Turner
b3d2350f33 Add test for order of operations 2015-07-24 11:49:23 -06:00
Jason Turner
3cae2aed1d Remove unused Inplace Eval ast node 2015-07-23 15:34:45 -06:00
Jason Turner
c6f262c675 Parse in-string eval at regular parse time
- don't delay and overcomplicate with an eval
2015-07-23 15:21:39 -06:00
Jason Turner
8239206ec5 Update fuzzy_tests now with more parser fixes in 2015-07-22 15:42:31 -06:00
Jason Turner
a2ff672b34 Memory error fixes
* prevent recognizing . as a number
 * do all checked iterator operations for incrementing through input
   stream
 * Verify that all is as expected when building up a dot notation call
2015-07-22 11:13:10 -06:00
Jason Turner
9a0a12d230 Bump version number to 5.7.2 2015-07-20 19:50:13 -06:00
Jason Turner
63ab117e7d Add release notes for 5.7.1 2015-07-17 14:58:40 -06:00
Jason Turner
93e7eb3fe5 Merge pull request #195 from ChaiScript/multithreaded_performance
Save stack & and prevent lookups
2015-07-16 19:06:19 -06:00
Jason Turner
419c2d72a8 Merge branch 'develop' of github.com:ChaiScript/ChaiScript into multithreaded_performance
Conflicts:
	include/chaiscript/language/chaiscript_eval.hpp
2015-07-16 18:12:09 -06:00
Jason Turner
e1c382211a Merge pull request #194 from ChaiScript/crash_fixes
Add crashes and fixes found during fuzzy testing
2015-07-16 17:41:22 -06:00
Jason Turner
6a7a934e3e Merge branch 'develop' of github.com:ChaiScript/ChaiScript into multithreaded_performance
Conflicts:
	include/chaiscript/language/chaiscript_eval.hpp
2015-07-16 13:16:04 -06:00
Jason Turner
1f72afc8f5 Add crashes and fixes found during fuzzy testing
* 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 &
2015-07-16 12:51:50 -06:00
Jason Turner
2fbc377119 More strongly typed handling of push_back wrapper
Closes #192
2015-07-11 18:36:07 -06:00
Jason Turner
563999f3b8 Add note about handling of thread contexts 2015-07-11 18:34:09 -06:00
Jason Turner
1ea608babe Better detect arithmetic types #192 2015-07-11 18:32:47 -06:00
Jason Turner
51355343f1 Add intro docs to user defined type conversions 2015-07-11 16:37:54 -06:00
Jason Turner
fe33a6aacb Add failing test for issue #192 2015-07-11 14:51:29 -06:00
Jason Turner
e117f50db0 Merge branch 'develop' of github.com:ChaiScript/ChaiScript into develop 2015-07-04 08:44:28 -06:00
Jason Turner
37120f486f Handle user defined conversions of return types from functor 2015-07-04 08:43:52 -06:00
Jason Turner
484ff7a98b Add utility for converting std::vector types 2015-07-03 14:39:21 -06:00
Jason Turner
496f5aff7a Add test for passing non-const ref param 2015-07-03 14:16:24 -06:00
Jason Turner
b270a198dc Don't clone return values into vector/map 2015-07-02 22:10:09 -06:00
Jason Turner
9e93d61236 Allow user to disable nothread warning 2015-07-02 21:18:36 -06:00
Jason Turner
72aedca39c Fix wrapping of functions with move only params 2015-06-29 20:43:12 -06:00
Jason Turner
748c18f465 Save stack & and prevent lookups 2015-06-28 15:17:58 -06:00
Jason Turner
b9875e2844 Miscellaneous performance tweaks 2015-06-28 13:20:20 -06:00
Jason Turner
902f48cd4c Revert "Use placement new to avoid unique_ptr allocations"
This reverts commit 83281bff52.
2015-06-24 11:25:56 -06:00
Jason Turner
1526ac96c1 Move to clang 3.6 address sanitizer 2015-06-23 16:49:58 -06:00
Jason Turner
e339055e0b Address some warnings for clang/gcc 2015-06-23 16:07:57 -06:00
Jason Turner
4890b47460 Reduce unary operator overhead 2015-06-23 14:25:34 -06:00
Jason Turner
b53432cf28 Remove remaining uses of std::function 2015-06-23 13:02:43 -06:00
Jason Turner
a112d97141 Simplify a couple of random things 2015-06-23 11:48:01 -06:00
Jason Turner
83281bff52 Use placement new to avoid unique_ptr allocations 2015-06-23 11:11:56 -06:00
Jason Turner
05bec3b4a8 Avoid attempting convert_down when not possible
@arBmind this should be significant for you
2015-06-21 21:09:26 -06:00
Jason Turner
cd2fb1ec66 Normalize integer types in the loc saving 2015-06-20 11:45:34 -06:00
Jason Turner
ec33cf2709 Make local location saving atomic 2015-06-20 10:52:05 -06:00
Jason Turner
c7689f18ec Save local variable location after first pass 2015-06-20 10:28:27 -06:00
Jason Turner
3eb7700912 Add missing <iterator> 2015-06-20 07:45:00 -06:00
Jason Turner
c4633436ba Avoid placeholder lookup cost 2015-06-20 07:13:54 -06:00
Jason Turner
2870874d91 Fix clang build errors 2015-06-20 06:53:23 -06:00
Jason Turner
a147278a7e Fix debug builds 2015-06-19 20:59:40 -06:00
Jason Turner
a2577b983c Don't constantly re-create the function objects 2015-06-19 20:31:39 -06:00
Jason Turner
646563eb3f A couple of cleanups and fixes 2015-06-19 20:10:45 -06:00
Jason Turner
f9860216c9 Move to std::vector for local stack objects 2015-06-19 16:49:16 -06:00
Jason Turner
b7eb469ac1 Move to some standard algorithms 2015-06-19 14:57:54 -06:00
Jason Turner
bcf573cf26 Don't loop over already filtered functions 2015-06-19 14:23:08 -06:00
Jason Turner
1bf4170d8f Simplify dispatch 2015-06-19 11:47:16 -06:00
Jason Turner
6d632f6aa4 Normalize methods for numeric->string conversions 2015-06-19 06:18:49 -06:00
Jason Turner
835b5a90af Reduce to_string overloads down to what is necessary 2015-06-18 21:47:05 -06:00
Jason Turner
9e743e3147 Set up links to codecov.io for coverage status 2015-06-18 15:45:03 -06:00
Jason Turner
7adbc11869 Merge pull request #188 from ChaiScript/wchar_t_2
Add support for char16, char32 and wchar
2015-06-18 14:07:13 -06:00
Jason Turner
2442e9ae20 Register all character types 2015-06-18 13:01:54 -06:00
Jason Turner
0dcac05f2f Add numeric support for wide characters 2015-06-18 11:57:58 -06:00
Jason Turner
60a497b0a6 Move to codecov 2015-06-16 17:09:07 -06:00
Jason Turner
11b372f526 Merge branch 'develop' of github.com:ChaiScript/ChaiScript into develop 2015-06-16 17:03:42 -06:00
Jason Turner
3d36ea6199 Add back CONSTEXPR for Type_Info 2015-06-16 17:01:01 -06:00
Jason Turner
cebeebdb7a Minor cleanups and versioning info added 2015-06-13 16:56:22 -06:00
Jason Turner
e5ccec0e89 Merge pull request #185 from kamilzubair/patch-1
Add two new examples. Thank you @kamilzubair
2015-06-13 07:47:41 -06:00
kamilzubair
62ca26c36c Add two new examples
- Add example how to expose base member from derived type
- Add example how to use STL
2015-06-11 09:11:43 +07:00
Jason Turner
68fa049d6c Fix g++4.6 build 2015-06-10 19:26:21 -06:00
Jason Turner
88ab00679f Fix spelling of Windows.h for cross compiling
Closes #176
2015-06-10 18:49:54 -06:00
Jason Turner
86482b0103 Correct docs for 'filter'
Closes #183
2015-06-10 18:44:30 -06:00
Jason Turner
f9e0193353 Add map .at method from c++11
closes #184
2015-06-10 18:41:50 -06:00
Jason Turner
ba492308f4 Move from multimap to sorted vector in dispatch 2015-06-08 15:19:32 -06:00
Jason Turner
d4e22c2c2c Merge remote-tracking branch 'origin/remove_std_function' into develop
Conflicts:
	include/chaiscript/dispatchkit/boxed_number.hpp
2015-06-08 14:34:02 -06:00
Jason Turner
b95526951f Address warnings on VS
We have to ignore many of these warnings due to the nature of Boxed_Number supporting any operation.
2015-06-08 13:18:52 -06:00
Jason Turner
e4be97eb79 Revert "Remove redundant Boxed_Number type operations"
This reverts commit 59eecab0e8.
2015-06-04 11:04:21 -06:00
Jason Turner
59eecab0e8 Remove redundant Boxed_Number type operations 2015-06-04 08:28:38 -06:00
Jason Turner
be159759ea Further boxed_number simplification 2015-06-03 21:24:09 -06:00
Jason Turner
1e41e73af2 Simplify boxed_number templates 2015-06-03 19:17:58 -06:00
Jason Turner
78819fd3a8 fixed boxed_number to_string impl 2015-06-03 18:39:49 -06:00
Jason Turner
c6c2bcc023 More template reduction in Boxed_Number 2015-06-03 08:59:01 -06:00
Jason Turner
e759a0c544 Reduce template instantiations 2015-06-03 07:00:28 -06:00
Jason Turner
b163065b3c Begin simplifying boxed_number implementation 2015-06-03 06:25:41 -06:00
Jason Turner
ecafb4aad0 Add missing cstring 2015-06-02 18:20:13 -06:00
Jason Turner
38a83e3e56 Fix MSVC2013 builds 2015-06-02 17:35:31 -06:00
Jason Turner
bacf546dff Merge branch 'develop' into remove_std_function
Conflicts:
	include/chaiscript/dispatchkit/proxy_functions_detail.hpp
2015-06-02 16:16:22 -06:00
Jason Turner
85a6d85c1f Fix warnings
- use `(void)` to avoid "unused parameter" warnings
 - Move to clang-3.6 for thread sanitizer - found bug in 3.5's reporting
2015-06-02 13:53:07 -06:00
Jason Turner
7522a19af5 g++4.6 correction 2015-06-01 16:08:04 -06:00
Jason Turner
26a0034176 Fixes for g++4.6 2015-06-01 16:07:10 -06:00
Jason Turner
cb5fbff1e6 Merge branch 'develop' into remove_std_function 2015-06-01 15:57:45 -06:00
Jason Turner
ff378abf84 Merge branch 'coverity_scan' into develop 2015-06-01 15:57:13 -06:00
Jason Turner
520f9bc0d2 Work around bug in g++4.6
I'm going to have to start dropping support for older compilers soon.

The 4.6 line is 4 years old now, and 4.7 has these issues fixed
2015-06-01 15:49:50 -06:00
Jason Turner
cf3db70d5d Merge branch 'develop' into remove_std_function
Conflicts:
	include/chaiscript/dispatchkit/proxy_functions_detail.hpp
2015-06-01 14:53:09 -06:00
Jason Turner
7026229273 Apply Index expansion technique to simplify code
Thanks @sean-parent I saw the technique in your future implementation
2015-06-01 09:43:29 -06:00
Jason Turner
da8fa77558 Update readme.md 2015-05-30 18:48:55 -06:00
Jason Turner
9fe8150861 Wrap up the coveralls / codecov choices 2015-05-30 18:48:27 -06:00
Jason Turner
d56e32e2c4 Tweak coveralls settings 2015-05-30 18:35:46 -06:00
Jason Turner
7f871374fa Codecov and coveralls enabled 2015-05-30 18:07:06 -06:00
Jason Turner
2848e16ea1 Another attempt at getting codecov working 2015-05-30 17:59:36 -06:00
Jason Turner
916708ce29 Disable coveralls, use codecov 2015-05-30 17:22:00 -06:00
Jason Turner
cff635fb65 Enable 'codecov' 2015-05-30 17:02:06 -06:00
Jason Turner
f6600c90e4 Correct missing 'sudo' for travis setup 2015-05-30 16:07:12 -06:00
Jason Turner
3701477f7f More cleanups to travis configuration 2015-05-30 16:03:23 -06:00
Jason Turner
d13d080dee Remove constexpr from type_info 2015-05-30 15:50:21 -06:00
Jason Turner
61d5e2ad85 Revert "Work around coverity crash"
This reverts commit bb0d100513.

Conflicts:
	include/chaiscript/dispatchkit/dispatchkit.hpp
	include/chaiscript/dispatchkit/type_info.hpp
2015-05-30 15:47:22 -06:00
Jason Turner
023a3edf40 Fix static usage of Type_Info objects 2015-05-30 15:36:25 -06:00
Jason Turner
4b577f1f2a Undefined types are never equal 2015-05-30 15:15:08 -06:00
Jason Turner
ac280a6971 Fix name() lookups 2015-05-30 14:14:48 -06:00
Jason Turner
d2f855e3f9 Cleanup g++-5 support for travis 2015-05-30 14:07:29 -06:00
Jason Turner
114e3939f6 Fix shell if command in travis 2015-05-30 13:55:34 -06:00
Jason Turner
ee672f5132 Further travis / coverity cleanups 2015-05-30 13:43:49 -06:00
Jason Turner
aa60cffe85 Add g++5.1 cleanup coverity use 2015-05-30 13:34:34 -06:00
Jason Turner
bb0d100513 Work around coverity crash
I'm not 100% convinced on these changes, but they might be for the
better.
2015-05-30 07:33:34 -06:00
Jason Turner
70326a5dff Try to distill travis / coverity settings 2015-05-30 06:32:14 -06:00
Jason Turner
cfc67f619a Travis 2015-05-29 23:08:27 -06:00
Jason Turner
1a02903b99 Another attempt with coverity support, add debugging 2015-05-29 22:47:53 -06:00
Jason Turner
f274d6beb3 Another attempt at coverity 2015-05-29 22:31:27 -06:00
Jason Turner
a04fe9d5a5 Fix env variables layout? 2015-05-29 22:19:59 -06:00
Jason Turner
f54bd484e6 Attempt to fix build matrix and coverity 2015-05-29 20:31:07 -06:00
Jason Turner
8ed4e6fad8 Fix coverity settings? 2015-05-29 20:17:13 -06:00
Jason Turner
c9312c0b7a Enable coverity scan? hopefully 2015-05-29 19:59:25 -06:00
Jason Turner
bb2938307c Move prelude into stdlib so it's not included everywhere 2015-05-23 16:16:39 -06:00
Jason Turner
919c3f2b4a Finish removing std::function and std::bind internally 2015-05-23 13:10:29 -06:00
Jason Turner
e0234d942e Various cleanups and fixes for older compilers 2015-05-22 19:40:56 -06:00
Jason Turner
df724b5c33 Completely remove Proxy_Function_Impl 2015-05-22 12:13:49 -06:00
Jason Turner
0b812942d4 Finish removing std::function<> 2015-05-22 11:35:58 -06:00
Jason Turner
48933bc32c Use std::ref to make free functions callable 2015-05-22 10:28:28 -06:00
Jason Turner
630c618ae7 Remove automagic wrapping to std::function<> 2015-05-22 09:39:21 -06:00
Jason Turner
03143a9f83 Phase one of getting rid of std::function usage 2015-05-22 09:30:42 -06:00
Jason Turner
33a929ef93 one more attempt to ignore catch.hpp from coverage 2015-05-20 20:06:06 -06:00
Jason Turner
e608d14a4f Attempt again to clean up coverage reporting 2015-05-20 18:43:28 -06:00
Jason Turner
e43b1b8d0d Make sure we are not also doing coverage testing on catch.hpp 2015-05-20 16:46:07 -06:00
Jason Turner
c32af523c3 Remove -n from coveralls call 2015-05-20 16:02:29 -06:00
Jason Turner
37b73f0e3c Merge branch 'develop' of github.com:ChaiScript/ChaiScript into develop 2015-05-20 15:04:22 -06:00
Jason Turner
13381ffa43 Add test, tweak coverage reporting 2015-05-20 15:04:04 -06:00
Jason Turner
2129c5318b Merge pull request #179 from ChaiScript/lambda_type_resolution
Lambda type resolution
2015-05-20 12:30:36 -06:00
Jason Turner
515ee711ce Remove unnecessary code 2015-05-20 12:00:41 -06:00
Jason Turner
bc8a4c42fa Get non-polymorphic Derived->Base conversions working 2015-05-20 11:08:07 -06:00
Jason Turner
051f483d20 Add failing non-polymorphic Derived->Base test 2015-05-20 09:48:46 -06:00
Jason Turner
da39b8403b Remove more usage of new 2015-05-19 14:15:21 -06:00
Jason Turner
5fa44d5eef Automatically deduce types of lambda for fun() 2015-05-19 13:47:34 -06:00
Jason Turner
dec88db26c Minor efficiency improvement by pre sizing match stack 2015-05-19 10:55:38 -06:00
Jason Turner
9da9012701 Fix version number mismatch 2015-05-13 06:20:25 -06:00
Jason Turner
f35c2fdb03 Update readme.md 2015-05-08 14:12:51 -06:00
Jason Turner
bb74d06b18 Merge pull request #177 from totalgee/patch-1
Fixing minor typos in cheatsheet
2015-05-08 08:04:32 -06:00
Glen Fraser
c21c21dfda Fixed minor typos in cheatsheet 2015-05-08 15:57:59 +02:00
Jason Turner
ef92b6619e Increment develop to 5.7.1 2015-05-06 14:18:28 -06:00
78 changed files with 4111 additions and 1869 deletions

View File

@@ -10,12 +10,12 @@ 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
- 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"

View File

@@ -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

View File

@@ -18,6 +18,7 @@ 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)
mark_as_advanced(USE_STD_MAKE_SHARED)
@@ -67,6 +68,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)
@@ -94,7 +102,7 @@ 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_PATCH 2)
set(CPACK_PACKAGE_EXECUTABLES "chai;ChaiScript Eval")
set(CPACK_PACKAGE_VENDOR "ChaiScript.com")
@@ -173,7 +181,7 @@ else()
add_definitions(-Wall -Wextra -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-sign-conversion -Wno-missing-prototypes -Wno-padded -Wno-missing-noreturn -Wno-exit-time-destructors)
else()
add_definitions(-Wnoexcept)
endif()
@@ -252,6 +260,8 @@ 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)
@@ -269,9 +279,51 @@ 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)
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
@@ -314,6 +366,19 @@ 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}/"
)
foreach(filename ${UNIT_TESTS})
message(STATUS "Adding test ${filename}")

View File

@@ -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
@@ -57,6 +80,18 @@ It's not strictly necessary to add types, but it helps with many things. Cloning
chai.add(chaiscript::user_type<MyClass>, "MyClass");
```
## Adding Type Conversions
User defined type conversions are possible, defined in either script or in C++.
A helper function exists for strongly typed and ChaiScript `Vector` function conversion definition:
```
chai.add(chaiscript::vector_conversion<std::vector<int>>());
```
This allows you to pass a ChaiScript function to a function requiring `std::vector<int>`
## Adding Objects
```
@@ -68,6 +103,22 @@ 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
```
# 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 +131,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
```
@@ -152,7 +205,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++
```
@@ -183,7 +236,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 +254,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 +354,18 @@ 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

View 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";
}

View File

@@ -35,6 +35,10 @@
#define CHAISCRIPT_HAS_THREAD_LOCAL
#endif
#if (defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ == 6)
#define CHAISCRIPT_GCC_4_6
#endif
#if (defined(__GNUC__) && __GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7) || defined(CHAISCRIPT_MSVC) || defined(__llvm__)
#define CHAISCRIPT_OVERRIDE override
#else
@@ -48,7 +52,7 @@
#define CHAISCRIPT_MODULE_EXPORT extern "C"
#endif
#ifdef CHAISCRIPT_MSVC
#ifdef CHAISCRIPT_MSVC_12
#define CHAISCRIPT_NOEXCEPT throw()
#define CHAISCRIPT_CONSTEXPR
#else
@@ -61,7 +65,7 @@
namespace chaiscript {
static const int version_major = 5;
static const int version_minor = 7;
static const int version_patch = 0;
static const int version_patch = 2;
template<typename B, typename D, typename ...Arg>
inline std::shared_ptr<B> make_shared(Arg && ... arg)

View File

@@ -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;
}

View File

@@ -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"
@@ -153,6 +155,7 @@ 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);

View File

@@ -36,7 +36,7 @@ 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())
{
}

View File

@@ -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> &params)
{
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"}

View File

@@ -243,18 +243,18 @@ 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 {
return c.at(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 {
return c.at(index);
}), "[]");
return m;
@@ -277,9 +277,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 +319,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 +328,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 +358,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 +369,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 +463,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 +549,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 +600,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 +627,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");

View File

@@ -79,13 +79,6 @@ 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>())
{
try {
@@ -108,10 +101,6 @@ namespace chaiscript
throw exception::bad_boxed_cast(bv.get_type_info(), typeid(Type));
}
#ifdef CHAISCRIPT_MSVC
#pragma warning(pop)
#endif
}
}

View File

@@ -58,6 +58,7 @@ namespace chaiscript
{
};
/// Cast_Helper_Inner for casting to a const * type
template<typename Result>
struct Cast_Helper_Inner<const Result *>
@@ -81,11 +82,11 @@ namespace chaiscript
typedef Result * Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *)
{
if (ob.is_ref())
if (!ob.get_type_info().is_const() && ob.get_type_info() == typeid(Result))
{
return &(ob.get().cast<std::reference_wrapper<Result> >()).get();
return static_cast<Result *>(throw_if_null(ob.get_ptr()));
} else {
return (ob.get().cast<std::shared_ptr<Result> >()).get();
throw chaiscript::detail::exception::bad_any_cast();
}
}
};
@@ -149,7 +150,6 @@ namespace chaiscript
{
};
/// Cast_Helper_Inner for casting to a const std::shared_ptr<const> & type
template<typename Result>
struct Cast_Helper_Inner<const std::shared_ptr<const Result> > : Cast_Helper_Inner<std::shared_ptr<const Result> >
@@ -162,12 +162,11 @@ 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 *)
{
@@ -179,11 +178,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 *)
{
return const_cast<Boxed_Value &>(ob);
return std::ref(const_cast<Boxed_Value &>(ob));
}
};

View File

@@ -43,7 +43,7 @@ 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)
#endif
@@ -59,8 +59,22 @@ namespace chaiscript
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 +84,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();
}
}
static Boxed_Value oper(Operators::Opers t_oper, const Boxed_Value &t_lhs, const Boxed_Value &t_rhs)
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)
{
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_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();
}
inline static Boxed_Value oper(Operators::Opers t_oper, const Boxed_Value &t_lhs)
{
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 +518,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 +545,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 +587,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 +677,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 +692,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 +770,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 +859,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 +874,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 +995,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);
}

View File

@@ -297,6 +297,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 +337,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 {

View 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-2015, 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

View File

@@ -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"
@@ -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;
@@ -407,8 +430,7 @@ namespace chaiscript
};
Dispatch_Engine()
: m_stack_holder(this),
m_place_holder(std::make_shared<dispatch::Placeholder_Object>())
: m_stack_holder(this)
{
}
@@ -438,14 +460,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 +482,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 +518,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 +533,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 +551,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())
{
@@ -524,15 +565,27 @@ namespace chaiscript
/// 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
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
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 +596,73 @@ namespace chaiscript
/// Pushes a new stack on to the list of stacks
void new_stack()
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()
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.load(std::memory_order_relaxed);
// 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.store( 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),
std::memory_order_relaxed);
return s->second;
}
}
}
t_loc.store( static_cast<uint_fast32_t>(Loc::located), std::memory_order_relaxed);
} 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.store(uint_fast32_t(obj.first), std::memory_order_relaxed);
return obj.second;
}
/// Registers a new named type
@@ -647,20 +720,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.load(std::memory_order_relaxed);
auto method_missing_funs = get_function("method_missing", method_missing_loc);
if (method_missing_funs.first != method_missing_loc) m_method_missing_loc.store(uint_fast32_t(method_missing_funs.first), std::memory_order_relaxed);
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 +750,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 +789,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 +800,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 +812,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 +836,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 +874,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);
}
@@ -832,31 +919,54 @@ namespace chaiscript
#pragma warning(push)
#pragma warning(disable : 4715)
#endif
Boxed_Value call_member(const std::string &t_name, const std::vector<Boxed_Value> &params, 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> &params, bool t_has_params)
{
const auto funs = get_function(t_name);
uint_fast32_t loc = t_loc.load(std::memory_order_relaxed);
const auto funs = get_function(t_name, loc);
if (funs.first != loc) t_loc.store(uint_fast32_t(funs.first), std::memory_order_relaxed);
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
{
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());
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});
} 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)) {
return do_attribute_call(1, params, *funs.second, m_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, m_conversions);
} catch(chaiscript::exception::dispatch_error&) {
except = std::current_exception();
}
@@ -868,7 +978,9 @@ 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)) {
fs.push_back(f);
@@ -890,12 +1002,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, m_conversions);
} else {
return dispatch::dispatch(functions, {params[0], var(t_name), var(std::vector<Boxed_Value>(params.begin()+1, params.end()))}, m_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 +1021,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 +1031,14 @@ namespace chaiscript
Boxed_Value call_function(const std::string &t_name, const std::vector<Boxed_Value> &params) const
Boxed_Value call_function(const std::string &t_name, std::atomic_uint_fast32_t &t_loc, const std::vector<Boxed_Value> &params) 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.load(std::memory_order_relaxed);
const auto funs = get_function(t_name, loc);
if (funs.first != loc) t_loc.store(uint_fast32_t(funs.first), std::memory_order_relaxed);
return dispatch::dispatch(*funs.second, params, m_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
@@ -1048,7 +1149,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 +1156,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;
}
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));
}
void save_function_params(Stack_Holder &t_s, std::vector<Boxed_Value> &&t_params)
{
for (auto &&param : t_params)
{
t_s.call_params.back().insert(t_s.call_params.back().begin(), std::move(param));
}
}
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 &&param : 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()
void new_function_call(Stack_Holder &t_s)
{
Stack_Holder &s = *m_stack_holder;
if (s.call_depth == 0)
if (t_s.call_depth == 0)
{
m_conversions.enable_conversion_saves(true);
}
++s.call_depth;
++t_s.call_depth;
save_function_params(m_conversions.take_saves());
}
void pop_function_call()
void pop_function_call(Stack_Holder &t_s)
{
Stack_Holder &s = *m_stack_holder;
--s.call_depth;
--t_s.call_depth;
assert(s.call_depth >= 0);
assert(t_s.call_depth >= 0);
if (s.call_depth == 0)
if (t_s.call_depth == 0)
{
s.call_params.back().clear();
t_s.call_params.back().clear();
m_conversions.enable_conversion_saves(false);
}
}
private:
void new_function_call()
{
new_function_call(*m_stack_holder);
}
void pop_function_call()
{
pop_function_call(*m_stack_holder);
}
Stack_Holder &get_stack_holder()
{
return *m_stack_holder;
}
/// Returns the current stack
/// make const/non const versions
const StackData &get_stack_data() const
@@ -1118,27 +1240,44 @@ namespace chaiscript
return m_stack_holder->stacks.back();
}
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 +1314,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 +1391,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 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 +1442,82 @@ 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())
{
}
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();
}
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;
};
}
}

View File

@@ -24,23 +24,53 @@ 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")
{
}
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 +89,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 +113,7 @@ namespace chaiscript
private:
std::string m_type_name;
bool m_option_explicit;
std::map<std::string, Boxed_Value> m_attrs;
};

View File

@@ -232,7 +232,7 @@ namespace chaiscript
protected:
virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions &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());

View File

@@ -14,6 +14,7 @@
#include "boxed_cast.hpp"
#include "function_call_detail.hpp"
#include "proxy_functions.hpp"
#include "callable_traits.hpp"
namespace chaiscript {
class Boxed_Value;
@@ -37,6 +38,15 @@ namespace chaiscript
std::function<FunctionType>
functor(const std::vector<Const_Proxy_Function> &funcs, const Type_Conversions *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);
}

View File

@@ -31,9 +31,9 @@ namespace chaiscript
struct Function_Caller_Ret
{
static Ret call(const std::vector<Const_Proxy_Function> &t_funcs,
const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions)
const std::vector<Boxed_Value> &params, const Type_Conversions *t_conversions)
{
return boxed_cast<Ret>(dispatch::dispatch(t_funcs, params, t_conversions));
return boxed_cast<Ret>(dispatch::dispatch(t_funcs, params, t_conversions?*t_conversions:Type_Conversions()), t_conversions);
}
};
@@ -44,9 +44,9 @@ namespace chaiscript
struct Function_Caller_Ret<Ret, true>
{
static Ret call(const std::vector<Const_Proxy_Function> &t_funcs,
const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions)
const std::vector<Boxed_Value> &params, const Type_Conversions *t_conversions)
{
return Boxed_Number(dispatch::dispatch(t_funcs, params, t_conversions)).get_as<Ret>();
return Boxed_Number(dispatch::dispatch(t_funcs, params, t_conversions?*t_conversions:Type_Conversions())).get_as<Ret>();
}
};
@@ -58,9 +58,9 @@ namespace chaiscript
struct Function_Caller_Ret<void, false>
{
static void call(const std::vector<Const_Proxy_Function> &t_funcs,
const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions)
const std::vector<Boxed_Value> &params, const Type_Conversions *t_conversions)
{
dispatch::dispatch(t_funcs, params, t_conversions);
dispatch::dispatch(t_funcs, params, t_conversions?*t_conversions:Type_Conversions());
}
};
@@ -70,31 +70,53 @@ 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)...
box<P>(std::forward<P>(param))...
}, m_conversions
);
}
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)
{
/*
if (funcs.size() == 1)
{
std::shared_ptr<const Proxy_Function_Impl<Ret (Params...)>> pfi =
@@ -108,8 +130,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));
}
}
}

View File

@@ -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,20 +103,14 @@ 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)
);
}
};

View File

@@ -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));
}
}
}

View File

@@ -16,6 +16,7 @@
#include <string>
#include <type_traits>
#include <vector>
#include <iterator>
#include "../chaiscript_defines.hpp"
#include "boxed_cast.hpp"
@@ -148,7 +149,11 @@ namespace chaiscript
Boxed_Value operator()(const std::vector<Boxed_Value> &params, const chaiscript::Type_Conversions &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
@@ -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;
@@ -206,7 +211,7 @@ namespace chaiscript
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())
@@ -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 &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))
{
}
@@ -349,24 +349,8 @@ namespace chaiscript
return m_description;
}
protected:
virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
{
if (m_arity < 0 || params.size() == size_t(m_arity))
{
if (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> &params, const Type_Conversions &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> &params, const Type_Conversions &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
@@ -543,54 +575,50 @@ namespace chaiscript
virtual bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions &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;
};
/// 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
{
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> &params, const Type_Conversions &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
{
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
@@ -643,14 +670,13 @@ namespace chaiscript
protected:
virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions &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>
@@ -697,19 +723,14 @@ namespace chaiscript
protected:
virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions &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 {}
@@ -755,49 +784,38 @@ namespace chaiscript
bool types_match_except_for_arithmetic(const FuncType &t_func, const std::vector<Boxed_Value> &plist,
const Type_Conversions &t_conversions)
{
if (t_func->get_arity() != static_cast<int>(plist.size()))
{
return false;
}
const std::vector<Type_Info> &types = t_func->get_param_types();
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 &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,30 @@ 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());
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 &param) -> Boxed_Value {
if (ti.is_arithmetic() && param.get_type_info().is_arithmetic()) {
return Boxed_Number(param).get_as(ti).bv;
} else {
return param;
}
}
);
for (size_t i = 0; i < plist.size(); ++i)
{
if (tis[i+1].is_arithmetic()
&& plist[i].get_type_info().is_arithmetic()) {
newplist.push_back(Boxed_Number(plist[i]).get_as(tis[i+1]).bv);
} else {
newplist.push_back(plist[i]);
}
}
try {
return (*(*matching_func))(newplist, t_conversions);
return (*(matching_func->second))(newplist, t_conversions);
} catch (const exception::bad_boxed_cast &) {
//parameter failed to cast
} catch (const exception::arity_error &) {
@@ -843,7 +866,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()));
}
}
@@ -857,18 +880,18 @@ namespace chaiscript
Boxed_Value dispatch(const Funcs &funcs,
const std::vector<Boxed_Value> &plist, const Type_Conversions &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 +899,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);
}
}
}

View File

@@ -16,6 +16,7 @@
#include "boxed_value.hpp"
#include "handle_return.hpp"
#include "type_info.hpp"
#include "callable_traits.hpp"
namespace chaiscript {
class Type_Conversions;
@@ -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;
@@ -97,7 +102,7 @@ namespace chaiscript
template<typename Ret, typename ... Params>
bool compare_types_cast(Ret (*)(Params...),
const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions)
{
{
try {
Try_Cast<Params...>::do_try(params, 0, t_conversions);
} catch (const exception::bad_boxed_cast &) {
@@ -111,8 +116,8 @@ namespace chaiscript
struct Call_Func
{
template<typename ... InnerParams>
static Ret do_call(const std::function<Ret (Params...)> &f,
template<typename Callable, typename ... InnerParams>
static Ret do_call(const Callable &f,
const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions, InnerParams &&... innerparams)
{
return Call_Func<Ret, count - 1, Params...>::do_call(f, params, t_conversions, std::forward<InnerParams>(innerparams)..., params[sizeof...(Params) - count]);
@@ -126,8 +131,8 @@ 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,
template<typename Callable, typename ... InnerParams>
static Ret do_call(const Callable &f,
const std::vector<Boxed_Value> &, const Type_Conversions &t_conversions, InnerParams &&... innerparams)
{
return f(boxed_cast<Params>(std::forward<InnerParams>(innerparams), &t_conversions)...);
@@ -143,8 +148,8 @@ 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,
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> &params, const Type_Conversions &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> &params, const Type_Conversions &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> &params, const Type_Conversions &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> &params, const Type_Conversions &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> &params, const Type_Conversions &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> &params, const Type_Conversions &t_conversions)
template<typename Signature, typename Callable>
static Boxed_Value go(const Callable &fun, const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions)
{
return Handle_Return<Ret>::handle(call_func(fun, params, t_conversions));
return Handle_Return<Ret>::handle(call_func(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> &params, const Type_Conversions &t_conversions)
template<typename Signature, typename Callable>
static Boxed_Value go(const Callable &fun, const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions)
{
call_func(fun, params, t_conversions);
call_func(Function_Signature<Signature>(), fun, params, t_conversions);
return Handle_Return<void>::handle();
}
};

View File

@@ -7,7 +7,6 @@
#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

View File

@@ -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,6 +301,12 @@ namespace chaiscript
return m_func(t_from);
}
virtual bool bidir() const CHAISCRIPT_OVERRIDE
{
return false;
}
private:
Callable m_func;
};
@@ -242,7 +337,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,7 +383,7 @@ 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;
}
@@ -338,7 +433,7 @@ namespace chaiscript
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
@@ -356,6 +451,19 @@ namespace chaiscript
}
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
{
@@ -417,17 +525,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 +575,24 @@ 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;
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);
}
}

View File

@@ -62,7 +62,7 @@ namespace chaiscript
CHAISCRIPT_CONSTEXPR bool operator==(const Type_Info &ti) const CHAISCRIPT_NOEXCEPT
{
return ti.m_type_info == m_type_info
return ti.m_type_info == m_type_info
|| (ti.m_type_info && m_type_info && *ti.m_type_info == *m_type_info);
}
@@ -87,7 +87,7 @@ namespace chaiscript
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_undef() const CHAISCRIPT_NOEXCEPT { return m_is_undef; }
CHAISCRIPT_CONSTEXPR bool is_pointer() const CHAISCRIPT_NOEXCEPT { return m_is_pointer; }
std::string name() const
@@ -100,7 +100,7 @@ namespace chaiscript
}
}
std::string bare_name() const
std::string bare_name() const
{
if (m_bare_type_info)
{
@@ -134,12 +134,14 @@ 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,
&typeid(T),
(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,11 +151,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::shared_ptr<T> ),
&typeid(typename Bare_Type<T>::type));
}
@@ -164,11 +166,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::shared_ptr<T> &),
&typeid(typename Bare_Type<T>::type));
}
@@ -179,11 +181,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 +196,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 +218,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 +233,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();
}

View File

@@ -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);
@@ -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());
}
~Function_Push_Pop()
{
m_de.pop_function_call();
m_ds.get()->pop_function_call(m_ds.get().stack_holder());
}
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;
};
}
}

View File

@@ -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
{
@@ -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) {
@@ -356,57 +350,58 @@ 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> &)>(
m_engine.add(fun(
[=](const dispatch::Proxy_Function_Base &t_fun, const std::vector<Boxed_Value> &t_params) {
return t_fun(t_params, this->m_engine.conversions());
}), "call");
m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::get_type_name, std::ref(m_engine)), "name");
m_engine.add(fun([this](const Type_Info &t_ti){ return m_engine.get_type_name(t_ti); }), "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 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<void(const Type_Info &, const Type_Info &, const std::function<Boxed_Value(const Boxed_Value &)> &)>(
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::add_global_const, this), "add_global_const");
m_engine.add(fun(&ChaiScript::add_global, this), "add_global");
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");
do_eval(ChaiScript_Prelude::chaiscript_prelude(), "standard prelude");
}
@@ -518,6 +513,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;

View File

@@ -44,19 +44,37 @@ namespace chaiscript
namespace detail
{
/// Helper function that will set up the scope around a function call, including handling the named function parameters
static Boxed_Value eval_function(chaiscript::detail::Dispatch_Engine &t_ss, const AST_NodePtr &t_node, const std::vector<std::string> &t_param_names, const std::vector<Boxed_Value> &t_vals, const std::map<std::string, Boxed_Value> &t_locals=std::map<std::string, Boxed_Value>()) {
chaiscript::eval::detail::Scope_Push_Pop spp(t_ss);
static Boxed_Value eval_function(chaiscript::detail::Dispatch_Engine &t_ss, const AST_NodePtr &t_node, const std::vector<std::string> &t_param_names, const std::vector<Boxed_Value> &t_vals, const std::map<std::string, Boxed_Value> *t_locals=nullptr) {
chaiscript::detail::Dispatch_State state(t_ss);
for (const auto &local : t_locals) {
t_ss.add_object(local.first, local.second);
const Boxed_Value *thisobj = [&]() -> const Boxed_Value *{
auto &stack = t_ss.get_stack_data(state.stack_holder()).back();
if (!stack.empty() && stack.back().first == "__this") {
return &stack.back().second;
} else if (!t_vals.empty()) {
return &t_vals[0];
} else {
return nullptr;
}
}();
chaiscript::eval::detail::Stack_Push_Pop tpp(state);
if (thisobj) state.add_object("this", *thisobj);
if (t_locals) {
for (const auto &local : *t_locals) {
state.add_object(local.first, local.second);
}
}
for (size_t i = 0; i < t_param_names.size(); ++i) {
t_ss.add_object(t_param_names[i], t_vals[i]);
if (t_param_names[i] != "this") {
state.add_object(t_param_names[i], t_vals[i]);
}
}
try {
return t_node->eval(t_ss);
return t_node->eval(state);
} catch (detail::Return_Value &rv) {
return std::move(rv.retval);
}
@@ -71,10 +89,10 @@ namespace chaiscript
{ }
virtual ~Binary_Operator_AST_Node() {}
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE {
return do_oper(t_ss, m_oper, text,
this->children[0]->eval(t_ss),
this->children[1]->eval(t_ss));
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE {
auto lhs = this->children[0]->eval(t_ss);
auto rhs = this->children[1]->eval(t_ss);
return do_oper(t_ss, m_oper, text, lhs, rhs);
}
virtual std::string pretty_print() const CHAISCRIPT_OVERRIDE
@@ -83,7 +101,7 @@ namespace chaiscript
}
protected:
Boxed_Value do_oper(chaiscript::detail::Dispatch_Engine &t_ss,
Boxed_Value do_oper(const chaiscript::detail::Dispatch_State &t_ss,
Operators::Opers t_oper, const std::string &t_oper_string, const Boxed_Value &t_lhs, const Boxed_Value &t_rhs) const
{
try {
@@ -100,26 +118,26 @@ namespace chaiscript
} else {
chaiscript::eval::detail::Function_Push_Pop fpp(t_ss);
fpp.save_params({t_lhs, t_rhs});
chaiscript::eval::detail::Stack_Push_Pop spp(t_ss);
return t_ss.call_function(t_oper_string, t_lhs, t_rhs);
return t_ss->call_function(t_oper_string, m_loc, {t_lhs, t_rhs});
}
}
catch(const exception::dispatch_error &e){
throw exception::eval_error("Can not find appropriate '" + t_oper_string + "' operator.", e.parameters, e.functions, false, t_ss);
throw exception::eval_error("Can not find appropriate '" + t_oper_string + "' operator.", e.parameters, e.functions, false, *t_ss);
}
}
private:
Operators::Opers m_oper;
mutable std::atomic_uint_fast32_t m_loc;
};
struct Int_AST_Node : public AST_Node {
public:
Int_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, Boxed_Value t_bv) :
AST_Node(std::move(t_ast_node_text), AST_Node_Type::Int, std::move(t_loc)),
m_value(std::move(t_bv)) { }
m_value(std::move(t_bv)) { assert(text != ""); }
virtual ~Int_AST_Node() {}
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &) const CHAISCRIPT_OVERRIDE{
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &) const CHAISCRIPT_OVERRIDE{
return m_value;
}
@@ -134,7 +152,7 @@ namespace chaiscript
AST_Node(std::move(t_ast_node_text), AST_Node_Type::Float, std::move(t_loc)),
m_value(std::move(t_bv)) { }
virtual ~Float_AST_Node() {}
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &) const CHAISCRIPT_OVERRIDE{
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &) const CHAISCRIPT_OVERRIDE{
return m_value;
}
@@ -147,17 +165,17 @@ namespace chaiscript
public:
Id_AST_Node(const std::string &t_ast_node_text, Parse_Location t_loc) :
AST_Node(t_ast_node_text, AST_Node_Type::Id, std::move(t_loc)),
m_value(get_value(t_ast_node_text))
m_value(get_value(t_ast_node_text)), m_loc(0)
{ }
virtual ~Id_AST_Node() {}
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE {
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE {
if (!m_value.is_undef())
{
return m_value;
} else {
try {
return t_ss.get_object(this->text);
return t_ss->get_object(this->text, m_loc);
}
catch (std::exception &) {
throw exception::eval_error("Can not find object: " + this->text);
@@ -170,21 +188,22 @@ namespace chaiscript
{
if (t_text == "true") {
return const_var(true);
}
else if (t_text == "false") {
} else if (t_text == "false") {
return const_var(false);
}
else if (t_text == "Infinity") {
} else if (t_text == "Infinity") {
return const_var(std::numeric_limits<double>::infinity());
}
else if (t_text == "NaN") {
} else if (t_text == "NaN") {
return const_var(std::numeric_limits<double>::quiet_NaN());
} else if (t_text == "_") {
return Boxed_Value(std::make_shared<dispatch::Placeholder_Object>());
} else {
return Boxed_Value();
}
}
Boxed_Value m_value;
mutable std::atomic_uint_fast32_t m_loc;
};
struct Char_AST_Node : public AST_Node {
@@ -219,7 +238,7 @@ namespace chaiscript
Fun_Call_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_NodePtr> t_children) :
AST_Node(std::move(t_ast_node_text), AST_Node_Type::Fun_Call, std::move(t_loc), std::move(t_children)) { }
virtual ~Fun_Call_AST_Node() {}
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE{
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE{
chaiscript::eval::detail::Function_Push_Pop fpp(t_ss);
std::vector<Boxed_Value> params;
@@ -234,17 +253,16 @@ namespace chaiscript
Boxed_Value fn(this->children[0]->eval(t_ss));
try {
chaiscript::eval::detail::Stack_Push_Pop spp(t_ss);
return (*t_ss.boxed_cast<const Const_Proxy_Function &>(fn))(params, t_ss.conversions());
return (*t_ss->boxed_cast<const Const_Proxy_Function &>(fn))(params, t_ss->conversions());
}
catch(const exception::dispatch_error &e){
throw exception::eval_error(std::string(e.what()) + " with function '" + this->children[0]->text + "'", e.parameters, e.functions, false, t_ss);
throw exception::eval_error(std::string(e.what()) + " with function '" + this->children[0]->text + "'", e.parameters, e.functions, false, *t_ss);
}
catch(const exception::bad_boxed_cast &){
try {
Const_Proxy_Function f = t_ss.boxed_cast<const Const_Proxy_Function &>(fn);
Const_Proxy_Function f = t_ss->boxed_cast<const Const_Proxy_Function &>(fn);
// handle the case where there is only 1 function to try to call and dispatch fails on it
throw exception::eval_error("Error calling function '" + this->children[0]->text + "'", params, {f}, false, t_ss);
throw exception::eval_error("Error calling function '" + this->children[0]->text + "'", params, {f}, false, *t_ss);
} catch (const exception::bad_boxed_cast &) {
throw exception::eval_error("'" + this->children[0]->pretty_print() + "' does not evaluate to a function.");
}
@@ -282,96 +300,7 @@ namespace chaiscript
};
struct Fun_Lookup_AST_Node : public AST_Node {
public:
Fun_Lookup_AST_Node(const std::string &t_fun_name)
: AST_Node(t_fun_name, 0, Parse_Location("<EVAL>"))
{
}
virtual ~Fun_Lookup_AST_Node() {}
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE {
try {
Boxed_Value bv = t_ss.get_object(text);
t_ss.add_object(text, bv);
std::cout << " Saved fun lookup: " << text << '\n';
return bv;
} catch (...) {
return Boxed_Value();
}
}
};
/// Used in the context of in-string ${} evals, so that no new scope is created
struct Inplace_Fun_Call_AST_Node : public AST_Node {
public:
Inplace_Fun_Call_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_NodePtr> t_children) :
AST_Node(t_ast_node_text, AST_Node_Type::Inplace_Fun_Call, std::move(t_loc), std::move(t_children))
{ assert(children.size() == 2); }
virtual ~Inplace_Fun_Call_AST_Node() {}
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE{
std::vector<Boxed_Value> params;
chaiscript::eval::detail::Function_Push_Pop fpp(t_ss);
for (const auto &child : this->children[1]->children) {
params.push_back(child->eval(t_ss));
}
Const_Proxy_Function fn;
try {
Boxed_Value bv = this->children[0]->eval(t_ss);
try {
fn = t_ss.boxed_cast<const Const_Proxy_Function &>(bv);
} catch (const exception::bad_boxed_cast &) {
throw exception::eval_error("'" + this->children[0]->pretty_print() + "' does not evaluate to a function.");
}
return (*fn)(params, t_ss.conversions());
}
catch(const exception::dispatch_error &e){
throw exception::eval_error(std::string(e.what()) + " with function '" + this->children[0]->text + "'", e.parameters, e.functions, false, t_ss);
}
catch(const exception::bad_boxed_cast &){
// handle the case where there is only 1 function to try to call and dispatch fails on it
throw exception::eval_error("Error calling function '" + this->children[0]->text + "'", params, {fn}, false, t_ss);
}
catch(const exception::arity_error &e){
throw exception::eval_error(std::string(e.what()) + " with function '" + this->children[0]->text + "'");
}
catch(const exception::guard_error &e){
throw exception::eval_error(std::string(e.what()) + " with function '" + this->children[0]->text + "'");
}
catch(detail::Return_Value &rv) {
return rv.retval;
}
}
virtual std::string pretty_print() const CHAISCRIPT_OVERRIDE
{
std::ostringstream oss;
int count = 0;
for (const auto &child : this->children) {
oss << child->pretty_print();
if (count == 0)
{
oss << "(";
}
++count;
}
oss << ")";
return oss.str();
}
};
struct Arg_AST_Node : public AST_Node {
public:
@@ -438,17 +367,17 @@ namespace chaiscript
return retval;
}
static std::pair<std::string, Type_Info> get_arg_type(const AST_NodePtr &t_node, chaiscript::detail::Dispatch_Engine &t_ss)
static std::pair<std::string, Type_Info> get_arg_type(const AST_NodePtr &t_node, const chaiscript::detail::Dispatch_State &t_ss)
{
if (t_node->children.size() < 2)
{
return std::pair<std::string, Type_Info>();
} else {
return std::pair<std::string, Type_Info>(t_node->children[0]->text, t_ss.get_type(t_node->children[0]->text, false));
return std::pair<std::string, Type_Info>(t_node->children[0]->text, t_ss->get_type(t_node->children[0]->text, false));
}
}
static dispatch::Param_Types get_arg_types(const AST_NodePtr &t_node, chaiscript::detail::Dispatch_Engine &t_ss) {
static dispatch::Param_Types get_arg_types(const AST_NodePtr &t_node, const chaiscript::detail::Dispatch_State &t_ss) {
std::vector<std::pair<std::string, Type_Info>> retval;
for (const auto &child : t_node->children)
@@ -468,9 +397,11 @@ namespace chaiscript
{ assert(children.size() == 3); }
Operators::Opers m_oper;
mutable std::atomic_uint_fast32_t m_loc;
mutable std::atomic_uint_fast32_t m_clone_loc;
virtual ~Equation_AST_Node() {}
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE {
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE {
chaiscript::eval::detail::Function_Push_Pop fpp(t_ss);
Boxed_Value rhs = this->children[2]->eval(t_ss);
Boxed_Value lhs = this->children[0]->eval(t_ss);
@@ -503,35 +434,36 @@ namespace chaiscript
} else {
if (!rhs.is_return_value())
{
rhs = t_ss.call_function("clone", rhs);
rhs = t_ss->call_function("clone", m_clone_loc, {rhs});
}
rhs.reset_return_value();
}
}
try {
return t_ss.call_function(this->children[1]->text, std::move(lhs), rhs);
return t_ss->call_function(this->children[1]->text, m_loc, {std::move(lhs), rhs});
}
catch(const exception::dispatch_error &e){
throw exception::eval_error("Unable to find appropriate'" + this->children[1]->text + "' operator.", e.parameters, e.functions, false, t_ss);
throw exception::eval_error("Unable to find appropriate'" + this->children[1]->text + "' operator.", e.parameters, e.functions, false, *t_ss);
}
}
catch(const exception::dispatch_error &e){
throw exception::eval_error("Missing clone or copy constructor for right hand side of equation", e.parameters, e.functions, false, t_ss);
throw exception::eval_error("Missing clone or copy constructor for right hand side of equation", e.parameters, e.functions, false, *t_ss);
}
}
else if (this->children[1]->text == ":=") {
if (lhs.is_undef() || Boxed_Value::type_match(lhs, rhs)) {
lhs.assign(rhs);
lhs.reset_return_value();
} else {
throw exception::eval_error("Mismatched types in equation");
}
}
else {
try {
return t_ss.call_function(this->children[1]->text, std::move(lhs), rhs);
return t_ss->call_function(this->children[1]->text, m_loc, {std::move(lhs), rhs});
} catch(const exception::dispatch_error &e){
throw exception::eval_error("Unable to find appropriate'" + this->children[1]->text + "' operator.", e.parameters, e.functions, false, t_ss);
throw exception::eval_error("Unable to find appropriate'" + this->children[1]->text + "' operator.", e.parameters, e.functions, false, *t_ss);
}
}
@@ -544,7 +476,7 @@ namespace chaiscript
Global_Decl_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_NodePtr> t_children) :
AST_Node(std::move(t_ast_node_text), AST_Node_Type::Global_Decl, std::move(t_loc), std::move(t_children)) { }
virtual ~Global_Decl_AST_Node() {}
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE {
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE {
const std::string &idname =
[&]()->const std::string &{
@@ -556,7 +488,7 @@ namespace chaiscript
}();
try {
return t_ss.add_global_no_throw(Boxed_Value(), idname);
return t_ss->add_global_no_throw(Boxed_Value(), idname);
}
catch (const exception::reserved_word_error &) {
throw exception::eval_error("Reserved word used as global '" + idname + "'");
@@ -571,7 +503,7 @@ namespace chaiscript
Var_Decl_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_NodePtr> t_children) :
AST_Node(std::move(t_ast_node_text), AST_Node_Type::Var_Decl, std::move(t_loc), std::move(t_children)) { }
virtual ~Var_Decl_AST_Node() {}
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE {
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE {
if (this->children[0]->identifier == AST_Node_Type::Reference)
{
return this->children[0]->eval(t_ss);
@@ -605,18 +537,17 @@ namespace chaiscript
Array_Call_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_NodePtr> t_children) :
AST_Node(std::move(t_ast_node_text), AST_Node_Type::Array_Call, std::move(t_loc), std::move(t_children)) { }
virtual ~Array_Call_AST_Node() {}
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE{
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE{
chaiscript::eval::detail::Function_Push_Pop fpp(t_ss);
std::vector<Boxed_Value> params{children[0]->eval(t_ss), children[1]->eval(t_ss)};
try {
chaiscript::eval::detail::Stack_Push_Pop spp(t_ss);
fpp.save_params(params);
return t_ss.call_function("[]", params);
return t_ss->call_function("[]", m_loc, params);
}
catch(const exception::dispatch_error &e){
throw exception::eval_error("Can not find appropriate array lookup operator '[]'.", e.parameters, e.functions, false, t_ss );
throw exception::eval_error("Can not find appropriate array lookup operator '[]'.", e.parameters, e.functions, false, *t_ss );
}
}
@@ -635,6 +566,8 @@ namespace chaiscript
return oss.str();
}
mutable std::atomic_uint_fast32_t m_loc;
};
struct Dot_Access_AST_Node : public AST_Node {
@@ -646,9 +579,10 @@ namespace chaiscript
children[2]->children[0]->text:children[2]->text) { }
virtual ~Dot_Access_AST_Node() {}
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE{
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE{
chaiscript::eval::detail::Function_Push_Pop fpp(t_ss);
Boxed_Value retval = children[0]->eval(t_ss);
std::vector<Boxed_Value> params{retval};
@@ -663,16 +597,14 @@ namespace chaiscript
fpp.save_params(params);
try {
chaiscript::eval::detail::Stack_Push_Pop spp(t_ss);
t_ss.add_object("this", retval);
retval = t_ss.call_member(m_fun_name, std::move(params), has_function_params);
retval = t_ss->call_member(m_fun_name, m_loc, std::move(params), has_function_params);
}
catch(const exception::dispatch_error &e){
if (e.functions.empty())
{
throw exception::eval_error("'" + m_fun_name + "' is not a function.");
} else {
throw exception::eval_error(std::string(e.what()) + " for function '" + m_fun_name + "'", e.parameters, e.functions, true, t_ss);
throw exception::eval_error(std::string(e.what()) + " for function '" + m_fun_name + "'", e.parameters, e.functions, true, *t_ss);
}
}
catch(detail::Return_Value &rv) {
@@ -681,10 +613,10 @@ namespace chaiscript
if (this->children[2]->identifier == AST_Node_Type::Array_Call) {
try {
retval = t_ss.call_function("[]", retval, this->children[2]->children[1]->eval(t_ss));
retval = t_ss->call_function("[]", m_array_loc, {retval, this->children[2]->children[1]->eval(t_ss)});
}
catch(const exception::dispatch_error &e){
throw exception::eval_error("Can not find appropriate array lookup operator '[]'.", e.parameters, e.functions, true, t_ss);
throw exception::eval_error("Can not find appropriate array lookup operator '[]'.", e.parameters, e.functions, true, *t_ss);
}
}
@@ -692,6 +624,8 @@ namespace chaiscript
}
private:
mutable std::atomic_uint_fast32_t m_loc;
mutable std::atomic_uint_fast32_t m_array_loc;
std::string m_fun_name;
};
@@ -702,7 +636,7 @@ namespace chaiscript
m_value(const_var(text)) { }
virtual ~Quoted_String_AST_Node() {}
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &) const CHAISCRIPT_OVERRIDE {
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &) const CHAISCRIPT_OVERRIDE {
return m_value;
}
@@ -723,7 +657,7 @@ namespace chaiscript
m_value(const_var(char(text.at(0)))) { }
virtual ~Single_Quoted_String_AST_Node() {}
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &) const CHAISCRIPT_OVERRIDE{
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &) const CHAISCRIPT_OVERRIDE{
return m_value;
}
@@ -744,7 +678,7 @@ namespace chaiscript
virtual ~Lambda_AST_Node() {}
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE{
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE{
const auto captures = [&]()->std::map<std::string, Boxed_Value>{
std::map<std::string, Boxed_Value> named_captures;
@@ -759,13 +693,17 @@ namespace chaiscript
const auto param_types = Arg_List_AST_Node::get_arg_types(this->children[1], t_ss);
const auto &lambda_node = this->children.back();
std::reference_wrapper<chaiscript::detail::Dispatch_Engine> engine(*t_ss);
return Boxed_Value(chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Dynamic_Proxy_Function>(
[&t_ss, lambda_node, param_names, captures](const std::vector<Boxed_Value> &t_params)
{
return detail::eval_function(t_ss, lambda_node, param_names, t_params, captures);
},
static_cast<int>(numparams), lambda_node, param_types));
return Boxed_Value(
dispatch::make_dynamic_proxy_function(
[engine, lambda_node, param_names, captures](const std::vector<Boxed_Value> &t_params)
{
return detail::eval_function(engine, lambda_node, param_names, t_params, &captures);
},
static_cast<int>(numparams), lambda_node, param_types
)
);
}
private:
@@ -779,7 +717,7 @@ namespace chaiscript
AST_Node(std::move(t_ast_node_text), AST_Node_Type::Block, std::move(t_loc), std::move(t_children)) { }
virtual ~Block_AST_Node() {}
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE{
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE{
chaiscript::eval::detail::Scope_Push_Pop spp(t_ss);
const auto num_children = children.size();
@@ -797,7 +735,7 @@ namespace chaiscript
AST_Node(std::move(t_ast_node_text), AST_Node_Type::Def, std::move(t_loc), std::move(t_children)) { }
virtual ~Def_AST_Node() {}
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE{
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE{
std::vector<std::string> t_param_names;
size_t numparams = 0;
AST_NodePtr guardnode;
@@ -822,25 +760,29 @@ namespace chaiscript
}
}
std::shared_ptr<dispatch::Dynamic_Proxy_Function> guard;
std::reference_wrapper<chaiscript::detail::Dispatch_Engine> engine(*t_ss);
std::shared_ptr<dispatch::Proxy_Function_Base> guard;
if (guardnode) {
guard = std::make_shared<dispatch::Dynamic_Proxy_Function>
([&t_ss, guardnode, t_param_names](const std::vector<Boxed_Value> &t_params)
{
return detail::eval_function(t_ss, guardnode, t_param_names, t_params);
}, static_cast<int>(numparams), guardnode);
guard = dispatch::make_dynamic_proxy_function(
[engine, guardnode, t_param_names](const std::vector<Boxed_Value> &t_params)
{
return detail::eval_function(engine, guardnode, t_param_names, t_params);
},
static_cast<int>(numparams), guardnode);
}
try {
const std::string & l_function_name = this->children[0]->text;
const std::string & l_annotation = this->annotation?this->annotation->text:"";
const auto & func_node = this->children.back();
t_ss.add(chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Dynamic_Proxy_Function>
([&t_ss, guardnode, func_node, t_param_names](const std::vector<Boxed_Value> &t_params)
{
return detail::eval_function(t_ss, func_node, t_param_names, t_params);
}, static_cast<int>(numparams), this->children.back(),
param_types, l_annotation, guard), l_function_name);
t_ss->add(
dispatch::make_dynamic_proxy_function(
[engine, guardnode, func_node, t_param_names](const std::vector<Boxed_Value> &t_params)
{
return detail::eval_function(engine, func_node, t_param_names, t_params);
},
static_cast<int>(numparams), this->children.back(),
param_types, l_annotation, guard), l_function_name);
}
catch (const exception::reserved_word_error &e) {
throw exception::eval_error("Reserved word used as function name '" + e.word() + "'");
@@ -857,7 +799,7 @@ namespace chaiscript
While_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_NodePtr> t_children) :
AST_Node(std::move(t_ast_node_text), AST_Node_Type::While, std::move(t_loc), std::move(t_children)) { }
virtual ~While_AST_Node() {}
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE {
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE {
chaiscript::eval::detail::Scope_Push_Pop spp(t_ss);
try {
@@ -883,7 +825,7 @@ namespace chaiscript
Class_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_NodePtr> t_children) :
AST_Node(std::move(t_ast_node_text), AST_Node_Type::Class, std::move(t_loc), std::move(t_children)) { }
virtual ~Class_AST_Node() {}
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE {
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE {
chaiscript::eval::detail::Scope_Push_Pop spp(t_ss);
/// \todo do this better
@@ -902,7 +844,7 @@ namespace chaiscript
AST_Node(std::move(t_ast_node_text), AST_Node_Type::If, std::move(t_loc), std::move(t_children))
{ assert(children.size() == 3); }
virtual ~Ternary_Cond_AST_Node() {}
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE {
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE {
if (get_bool_condition(children[0]->eval(t_ss))) {
return children[1]->eval(t_ss);
}
@@ -918,7 +860,7 @@ namespace chaiscript
If_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_NodePtr> t_children) :
AST_Node(std::move(t_ast_node_text), AST_Node_Type::If, std::move(t_loc), std::move(t_children)) { }
virtual ~If_AST_Node() {}
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE{
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE{
if (get_bool_condition(children[0]->eval(t_ss))) {
return children[1]->eval(t_ss);
@@ -951,7 +893,7 @@ namespace chaiscript
{ assert(children.size() == 4); }
virtual ~For_AST_Node() {}
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE{
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE{
chaiscript::eval::detail::Scope_Push_Pop spp(t_ss);
try {
@@ -983,7 +925,7 @@ namespace chaiscript
Switch_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_NodePtr> t_children) :
AST_Node(std::move(t_ast_node_text), AST_Node_Type::Switch, std::move(t_loc), std::move(t_children)) { }
virtual ~Switch_AST_Node() {}
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE {
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE {
bool breaking = false;
size_t currentCase = 1;
bool hasMatched = false;
@@ -997,7 +939,7 @@ namespace chaiscript
if (this->children[currentCase]->identifier == AST_Node_Type::Case) {
//This is a little odd, but because want to see both the switch and the case simultaneously, I do a downcast here.
try {
if (hasMatched || boxed_cast<bool>(t_ss.call_function("==", match_value, this->children[currentCase]->children[0]->eval(t_ss)))) {
if (hasMatched || boxed_cast<bool>(t_ss->call_function("==", m_loc, {match_value, this->children[currentCase]->children[0]->eval(t_ss)}))) {
this->children[currentCase]->eval(t_ss);
hasMatched = true;
}
@@ -1008,7 +950,7 @@ namespace chaiscript
}
else if (this->children[currentCase]->identifier == AST_Node_Type::Default) {
this->children[currentCase]->eval(t_ss);
breaking = true;
hasMatched = true;
}
}
catch (detail::Break_Loop &) {
@@ -1018,6 +960,8 @@ namespace chaiscript
}
return Boxed_Value();
}
mutable std::atomic_uint_fast32_t m_loc;
};
struct Case_AST_Node : public AST_Node {
@@ -1027,7 +971,7 @@ namespace chaiscript
{ assert(children.size() == 2); /* how many children does it have? */ }
virtual ~Case_AST_Node() {}
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE {
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE {
chaiscript::eval::detail::Scope_Push_Pop spp(t_ss);
children[1]->eval(t_ss);
@@ -1042,7 +986,7 @@ namespace chaiscript
AST_Node(std::move(t_ast_node_text), AST_Node_Type::Default, std::move(t_loc), std::move(t_children))
{ assert(children.size() == 1); }
virtual ~Default_AST_Node() {}
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE {
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE {
chaiscript::eval::detail::Scope_Push_Pop spp(t_ss);
children[0]->eval(t_ss);
@@ -1057,12 +1001,17 @@ namespace chaiscript
Inline_Array_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_NodePtr> t_children) :
AST_Node(std::move(t_ast_node_text), AST_Node_Type::Inline_Array, std::move(t_loc), std::move(t_children)) { }
virtual ~Inline_Array_AST_Node() {}
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE {
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE {
try {
std::vector<Boxed_Value> vec;
if (!children.empty()) {
for (const auto &child : children[0]->children) {
vec.push_back(t_ss.call_function("clone", child->eval(t_ss)));
auto obj = child->eval(t_ss);
if (!obj.is_return_value()) {
vec.push_back(t_ss->call_function("clone", m_loc, {obj}));
} else {
vec.push_back(std::move(obj));
}
}
}
return const_var(std::move(vec));
@@ -1076,6 +1025,8 @@ namespace chaiscript
{
return "[" + AST_Node::pretty_print() + "]";
}
mutable std::atomic_uint_fast32_t m_loc;
};
struct Inline_Map_AST_Node : public AST_Node {
@@ -1083,22 +1034,27 @@ namespace chaiscript
Inline_Map_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_NodePtr> t_children) :
AST_Node(std::move(t_ast_node_text), AST_Node_Type::Inline_Map, std::move(t_loc), std::move(t_children)) { }
virtual ~Inline_Map_AST_Node() {}
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE{
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE{
try {
std::map<std::string, Boxed_Value> retval;
for (const auto &child : children[0]->children) {
Boxed_Value bv = t_ss.call_function("clone", child->children[1]->eval(t_ss));
retval[t_ss.boxed_cast<std::string>(child->children[0]->eval(t_ss))] = std::move(bv);
auto obj = child->children[1]->eval(t_ss);
if (!obj.is_return_value()) {
obj = t_ss->call_function("clone", m_loc, {obj});
}
retval[t_ss->boxed_cast<std::string>(child->children[0]->eval(t_ss))] = std::move(obj);
}
return const_var(std::move(retval));
}
catch (const exception::dispatch_error &e) {
throw exception::eval_error("Can not find appropriate copy constructor or 'clone' while inserting into Map.", e.parameters, e.functions, false, t_ss);
throw exception::eval_error("Can not find appropriate copy constructor or 'clone' while inserting into Map.", e.parameters, e.functions, false, *t_ss);
}
}
mutable std::atomic_uint_fast32_t m_loc;
};
struct Return_AST_Node : public AST_Node {
@@ -1106,7 +1062,7 @@ namespace chaiscript
Return_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_NodePtr> t_children) :
AST_Node(std::move(t_ast_node_text), AST_Node_Type::Return, std::move(t_loc), std::move(t_children)) { }
virtual ~Return_AST_Node() {}
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE{
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE{
if (!this->children.empty()) {
throw detail::Return_Value(children[0]->eval(t_ss));
}
@@ -1122,12 +1078,23 @@ namespace chaiscript
File_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_NodePtr> t_children) :
AST_Node(std::move(t_ast_node_text), AST_Node_Type::File, std::move(t_loc), std::move(t_children)) { }
virtual ~File_AST_Node() {}
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE {
const auto num_children = children.size();
for (size_t i = 0; i < num_children-1; ++i) {
children[i]->eval(t_ss);
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE {
try {
const auto num_children = children.size();
if (num_children > 0) {
for (size_t i = 0; i < num_children-1; ++i) {
children[i]->eval(t_ss);
}
return children.back()->eval(t_ss);
} else {
return Boxed_Value();
}
} catch (const detail::Continue_Loop &) {
throw exception::eval_error("Unexpected `continue` statement outside of a loop");
} catch (const detail::Break_Loop &) {
throw exception::eval_error("Unexpected `break` statement outside of a loop");
}
return children.back()->eval(t_ss);
}
};
@@ -1137,7 +1104,7 @@ namespace chaiscript
AST_Node(std::move(t_ast_node_text), AST_Node_Type::Reference, std::move(t_loc), std::move(t_children))
{ assert(children.size() == 1); }
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE{
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE{
try {
Boxed_Value bv;
t_ss.add_object(this->children[0]->text, bv);
@@ -1159,27 +1126,27 @@ namespace chaiscript
{ }
virtual ~Prefix_AST_Node() {}
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE{
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE{
Boxed_Value bv(children[1]->eval(t_ss));
try {
// short circuit arithmetic operations
if (m_oper != Operators::invalid && bv.get_type_info().is_arithmetic())
if (m_oper != Operators::invalid && m_oper != Operators::bitwise_and && bv.get_type_info().is_arithmetic())
{
return Boxed_Number::do_oper(m_oper, std::move(bv));
return Boxed_Number::do_oper(m_oper, bv);
} else {
chaiscript::eval::detail::Function_Push_Pop fpp(t_ss);
chaiscript::eval::detail::Stack_Push_Pop spp(t_ss);
fpp.save_params({bv});
return t_ss.call_function(children[0]->text, std::move(bv));
return t_ss->call_function(children[0]->text, m_loc, {std::move(bv)});
}
} catch (const exception::dispatch_error &e) {
throw exception::eval_error("Error with prefix operator evaluation: '" + children[0]->text + "'", e.parameters, e.functions, false, t_ss);
throw exception::eval_error("Error with prefix operator evaluation: '" + children[0]->text + "'", e.parameters, e.functions, false, *t_ss);
}
}
private:
Operators::Opers m_oper;
mutable std::atomic_uint_fast32_t m_loc;
};
struct Break_AST_Node : public AST_Node {
@@ -1187,7 +1154,7 @@ namespace chaiscript
Break_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_NodePtr> t_children) :
AST_Node(std::move(t_ast_node_text), AST_Node_Type::Break, std::move(t_loc), std::move(t_children)) { }
virtual ~Break_AST_Node() {}
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &) const CHAISCRIPT_OVERRIDE{
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &) const CHAISCRIPT_OVERRIDE{
throw detail::Break_Loop();
}
};
@@ -1197,7 +1164,7 @@ namespace chaiscript
Continue_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_NodePtr> t_children) :
AST_Node(std::move(t_ast_node_text), AST_Node_Type::Continue, std::move(t_loc), std::move(t_children)) { }
virtual ~Continue_AST_Node() {}
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &) const CHAISCRIPT_OVERRIDE{
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &) const CHAISCRIPT_OVERRIDE{
throw detail::Continue_Loop();
}
};
@@ -1210,7 +1177,7 @@ namespace chaiscript
{ }
virtual ~Noop_AST_Node() {}
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &) const CHAISCRIPT_OVERRIDE{
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &) const CHAISCRIPT_OVERRIDE{
// It's a no-op, that evaluates to "true"
return m_value;
}
@@ -1238,17 +1205,18 @@ namespace chaiscript
Inline_Range_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_NodePtr> t_children) :
AST_Node(std::move(t_ast_node_text), AST_Node_Type::Inline_Range, std::move(t_loc), std::move(t_children)) { }
virtual ~Inline_Range_AST_Node() {}
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE{
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE{
try {
return t_ss.call_function("generate_range",
children[0]->children[0]->children[0]->eval(t_ss),
children[0]->children[0]->children[1]->eval(t_ss));
auto oper1 = children[0]->children[0]->children[0]->eval(t_ss);
auto oper2 = children[0]->children[0]->children[1]->eval(t_ss);
return t_ss->call_function("generate_range", m_loc, {oper1, oper2});
}
catch (const exception::dispatch_error &e) {
throw exception::eval_error("Unable to generate range vector, while calling 'generate_range'", e.parameters, e.functions, false, t_ss);
throw exception::eval_error("Unable to generate range vector, while calling 'generate_range'", e.parameters, e.functions, false, *t_ss);
}
}
mutable std::atomic_uint_fast32_t m_loc;
};
struct Annotation_AST_Node : public AST_Node {
@@ -1264,7 +1232,7 @@ namespace chaiscript
AST_Node(std::move(t_ast_node_text), AST_Node_Type::Try, std::move(t_loc), std::move(t_children)) { }
virtual ~Try_AST_Node() {}
Boxed_Value handle_exception(chaiscript::detail::Dispatch_Engine &t_ss, const Boxed_Value &t_except) const
Boxed_Value handle_exception(const chaiscript::detail::Dispatch_State &t_ss, const Boxed_Value &t_except) const
{
Boxed_Value retval;
@@ -1286,7 +1254,7 @@ namespace chaiscript
if (dispatch::Param_Types(
std::vector<std::pair<std::string, Type_Info>>{Arg_List_AST_Node::get_arg_type(catch_block->children[0], t_ss)}
).match(std::vector<Boxed_Value>{t_except}, t_ss.conversions()))
).match(std::vector<Boxed_Value>{t_except}, t_ss->conversions()))
{
t_ss.add_object(name, t_except);
@@ -1325,7 +1293,7 @@ namespace chaiscript
return retval;
}
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE{
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE{
Boxed_Value retval;
chaiscript::eval::detail::Scope_Push_Pop spp(t_ss);
@@ -1340,9 +1308,14 @@ namespace chaiscript
}
throw;
}
catch (const std::runtime_error &e) {
retval = handle_exception(t_ss, Boxed_Value(std::ref(e)));
}
catch (const std::out_of_range &e) {
retval = handle_exception(t_ss, Boxed_Value(std::ref(e)));
}
catch (const std::exception &e) {
retval = handle_exception(t_ss, Boxed_Value(std::ref(e)));
}
catch (Boxed_Value &e) {
retval = handle_exception(t_ss, e);
@@ -1383,11 +1356,11 @@ namespace chaiscript
Method_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_NodePtr> t_children) :
AST_Node(std::move(t_ast_node_text), AST_Node_Type::Method, std::move(t_loc), std::move(t_children)) { }
virtual ~Method_AST_Node() {}
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE{
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE{
AST_NodePtr guardnode;
const auto d = t_ss.get_parent_locals();
const auto d = t_ss->get_parent_locals();
const auto itr = d.find("_current_class_name");
const auto class_offset = (itr != d.end())?-1:0;
const std::string & class_name = (itr != d.end())?std::string(boxed_cast<std::string>(itr->second)):this->children[0]->text;
@@ -1415,39 +1388,48 @@ namespace chaiscript
const size_t numparams = t_param_names.size();
std::shared_ptr<dispatch::Dynamic_Proxy_Function> guard;
std::shared_ptr<dispatch::Proxy_Function_Base> guard;
std::reference_wrapper<chaiscript::detail::Dispatch_Engine> engine(*t_ss);
if (guardnode) {
guard = std::make_shared<dispatch::Dynamic_Proxy_Function>
(std::bind(chaiscript::eval::detail::eval_function,
std::ref(t_ss), guardnode,
t_param_names, std::placeholders::_1, std::map<std::string, Boxed_Value>()), static_cast<int>(numparams), guardnode);
guard = dispatch::make_dynamic_proxy_function(
[engine, t_param_names, guardnode](const std::vector<Boxed_Value> &t_params) {
return chaiscript::eval::detail::eval_function(engine, guardnode, t_param_names, t_params);
},
static_cast<int>(numparams), guardnode);
}
try {
const std::string & l_annotation = annotation?annotation->text:"";
const std::string & function_name = children[static_cast<size_t>(1 + class_offset)]->text;
auto node = children.back();
if (function_name == class_name) {
param_types.push_front(class_name, Type_Info());
t_ss.add(std::make_shared<dispatch::detail::Dynamic_Object_Constructor>(class_name, std::make_shared<dispatch::Dynamic_Proxy_Function>(std::bind(chaiscript::eval::detail::eval_function,
std::ref(t_ss), children.back(), t_param_names, std::placeholders::_1, std::map<std::string, Boxed_Value>()),
static_cast<int>(numparams), children.back(), param_types, l_annotation, guard)),
t_ss->add(
std::make_shared<dispatch::detail::Dynamic_Object_Constructor>(class_name,
dispatch::make_dynamic_proxy_function(
[engine, t_param_names, node](const std::vector<Boxed_Value> &t_params) {
return chaiscript::eval::detail::eval_function(engine, node, t_param_names, t_params);
},
static_cast<int>(numparams), node, param_types, l_annotation, guard
)
),
function_name);
} else {
// if the type is unknown, then this generates a function that looks up the type
// at runtime. Defining the type first before this is called is better
auto type = t_ss.get_type(class_name, false);
auto type = t_ss->get_type(class_name, false);
param_types.push_front(class_name, type);
t_ss.add(
std::make_shared<dispatch::detail::Dynamic_Object_Function>(class_name,
std::make_shared<dispatch::Dynamic_Proxy_Function>(std::bind(chaiscript::eval::detail::eval_function,
std::ref(t_ss), children.back(),
t_param_names, std::placeholders::_1, std::map<std::string, Boxed_Value>()), static_cast<int>(numparams), children.back(),
param_types, l_annotation, guard), type), function_name);
t_ss->add(std::make_shared<dispatch::detail::Dynamic_Object_Function>(class_name,
dispatch::make_dynamic_proxy_function(
[engine, t_param_names, node](const std::vector<Boxed_Value> &t_params) {
return chaiscript::eval::detail::eval_function(engine, node, t_param_names, t_params);
},
static_cast<int>(numparams), node, param_types, l_annotation, guard), type),
function_name);
}
}
catch (const exception::reserved_word_error &e) {
@@ -1465,23 +1447,22 @@ namespace chaiscript
Attr_Decl_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_NodePtr> t_children) :
AST_Node(std::move(t_ast_node_text), AST_Node_Type::Attr_Decl, std::move(t_loc), std::move(t_children)) { }
virtual ~Attr_Decl_AST_Node() {}
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE
{
const auto &d = t_ss.get_parent_locals();
const auto &d = t_ss->get_parent_locals();
const auto itr = d.find("_current_class_name");
const auto class_offset = (itr != d.end())?-1:0;
std::string class_name = (itr != d.end())?std::string(boxed_cast<std::string>(itr->second)):this->children[0]->text;
try {
t_ss.add(
std::string attr_name = this->children[static_cast<size_t>(1 + class_offset)]->text;
t_ss->add(
std::make_shared<dispatch::detail::Dynamic_Object_Function>(
std::move(class_name),
fun(std::function<Boxed_Value (dispatch::Dynamic_Object &)>(
std::bind(static_cast<Boxed_Value &(dispatch::Dynamic_Object::*)(const std::string &)>(&dispatch::Dynamic_Object::get_attr),
std::placeholders::_1,
this->children[static_cast<size_t>(1 + class_offset)]->text
))
),
fun([attr_name](dispatch::Dynamic_Object &t_obj) {
return t_obj.get_attr(attr_name);
}),
true
), this->children[static_cast<size_t>(1 + class_offset)]->text);
@@ -1505,7 +1486,7 @@ namespace chaiscript
{ assert(children.size() == 3); }
virtual ~Logical_And_AST_Node() {}
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE{
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE{
return const_var(get_bool_condition(children[0]->eval(t_ss))
&& get_bool_condition(children[2]->eval(t_ss)));
}
@@ -1522,7 +1503,7 @@ namespace chaiscript
AST_Node(std::move(t_ast_node_text), AST_Node_Type::Logical_Or, std::move(t_loc), std::move(t_children))
{ assert(children.size() == 3); }
virtual ~Logical_Or_AST_Node() {}
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE{
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE{
return const_var(get_bool_condition(children[0]->eval(t_ss))
|| get_bool_condition(children[2]->eval(t_ss)));
}

File diff suppressed because it is too large Load Diff

View File

@@ -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;

View File

@@ -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.

View File

@@ -0,0 +1,647 @@
// 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>
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;
}
}
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* = 0 ) : Internal( b ), Type( Class::Boolean ){}
template <typename T>
JSON( T i, typename enable_if<is_integral<T>::value && !is_same<T,bool>::value>::type* = 0 ) : Internal( long(i) ), Type( Class::Integral ){}
template <typename T>
JSON( T f, typename enable_if<is_floating_point<T>::value>::type* = 0 ) : Internal( double(f) ), Type( Class::Floating ){}
template <typename T>
JSON( T s, typename enable_if<is_convertible<T,string>::value>::type* = 0 ) : 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;
};
JSON Array() {
return JSON::Make( JSON::Class::Array );
}
template <typename... T>
JSON Array( T... args ) {
JSON arr = JSON::Make( JSON::Class::Array );
arr.append( args... );
return arr;
}
JSON Object() {
return JSON::Make( JSON::Class::Object );
}
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 = 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 + "'");
}
}
JSON JSON::Load( const string &str ) {
size_t offset = 0;
return parse_next( str, offset );
}
} // End Namespace json
#endif

View 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

View File

@@ -1,7 +1,11 @@
Master Status: [![Build Status](https://travis-ci.org/ChaiScript/ChaiScript.png?branch=master)](https://travis-ci.org/ChaiScript/ChaiScript) [![Coverage Status](https://coveralls.io/repos/ChaiScript/ChaiScript/badge.png?branch=master)](https://coveralls.io/r/ChaiScript/ChaiScript?branch=master)
Master Status: [![Linux Build Status](https://travis-ci.org/ChaiScript/ChaiScript.png?branch=master)](https://travis-ci.org/ChaiScript/ChaiScript) [![Windows Build status](https://ci.appveyor.com/api/projects/status/6u3r4s81kkjqmsqw?svg=true)](https://ci.appveyor.com/project/lefticus/chaiscript) [![codecov.io](http://codecov.io/github/ChaiScript/ChaiScript/coverage.svg?branch=master)](http://codecov.io/github/ChaiScript/ChaiScript?branch=master)
Develop Status: [![Build Status](https://travis-ci.org/ChaiScript/ChaiScript.png?branch=develop)](https://travis-ci.org/ChaiScript/ChaiScript) [![Coverage Status](https://coveralls.io/repos/ChaiScript/ChaiScript/badge.png?branch=develop)](https://coveralls.io/r/ChaiScript/ChaiScript?branch=develop)
Develop Status: [![Linux Build Status](https://travis-ci.org/ChaiScript/ChaiScript.png?branch=develop)](https://travis-ci.org/ChaiScript/ChaiScript) [![Windows Build status](https://ci.appveyor.com/api/projects/status/6u3r4s81kkjqmsqw/branch/develop?svg=true)](https://ci.appveyor.com/project/lefticus/chaiscript/branch/develop) [![codecov.io](http://codecov.io/github/ChaiScript/ChaiScript/coverage.svg?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

View File

@@ -1,6 +1,33 @@
Notes:
=======
Current Version: 5.7.0
Current Version: 5.7.1
### 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

View File

@@ -0,0 +1,32 @@
#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( ) );
static const char script[ ] =
R""(
class Rectangle
{
def Rectangle() { }
}
var rect = Rectangle( );
)"";
try
{
ch.eval( script );
}
catch ( std::exception e )
{
printf( " >>> Exception thrown: %s \n" , e.what( ) );
}
return 1;
}

View File

@@ -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 ) {
@@ -352,12 +360,23 @@ int main(int argc, char *argv[])
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;

View File

@@ -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__

View File

@@ -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();
@@ -171,6 +177,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

View 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)

View File

@@ -37,8 +37,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");
@@ -723,3 +722,83 @@ 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)");
}

View 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})

Binary file not shown.

View File

@@ -0,0 +1,6 @@
assert_equal("\x39", "9")
assert_equal("\x039", "9")
assert_equal("\x39g", "9g")
assert_equal("b\x39g", "b9g")

View File

@@ -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
View File

@@ -0,0 +1,3 @@
assert_true(from_json("null").is_var_null())

1
unittests/json_10.chai Normal file
View 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
View 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" ]);

1
unittests/json_12.chai Normal file
View File

@@ -0,0 +1 @@
assert_equal(from_json("\"\""), "")

1
unittests/json_13.chai Normal file
View File

@@ -0,0 +1 @@
assert_equal(from_json("1.20E+2"), 1.20e2)

3
unittests/json_2.chai Normal file
View File

@@ -0,0 +1,3 @@
assert_true(from_json("true"))

1
unittests/json_3.chai Normal file
View File

@@ -0,0 +1 @@
assert_equal(from_json("100"), 100)

1
unittests/json_4.chai Normal file
View File

@@ -0,0 +1 @@
assert_equal(from_json("1.234"), 1.234)

1
unittests/json_5.chai Normal file
View File

@@ -0,0 +1 @@
assert_equal(from_json("\"StringTest\""), "StringTest")

1
unittests/json_6.chai Normal file
View File

@@ -0,0 +1 @@
assert_equal(from_json("{}"), Map())

4
unittests/json_7.chai Normal file
View File

@@ -0,0 +1,4 @@
assert_equal(from_json("\n" +
"{\n" +
" \"Key\" : \"Value\"\n" +
"}\n"), ["Key":"Value"])

1
unittests/json_8.chai Normal file
View File

@@ -0,0 +1 @@
assert_equal(from_json("[]"), [])

2
unittests/json_9.chai Normal file
View File

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

View File

@@ -0,0 +1,6 @@
var m = ["a" : 1, "b" : [ 1, 2, 3 ], "c" : [1, "a string", ["d" : 15.4]]]
assert_equal(from_json(to_json(m)), m)

View File

@@ -6,3 +6,9 @@ x.push_back("A")
assert_equal(3, x.front());
assert_equal("A", x.back());
// push_back newly constructed return value that's non-copyable
x.push_back(async(fun(){}))

View File

@@ -6,3 +6,8 @@ x.push_front("A")
assert_equal("A", x.front());
assert_equal(3, x.back());
// push_back newly constructed return value that's non-copyable
x.push_front(async(fun(){}))

View File

@@ -1,2 +1,19 @@
auto x = ["bob":2, "fred":3]
assert_equal(3, x["fred"])
try {
auto m = ["bob":2, "fred":3];
m.at("tom");
assert_true(false);
} catch (out_of_range e) {
print("out_of_range")
assert_true(true);
} catch (e) {
print("other")
dump_object(e);
assert_true(false);
}
assert_equal(["bob":2, "fred":3].at("fred"), 3);

View File

@@ -0,0 +1,8 @@
load_module("test_module")
var t2 = TestBaseType();
var s = "5";
t2.set_string_val(s);
assert_equal(s, "42")

View File

@@ -2,8 +2,8 @@ assert_equal(true, int_type.bare_equal(1.get_type_info()))
assert_equal(true, unsigned_int_type.bare_equal(1u.get_type_info()))
assert_equal(true, unsigned_long_type.bare_equal(1lu.get_type_info()))
assert_equal(true, long_type.bare_equal(1l.get_type_info()))
assert_equal(true, int64_t_type.bare_equal(1ll.get_type_info()))
assert_equal(true, uint64_t_type.bare_equal(1ull.get_type_info()))
assert_equal(true, long_long_type.bare_equal(1ll.get_type_info()))
assert_equal(true, unsigned_long_long_type.bare_equal(1ull.get_type_info()))
assert_equal(true, double_type.bare_equal(1.6.get_type_info()))
assert_equal(true, float_type.bare_equal(1.6f.get_type_info()))

View File

@@ -0,0 +1,6 @@
assert_equal("\71", "9")
assert_equal("\071", "9")
assert_equal("\71a", "9a")
assert_equal("b\71a", "b9a")

View File

@@ -0,0 +1,7 @@
def string::`/=`(double d) { this = "${this}/=${d}"; return this; }
var s = "Hello World"
s /= 2

View File

@@ -0,0 +1,6 @@
def string::`*`(double d) { return "${this} * ${d}"; }
"Hello World" * 2

View File

@@ -0,0 +1,4 @@
assert_true(2>-1);
assert_false(3<-2);
assert_true(-1==-1);

View File

@@ -0,0 +1,7 @@
var s = ""
s += to_string(fun[s](){ s += "3"; 3}() % fun[s](){ s += "2"; 2}());
assert_equal(s, "321");

View File

@@ -0,0 +1,10 @@
auto p = parse("5 + 4");
try {
assert_equal(eval(p), 9)
} catch (e) {
print(e.pretty_print());
assert_true(false);
}

View File

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

View File

@@ -5,33 +5,58 @@
#include <iostream>
#include <cstdlib>
void test_type(const chaiscript::Type_Info &ti, bool t_is_const, bool t_is_pointer, bool t_is_reference, bool t_is_void,
bool t_is_undef)
#ifdef CHAISCRIPT_MSVC
#pragma warning(push)
#pragma warning(disable : 4190 4640 28251 4702 6330)
#endif
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wshadow"
#pragma GCC diagnostic ignored "-Wold-style-cast"
#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
#define CATCH_CONFIG_MAIN
#include "catch.hpp"
TEST_CASE("Type_Info objects generate expected results")
{
if (ti.is_const() == t_is_const
&& ti.is_pointer() == t_is_pointer
&& ti.is_reference() == t_is_reference
&& ti.is_void() == t_is_void
&& ti.is_undef() == t_is_undef)
const auto test_type = [](const chaiscript::Type_Info &ti, bool t_is_const, bool t_is_pointer, bool t_is_reference, bool t_is_void,
bool t_is_undef, bool t_is_arithmetic)
{
return;
} else {
exit(EXIT_FAILURE);
}
}
CHECK(ti.is_const() == t_is_const);
CHECK(ti.is_pointer() == t_is_pointer);
CHECK(ti.is_reference() == t_is_reference);
CHECK(ti.is_void() == t_is_void);
CHECK(ti.is_undef() == t_is_undef);
CHECK(ti.is_arithmetic() == t_is_arithmetic);
};
int main()
{
test_type(chaiscript::user_type<void>(), false, false, false, true, false);
test_type(chaiscript::user_type<const int>(), true, false, false, false, false);
test_type(chaiscript::user_type<const int &>(), true, false, true, false, false);
test_type(chaiscript::user_type<int>(), false, false, false, false, false);
test_type(chaiscript::user_type<int *>(), false, true, false, false, false);
test_type(chaiscript::user_type<const int *>(), true, true, false, false, false);
test_type(chaiscript::Type_Info(), false, false, false, false, true);
SECTION("void") { test_type(chaiscript::user_type<void>(), false, false, false, true, false, false); }
SECTION("const int") { test_type(chaiscript::user_type<const int>(), true, false, false, false, false, true); }
SECTION("const int &") { test_type(chaiscript::user_type<const int &>(), true, false, true, false, false, true); }
SECTION("int") { test_type(chaiscript::user_type<int>(), false, false, false, false, false, true); }
SECTION("int *") { test_type(chaiscript::user_type<int *>(), false, true, false, false, false, false); }
SECTION("const int *") { test_type(chaiscript::user_type<const int *>(), true, true, false, false, false, false); }
SECTION("const bool &") { test_type(chaiscript::user_type<const bool &>(), true, false, true, false, false, false); }
SECTION("default") { test_type(chaiscript::Type_Info(), false, false, false, false, true, false); }
std::cout << "Size of Type_Info " << sizeof(chaiscript::Type_Info) << '\n';
return EXIT_SUCCESS;
}

View File

@@ -0,0 +1,18 @@
var v = []
v.push_back(3.4);
v.push_back(1);
v.push_back("bob");
assert_true(v[0] == 3.4)
assert_true(v[1] == 1)
assert_true(v[2] == "bob")
v[0] = 2.9
v[1] = 3
v[2] = "tom"
assert_true(v[0] == 2.9)
assert_true(v[1] == 3)
assert_true(v[2] == "tom")

View File

@@ -0,0 +1,5 @@
var v = []
v.push_back(int(1));
v[0] = 3;

View File

@@ -3,3 +3,18 @@ x.push_back(3)
assert_equal(3, x.size())
assert_equal(3, x.back())
assert_equal(1, x.front())
load_module("stl_extra")
auto uint16v = u16vector();
uint16v.push_back(1u);
assert_equal(1, uint16v.front());
// push_back newly constructed return value that's non-copyable
var v = []
v.push_back(async(fun(){}))