Compare commits

...

834 Commits

Author SHA1 Message Date
Jason Turner
0f9d9cae4a Merge pull request #332 from ftk/develop
Ability to disable module loading support at compile time
2017-03-21 12:55:30 -07:00
Jason Turner
468d65a661 Merge pull request #336 from totalgee/from_json_fix
Handle negative numbers in JSONParse::parse_number
2017-03-21 12:21:26 -07:00
Jason Turner
9847618cf3 Fix use after move during parsing
closes #337
2017-03-21 12:17:30 -07:00
Jason Turner
a281d9571e Add workaround for chaiscript used as static
closes #338
2017-03-21 11:58:33 -07:00
Jason Turner
204faa82c1 Add failing static chaiscript test 2017-03-21 11:58:21 -07:00
Jason Turner
be2fec02d9 Simplify usage of Thread_Specific object 2017-03-21 10:44:53 -07:00
Glen Fraser
491b95099d In JSONParser::parse_number(), only allow a single '-' at start
- also, don't allow multiple '.' decimal points. Add unit tests to
  cover these cases.
2017-03-14 13:01:09 +01:00
Glen Fraser
561c5bc981 Handle negative numbers in JSONParse::parse_number
- fix issue #334, where negative numbers loaded from JSON were being
  parsed as 0.
- add unit tests to cover these cases.
2017-03-14 12:01:51 +01:00
ftk
12829ee5d2 Simplified travis.yml 2017-03-11 15:42:24 +03:00
ftk
f53a1ed951 Fix compilation of multithreaded_test 2017-03-11 15:09:55 +03:00
ftk
12100cce99 Updated travis.yml 2017-03-11 15:09:54 +03:00
ftk
d22c27b627 Added option to disable dynload in cmakelists.txt 2017-03-08 12:31:30 +03:00
ftk
60c43233c6 More clear error message in load_module 2017-03-05 21:55:01 +03:00
ftk
c2f7ca3aa2 Using runtime stdlib constructor will result in compilation error 2017-03-05 21:48:59 +03:00
ftk
72cb9bd940 Compile out module path search code when module support is disabled 2017-03-05 21:26:01 +03:00
ftk
84f9c44ab6 Do not register load_module by default when dynamic loading is disabled 2017-03-05 21:23:05 +03:00
ftk
698dfb06db Loadable module support can be disabled by defining CHAISCRIPT_NO_DYNLOAD 2017-03-05 20:54:01 +03:00
Jason Turner
244b5b224b Merge pull request #330 from IonoclastBrigham/patch-1
Fixes path reference and code formatting in readme.
2017-03-03 09:55:27 -08:00
Ionoclast Laboratories
534897d835 Fixes path reference and code formatting in readme.
Changes Example.cpp's directory "src" => "samples" to match repo.
Change code example from indented quote to highlighted code block.
2017-03-02 11:27:10 -08:00
Jason Turner
fac5a39066 Update readme.md for 6.0.0 2017-02-23 17:54:59 -07:00
Jason Turner
064a385a64 Merge branch 'develop' of github.com:ChaiScript/ChaiScript into develop 2017-02-22 15:56:04 -07:00
Jason Turner
e342243193 Update release notes for 6.0.0 2017-02-22 15:33:42 -07:00
Jason Turner
283785faaf Add PVS Studio and address some issues it found 2017-02-22 15:18:56 -07:00
Jason Turner
c0c0bd3172 Address warning from MSVC /analyze 2017-02-22 14:04:56 -07:00
Jason Turner
40fb8d257e Fix warnings from MSVC 2017-02-22 13:55:02 -07:00
Jason Turner
f5f6ddf219 Disable tests on MSVC for broken literal handling 2017-02-20 13:28:31 -07:00
Jason Turner
87f1242ed4 Update copyrights to 2017 2017-02-15 15:55:40 -07:00
Jason Turner
faba0f1317 Require thread_local support, move to xcode8 2017-02-15 15:38:44 -07:00
Jason Turner
077c93ab27 Fix/enhance unique_ptr support 2017-02-04 09:14:07 -08:00
Jason Turner
914bca6295 Merge pull request #324 from Dalzhim/uniquePtrTests
Add test to call base class methods through std::unique_ptr<derived>.
2017-02-04 09:18:39 -07:00
Gabriel Aubut-Lussier
2549b4e983 Add test to call base class methods through std::unique_ptr<derived>. 2017-02-03 23:19:25 -05:00
Jason Turner
1cb15d8b22 Handle return of std::unique_ptr objects 2017-02-03 19:34:12 -08:00
Jason Turner
2ce155237d Add test for unique_ptr returned from function 2017-02-03 18:55:58 -08:00
Jason Turner
dca3ce4ea6 Enhance testing of integer literals
* enable the ability to check a boxed_number conversion
 * fix integer_literal_test to pass on MacOS
2017-02-02 15:07:37 -07:00
Jason Turner
ca7d4ab734 Add test for calling method of unique_ptr var 2017-02-02 13:17:59 -08:00
Jason Turner
f5ced799cf Hopefully find balance with gcc/clang for static_string 2017-02-02 08:10:47 -08:00
Jason Turner
1499061f86 Add check for negate conversion to bool
Check for #321
2017-02-02 08:06:41 -08:00
Jason Turner
24352c62e8 Some clang specific fixes / warnings 2017-02-02 08:00:57 -08:00
Jason Turner
6b4c47c5ba Merge branch 'develop' of github.com:ChaiScript/ChaiScript into develop 2017-02-01 20:03:17 -08:00
Jason Turner
396d43a13f sublime now at ChaiScript/sublimetext-chaiscript 2017-02-01 20:01:30 -08:00
Jason Turner
18cf09b512 Merge pull request #319 from Tw1ddle/patch-1
Add double stringize trick so _MSC_FULL_VER macro gets expanded
2017-02-01 20:12:04 -07:00
Jason Turner
2782cdd33b Remove 2-value bind in favor of lambdas
closes #320
2017-02-01 15:42:32 -08:00
Jason Turner
d8d7bc79b7 Enhance number parsing tests 2017-02-01 09:07:40 -08:00
Jason Turner
3e04210027 Add more integer literal tests / fix neg test
Addresses #322
2017-02-01 07:02:18 -08:00
Jason Turner
c82c9ccb6e Revert "Fix parsing of negative numbers"
This reverts commit 83b7973cb885af928e36195a7cbc6ab8f04a93b6.
2017-02-01 06:18:14 -08:00
Jason Turner
efd37a7071 Add some more integer literal tests 2017-01-31 17:05:53 -08:00
Jason Turner
83b7973cb8 Fix parsing of negative numbers 2017-01-31 15:41:21 -08:00
Jason Turner
e7a6b2306c Add tests for parsing of neg numbers 2017-01-31 15:30:38 -08:00
Jason Turner
0a18f0a809 Remove unnecessary params 2017-01-31 13:40:16 -08:00
Jason Turner
8efba903c3 use std::end instead of end because of MSVC 2017-01-31 13:28:40 -08:00
Jason Turner
ca87c05cd4 Don't add 'this' if it was explicitly captured 2017-01-31 13:25:26 -08:00
Jason Turner
94fb7c2453 Add test for explicitly capturing "this" 2017-01-31 13:24:53 -08:00
Jason Turner
c54d84fae6 Don't force compiler when building cppcheck 2017-01-31 10:11:28 -08:00
Sam Twidale
574f4a9664 Add double stringize trick so _MSC_FULL_VER macro gets expanded
This fixes CHAISCRIPT_COMPILER_VERSION, so it gets the compiler version number instead of the string "_MSC_FULL_VER".

This means, for example, build ids read like msvc-190023918-Debug, not msvc-_MSC_FULL_VER-Debug.
2017-01-09 18:38:19 +00:00
Jason Turner
b7e8897a43 Merge pull request #317 from ChaiScript/add_osx_travis
Add osx travis
2016-12-29 12:32:19 -07:00
Jason Turner
7a588ed5cf Disable cppcheck runs 2016-12-27 17:56:10 -07:00
Jason Turner
89f373d21c Clean up ENV and addons 2016-12-27 16:10:08 -07:00
Jason Turner
037335a0ea Don't require sudu on linux for travis.yml 2016-12-27 16:02:55 -07:00
Jason Turner
2431362e54 Simplify OS types for travis 2016-12-27 15:50:53 -07:00
Jason Turner
9c59600b9f Add OSX to OS matrix 2016-12-27 15:23:58 -07:00
Jason Turner
51663df1ba Demonstrate workaround for pointer to ref member
closes #302
2016-12-06 14:51:00 -07:00
Jason Turner
624c7c435b Add unit test for #302 2016-12-06 14:26:10 -07:00
Jason Turner
cf89bdd804 Update release notes, add chai type fun conversion test 2016-12-06 14:15:39 -07:00
Jason Turner
a8e70a4cfe Merge branch 'develop' of github.com:ChaiScript/ChaiScript into develop 2016-12-06 13:43:53 -07:00
Jason Turner
f79de06e0b Change comment format 2016-12-06 13:42:58 -07:00
Jason Turner
cee57f998a Allow conversions while calling chaiscript funcs
* This puts ChaiScript funcs more on even footings with
   C++ defined funcs
 * Minor performance hit (0.5%)
2016-12-06 13:05:17 -07:00
Jason Turner
ce62706fea Clean up warnings
* msvc
 * pvs-studio
2016-12-06 10:31:36 -07:00
Jason Turner
92c2ade1cd More relase note updates 2016-12-05 12:13:19 -07:00
Jason Turner
6b7481e6a1 Merge branch 'develop' of github.com:ChaiScript/ChaiScript into develop 2016-12-05 12:11:51 -07:00
Jason Turner
d096f926d3 Update release notes 2016-12-05 12:11:32 -07:00
Jason Turner
fb7f8f194c Add support for r-value parameters and unique_ptr
Notes
 * Due to the limitations for how Boxed_Value is handled
   the unique_ptrs must still be wrapped in a shared_ptr
 * However, this caveat does not directly affect the user
2016-12-05 12:07:56 -07:00
Jason Turner
78f885ec61 Merge pull request #310 from M2tM/patch-1
nullify_shared_ptr changing == to = in documentation.
2016-12-03 14:01:01 -07:00
Jason Turner
d6d50478de Make constexpr members const 2016-12-03 07:59:06 -07:00
Jason Turner
defdb53a55 Fix regression from last commit on single char operators 2016-12-02 23:26:54 -07:00
Jason Turner
0dea62dd54 Finish removing runtime string comparisons
* Now virtually all parser string work is done at compile time
 * Continuing the work started by @niXman
2016-12-02 23:01:57 -07:00
Jason Turner
590905f4b3 Add notes on base_class conversions 2016-12-02 20:32:47 -07:00
Michael Hamilton
9218dda001 nullify_shared_ptr changing == to = in documentation. 2016-12-01 22:24:47 -08:00
Jason Turner
9e17514b57 Move away from class level statics
- Avoiding potential issues with linking and multiple symbol definitions
2016-12-01 15:20:48 -07:00
Jason Turner
5f402e71dd Move away from macro, get slight perf boost with hand rolled compare 2016-12-01 14:47:23 -07:00
Jason Turner
95e119fffe Merge github.com:niXman/ChaiScript into develop 2016-12-01 14:03:56 -07:00
Jason Turner
f17439a9d3 Add scope around condition in for/while
* solves issue with rapidly expanding memory usage if
   function variable use stack is growing rapidly
2016-12-01 13:42:40 -07:00
Jason Turner
940e0c2d86 Merge pull request #306 from StanEpp/develop
Added add_class overload for scoped enums.
2016-12-01 10:10:49 -07:00
Jason Turner
e8c03b33c6 Merge pull request #307 from sjaustirni/develop
Fixed a bug in the first example in the docs
2016-11-29 11:25:25 -07:00
sjaustirni
b68f917677 Fixed a bug in the first example
This example has been forgotten to be updated, despite other being up to date.
2016-11-26 15:43:28 +01:00
Stan
7f4af72244 Added add_class overload for scoped enums. 2016-11-23 20:39:21 +01:00
Jason Turner
6757b66f95 Merge pull request #305 from mlamby/patch-2
Add break statement to cheatsheet.md
2016-11-20 18:05:37 -07:00
Michael Lamb
c9034a0485 Add break statement to cheatsheet.md
Added information about the existence of the break statement to the loop section.
2016-11-21 11:57:52 +11:00
Jason Turner
50dcbc8c7e Simplify Symbol parsing.
closes #301
2016-11-13 15:14:41 -07:00
niXman
1ea91faf52 parser optimization Three 2016-11-08 01:11:46 +02:00
niXman
745e0c0f0b parser optimization step Two 2016-11-04 09:15:02 +02:00
niXman
c42477f2eb parser optimization step One 2016-11-03 22:47:48 +02:00
Jason Turner
335a02f165 Add release notes on if-init expressions 2016-11-01 13:04:49 -06:00
Jason Turner
012f1ffff5 Remove incorrect override 2016-10-30 21:51:00 -06:00
Jason Turner
9925b20fad Cleanups found with PMD's CPD 2016-10-29 09:41:55 -06:00
Jason Turner
28122f7cb0 Fix single parameter constructors found by cppcheck 2016-10-28 15:49:40 -06:00
Jason Turner
b1f1803759 Some cleanups found by clang's analyzer 2016-10-28 14:53:01 -06:00
Jason Turner
359897a442 Flesh out parser and tracer usage cases 2016-10-28 13:36:10 -06:00
Jason Turner
ffcd7e3a76 Merge branch 'release-5.x' into develop 2016-10-28 11:04:15 -06:00
Jason Turner
2c99e6cd32 Update release notes 2016-10-28 11:03:31 -06:00
Jason Turner
332a62769b Merge branch 'release-5.x' into develop 2016-10-28 10:57:55 -06:00
Jason Turner
a38b254a98 Only allow class in top level scope
* Throw error if class is in unexpected place
 * Allow catching of `eval_error` from inside of script

closes #297
2016-10-28 10:56:12 -06:00
Jason Turner
77231461ca Add test for class inside of scope
Addresses #297
2016-10-28 09:01:40 -06:00
Jason Turner
eefd50a6bc Merge branch 'release-5.x' into develop 2016-10-26 14:05:28 -06:00
Jason Turner
0d4a99af82 Enable conversion to bool in conditionals
closes #295
2016-10-26 13:52:03 -06:00
Jason Turner
9f30d84f39 Add conversion to bool tests as conditionals 2016-10-26 12:29:30 -06:00
Jason Turner
8b18e301d2 Merge branch 'release-5.x' into develop 2016-10-26 12:24:40 -06:00
Jason Turner
508729ec77 Properly handle error reporting with method_missing 2016-10-26 10:08:53 -06:00
Jason Turner
0fe78f7ba5 Make sure to not break non-basic interface 2016-10-26 08:47:49 -06:00
Jason Turner
6202149b4f Merge pull request #294 from roig/fixCompilerErrors
Fix some GCC compiler errors.
2016-10-26 08:41:15 -06:00
Daniel Guzman
4ad661475b Fix some GCC compiler errors. 2016-10-22 16:49:53 +02:00
Jason Turner
6d309b7516 Merge branch 'develop' of github.com:ChaiScript/ChaiScript into develop 2016-10-17 20:55:47 -06:00
Jason Turner
7d9e1b3af7 Add ability to disable loading external files
* Options are passed to ChaiScript constructor
 * load_module / eval_file / use can be disabled
   from script context
2016-10-17 20:51:15 -06:00
Jason Turner
b99ccafa07 Fix some MSVC issues
* Add error if you are using too low of an MSVC compiler
 * Fix some warnings
2016-10-16 16:04:33 -06:00
Jason Turner
c97a69537d Add ability to get current script context
closes #277
2016-10-13 20:44:13 -06:00
Jason Turner
fac8f3ec90 Merge branch 'release-5.x' into develop 2016-10-10 20:09:40 -06:00
Jason Turner
ab07872857 Update to 5.8.6 2016-10-10 19:46:29 -06:00
Jason Turner
23c13e6570 Apply return optimization to lambdas
closes #289
2016-10-10 18:52:54 -06:00
Jason Turner
aa9267726f Merge branch 'develop' of github.com:ChaiScript/ChaiScript into develop 2016-10-09 20:03:39 -06:00
Jason Turner
396e78d295 Merge branch 'release-5.x' of github.com:ChaiScript/ChaiScript into develop 2016-10-09 20:03:22 -06:00
Jason Turner
7339ff2c2f Update release notes for 5.8.5 2016-10-09 19:59:48 -06:00
Jason Turner
1efcddd335 Update releasenotes.md 2016-10-08 07:38:49 -06:00
Jason Turner
21ccb1d1d0 Fix module loading 2016-10-07 21:54:40 -06:00
Jason Turner
c37c901a0c Fix MSVC build
closes #287
2016-10-07 21:39:19 -06:00
Jason Turner
690b96d9ee Change fuzzy tests to account for prefix & changes 2016-10-07 11:26:30 -06:00
Jason Turner
d638d87a0f Fix function reassignment 2016-10-07 09:36:38 -06:00
Jason Turner
b091439567 Merge branch 'release-5.x' into develop 2016-10-07 09:13:19 -06:00
Jason Turner
665125665a Bump to 5.8.5
- remove parsing of unary &, it was unused
2016-10-06 22:32:55 -06:00
Jason Turner
d1c7645a4e Backport inits for g++4.6 2016-10-06 15:19:47 -06:00
Jason Turner
58faea1cf2 Add conversion to bool compile test
Re: #275
2016-10-06 14:52:34 -06:00
Jason Turner
8b7fe33bf1 Fix order of operations for prefix and '*', '/'
The problem is that Prefix did not properly participate in
operator precedence. I've fixed this, at least for the moment,
by adding a final depth of precedence that can be called when
the depth gets to the bottom.

closes #285
2016-10-06 14:44:30 -06:00
Jason Turner
7cc100e3d7 Make ChaiScript constructor public... 2016-10-06 09:36:43 -06:00
Jason Turner
21495ebb40 Make sure atomics are initialized 2016-10-06 09:09:50 -06:00
Jason Turner
b2907fc608 Merge branch 'release-5.x' into develop 2016-10-05 15:14:58 -06:00
Jason Turner
bec1b91b7b Increment to 5.8.4 2016-09-24 17:17:40 -06:00
Jason Turner
4b81a24a0a Fix numeric mixed-convesion operations 2016-09-24 17:15:17 -06:00
Jason Turner
3b2c82ba2c Add 6.0.0 release notes 2016-09-16 14:20:11 -06:00
Jason Turner
8cb3bd4af8 Fix gcc 4.9 build 2016-09-16 12:47:01 -06:00
Jason Turner
26e6f51fa8 Add notes on bound member function 2016-09-16 12:39:42 -06:00
Jason Turner
87294fc89d Merge branch 'develop' of github.com:ChaiScript/ChaiScript into develop 2016-09-16 12:38:44 -06:00
Jason Turner
9cc0ce01b9 Merge pull request #265 from profiler-bg/patch-1
Update cheatsheet.md
2016-09-16 12:38:31 -06:00
Jason Turner
c9ee707972 Merge branch 'release-5.x' into develop 2016-09-16 12:33:58 -06:00
Jason Turner
cefb4d3c78 Update release notes for 5.x 2016-09-16 12:33:07 -06:00
Jason Turner
4e6e63ab5d Cleanups and split up into _basic options 2016-08-27 10:33:44 -06:00
Jason Turner
7561aa8828 Get all unit tests passing 2016-06-29 21:06:31 -06:00
Jason Turner
e44724c780 Fix debug/clang build issues 2016-06-29 17:27:07 -06:00
Jason Turner
b0f07cbe5d Merge branch 'develop' into cleanups_and_reworkds 2016-06-29 16:11:00 -06:00
Jason Turner
62639a4359 Get building with libc++ again 2016-06-29 16:06:27 -06:00
Jason Turner
176d608bb4 Merge pull request #276 from ELynx/develop
Add UTF-8 escape notation to parser
2016-06-29 15:03:40 -06:00
Jason Turner
a1d90c95f0 Create DesignGoals.md 2016-06-28 10:34:30 -06:00
Jason Turner
a14f1983e8 Handle a few more optimization cases 2016-06-27 12:56:43 -06:00
ELynx
5642e062e6 Fix unittest 2016-06-27 18:02:50 +03:00
Jason Turner
9e16cc2a79 Simplify and normalize if block code 2016-06-27 08:56:03 -06:00
ELynx
201fef49c6 More standard compliant, use converter only where available 2016-06-27 17:40:43 +03:00
ELynx
58ebb22c55 clean-up conversion for other than std:string 2016-06-27 16:03:32 +03:00
ELynx
830b7c93ca Fix unit test, limit unit test to UTF-8 2016-06-27 15:26:07 +03:00
ELynx
368a3b78a2 create holder class 2016-06-27 13:46:37 +03:00
ELynx
e3e90de02a Proper comparison in unit tests; remove leftover static keyword 2016-06-27 13:09:32 +03:00
ELynx
8478ddc470 Move details to detail namespace, make to standard 2016-06-27 12:45:38 +03:00
ELynx
2adefaf46d Basic unit tests 2016-06-27 12:39:03 +03:00
ELynx
bd26355516 No warnings from MSVC 2016-06-27 12:38:50 +03:00
ELynx
19a730b78b Basic support for Unicode 'slash'uABCD escape notation - parser understands escape sequence and following data 2016-06-27 11:52:22 +03:00
Jason Turner
e3d1741c63 Add C++17-style if-init blocks 2016-06-26 22:10:53 -06:00
Jason Turner
09bdec4882 Add ranged-for loops
closes [#145]
2016-06-26 20:00:01 -06:00
Jason Turner
c31ebb5665 Move checking of valid object names to parse time 2016-06-23 10:23:40 -06:00
Jason Turner
52a191df9e Add optimization for unused return values 2016-06-19 20:20:51 -06:00
Jason Turner
228c942b6c Use std::exchange 2016-06-07 12:26:30 -06:00
Jason Turner
09ed0ca573 Merge pull request #270 from rmpowell77/issue_269
Fix for: samples/example.cpp crashes #269
2016-05-14 15:00:21 -06:00
Richard Powell
ee68ff20ed Fix for: samples/example.cpp crashes #269
Add the system as global.
2016-05-14 09:40:22 -06:00
Jason Turner
b72eed3921 Update docs to reflect C++14 closes #268 2016-05-12 08:55:01 -06:00
Jason Turner
039d0edce3 Move to std::next instead of homebrewed function 2016-05-12 08:53:38 -06:00
Jason Turner
7b3f06b269 Even more scope / block simplification 2016-05-03 14:41:16 -06:00
Jason Turner
5373bbd52e Add Fold-Right optimizer 2016-05-03 10:21:59 -06:00
Jason Turner
17821be1e2 Reduce shared_ptr copies during dispatch 2016-05-03 08:51:44 -06:00
Jason Turner
9a526bc1ec Allow constant folding to do conversions also 2016-05-01 12:46:15 -06:00
Jason Turner
03803ee4c4 Initial take on Tracer hooks
This will allow the user to add hooks in for debugging / execution
tracing / throttling / etc for each node execution

The cost is *almost* 0 if no tracing is enabled.
2016-04-30 20:53:01 -06:00
Jason Turner
dcedd64032 Merge branch 'develop' into cleanups_and_reworkds 2016-04-29 10:40:38 -06:00
Jason Turner
d34d74205c Merge branch 'release-5.x' into develop 2016-04-29 10:40:26 -06:00
Jason Turner
41c1c490c8 Add support for *& return types 2016-04-29 08:31:59 -06:00
Jason Turner
70cdbef693 Fix threading build 2016-04-29 07:09:57 -06:00
Jason Turner
f6c69f2826 Allow folding of if blocks 2016-04-25 21:32:48 -06:00
Jason Turner
184ca7f7b2 Create Block reducing optimizer 2016-04-24 07:49:00 -06:00
Jason Turner
71caf5006f Pull constant folding optimizer out 2016-04-23 22:27:34 -06:00
Jason Turner
4dbf1ee2bd Pull out Return_Optimizer 2016-04-23 22:12:08 -06:00
Jason Turner
4324a700ad Fix instring eval parsing 2016-04-23 21:00:32 -06:00
Jason Turner
5b78d5a898 Make optimizer pluggable 2016-04-23 20:22:17 -06:00
Jason Turner
ff2ab6bb8d Make optimizer split out 2016-04-23 15:52:19 -06:00
Jason Turner
25575564c0 Make module load error much more explicit 2016-04-23 15:47:39 -06:00
Jason Turner
683164650a Add ability to 'compile' for loops 2016-04-21 08:09:10 -06:00
Jason Turner
647f8842fd Optimize dispatch for perfect match case 2016-04-20 09:20:38 -06:00
Jason Turner
6d6f79b1a4 Only pop min/max if they were defined previously 2016-04-18 14:38:25 -06:00
Jason Turner
06b2893bfb Update tests for removal of ChaiScript_Parser from stdlib 2016-04-17 21:15:59 -06:00
Jason Turner
7ab6bce7fa Untangle chaiscript_engine from the rest of it 2016-04-17 21:14:01 -06:00
Jason Turner
f9294c8cbe Remove ChaiScript_Parser from stdlib, unnecessary 2016-04-17 16:55:08 -06:00
Jason Turner
80cc18bf2f Make type_info fully constexpr
- Minor hit in compile size
 - Minor improvement in runtime
2016-04-17 08:15:24 -06:00
Jason Turner
c68488388e Remove some unused code in Boxed_Value 2016-04-16 22:14:02 -06:00
Jason Turner
7d5a97aa2f Clean up if block parsing and eval 2016-04-16 15:39:32 -06:00
Jason Turner
83c6df11f0 Fix global reference assignment 2016-04-16 14:30:12 -06:00
Jason Turner
10b984556d Add global & test 2016-04-16 14:23:11 -06:00
Jason Turner
cf2fa09d6c Eliminate branching in var decl 2016-04-16 14:13:14 -06:00
Jason Turner
f3f84594ee A few parser cleanups 2016-04-16 12:04:18 -06:00
Jason Turner
57aa874c6e Revert "Prefer make_unique over make_shared"
This reverts commit 5a947b5035dc99d2dbef35a220340036886e189c.
2016-04-16 09:02:38 -06:00
Jason Turner
32bd936a18 Remove 'annotation' feature 2016-04-16 07:52:39 -06:00
Jason Turner
498339c202 Remove some dead parser code 2016-04-16 07:35:30 -06:00
Jason Turner
56b4f465a1 Add warning on platforms without thread_local 2016-04-15 23:09:20 -06:00
Jason Turner
1a42614441 Remove unnecessary code 2016-04-15 23:02:42 -06:00
Jason Turner
6fa83bca85 Remove Do_Call helper class 2016-04-15 15:31:19 -06:00
Hristo Petrov
fd57bec676 Update cheatsheet.md
Added missing parameters to the examples of "Adding Method / Member"
2016-04-15 16:11:36 +01:00
Jason Turner
14307194e9 Merge pull request #264 from ELynx/develop
Expose std::vector and std::list resize, reserve and capacity methods
2016-04-15 08:18:13 -06:00
ELynx
62e34c097c Add capacity check; fix vector_reserve unittest 2016-04-15 14:12:07 +03:00
ELynx
cdb9dcc154 Fix list unittest 2016-04-15 14:08:03 +03:00
ELynx
14d429853b Add typename; pass value to resize by const referene 2016-04-15 14:00:01 +03:00
ELynx
e8ff1f9d7e Proper template types for resizable_type and reservable_type 2016-04-15 13:39:51 +03:00
ELynx
49ef5306a9 Add resize to stl list and vector; add reserve to stl vector 2016-04-15 13:15:30 +03:00
Jason Turner
7d9dbc3d86 Fix some boxed_cast issues introduced with refactor 2016-04-14 19:06:37 -06:00
Jason Turner
49dfdfd15a Fix some boxed_cast and exception issues 2016-04-14 12:03:55 -06:00
Jason Turner
720395e47a clean up reflection tests for new capabilities 2016-04-14 09:31:38 -06:00
Jason Turner
5e0a882b18 Bootstrap simplifications 2016-04-13 21:08:25 -06:00
Jason Turner
9603d3910a Get multifile compiling 2016-04-13 15:26:36 -06:00
Jason Turner
6f0d02f158 Massive simplification of boxed_cast. More planned 2016-04-13 14:09:08 -06:00
Jason Turner
8d808f75c0 Remove pretty_print functionality 2016-04-13 12:04:55 -06:00
Jason Turner
2a1632f213 Merge branch 'develop' into cleanups_and_reworkds 2016-04-11 17:48:31 -06:00
Jason Turner
e57f11fcf4 Merge pull request #262 from rollbear/develop
Pass Module by reference instead of shared ptr
2016-04-11 16:58:27 -06:00
Bjorn Fahller
2fe794fcae Do not return Module& from internal funcs on Module&
A slight improvement in built binary size is achieved by not having
to generate code for the return.
2016-04-11 18:16:30 +02:00
Jason Turner
b594043eef Clean up redundant code 2016-04-11 09:36:23 -06:00
Jason Turner
fe8f8a89a7 Implement constant expression folding 2016-04-11 08:19:02 -06:00
Jason Turner
40694c798c Eliminate Str_AST_Node 2016-04-10 23:12:35 -06:00
Jason Turner
443828fa23 More parser simplification 2016-04-10 22:27:35 -06:00
Jason Turner
866db4ee8b Reduce instances of Str_AST_Node 2016-04-10 21:38:44 -06:00
Jason Turner
5e97f459d8 Remove unnecessary false 2016-04-10 19:01:55 -06:00
Jason Turner
e02ac78195 Remove Char_AST_Node 2016-04-10 18:57:23 -06:00
Jason Turner
62cd8031ac Make quoted strings into Constants 2016-04-10 18:29:16 -06:00
Jason Turner
61dfcb00c0 Move int/float into Constant 2016-04-10 17:19:48 -06:00
Jason Turner
4bf619c80f some initialization and destructor cleanups 2016-04-09 22:10:06 -06:00
Jason Turner
08a68f310a Move to strongly typed algebraic enum 2016-04-09 21:50:23 -06:00
Jason Turner
641ac1a1ae Split up ifdef'd module code 2016-04-09 21:49:12 -06:00
Jason Turner
2400c64c82 Move to strongly typed enums for node types 2016-04-09 21:15:07 -06:00
Jason Turner
1e584048ce Remove std::function from bind_first 2016-04-09 21:00:07 -06:00
Bjorn Fahller
7865f8e7f2 Keep ModulePtr kompatible functions
Since use of (one of) the functions in bootstrap_stl.hpp is in a
sample, chances are there are people using them in real world
application code. Thus the backwards compatible versions.
2016-04-09 21:09:45 +02:00
Bjorn Fahller
5ff97979fd Pass Module by reference instead of shared ptr
This gives a small but noticeable compile time improvement as
well as a measurable, albeit not great, reduction in size of the
stdlib.
2016-04-09 15:42:55 +02:00
Jason Turner
5567e767a3 Change some {{ code 2016-04-04 15:57:14 -06:00
Jason Turner
5a947b5035 Prefer make_unique over make_shared 2016-04-04 15:36:38 -06:00
Jason Turner
6ecbaab2fe Merge branch 'develop' of github.com:ChaiScript/ChaiScript into develop 2016-03-30 13:02:07 -06:00
Jason Turner
dd6b38cafb Merge branch 'release-5.x' into develop 2016-03-30 13:01:46 -06:00
Jason Turner
1e62eb4e12 Update to 5.8.2 release notes 2016-03-30 12:52:53 -06:00
Jason Turner
6e6795e914 Merge pull request #260 from ELynx/develop
Fix description of get_guard()
2016-03-30 12:08:14 -06:00
Eduard
33c966b8d6 Fix description of get_guard() 2016-03-30 18:14:12 +03:00
Jason Turner
c07c2a9cc2 Make sure type_info works with shared_ptr & 2016-03-28 15:57:26 -06:00
Jason Turner
46c45e8fc7 Update boxed_cast_tests to account for new features 2016-03-27 20:50:15 -06:00
Jason Turner
91a3ae1f14 Add ability to take non-const & shared_ptr params 2016-03-27 20:02:27 -06:00
Jason Turner
328aef10d7 Add failing test for non-const shared_ptr & 2016-03-27 18:24:38 -06:00
Jason Turner
f7b52f6c39 Merge branch 'develop' of github.com:ChaiScript/ChaiScript into develop 2016-03-26 17:34:54 -06:00
Jason Turner
2f2f789f48 Fix parsing of '' strings. found by AFL 2016-03-26 17:34:36 -06:00
Jason Turner
06783b7f65 Add fuzzy testing notes 2016-03-25 07:04:39 -06:00
Jason Turner
a45c76721f Add fuzzy test files 2016-03-25 07:02:41 -06:00
Jason Turner
3627efe03b Move away from shared_lock
It's not supported by enough standard library implementations yet
2016-03-16 20:14:48 -06:00
Jason Turner
1cd7a1b972 Change unsigned to size_t 2016-03-16 19:59:56 -06:00
Jason Turner
df9466e2a7 Remove unneeded overloads / make explicit 2016-03-16 19:50:59 -06:00
Jason Turner
dc8aa372c1 Less manual managing of JSON internal state 2016-03-16 19:39:10 -06:00
Jason Turner
bcc25222dd Code reorg to reduce anon namespace 2016-03-16 19:08:50 -06:00
Jason Turner
6507a6e68e Update naming of JSON functions 2016-03-16 18:52:02 -06:00
Jason Turner
5872b020fa First pass at updating JSON lib
* eliminate manual memory management
2016-03-16 18:32:10 -06:00
Jason Turner
c57ea79d0d Update reference to prelude 2016-03-13 16:26:46 -06:00
Jason Turner
b424d1f9cb delimit chaiscript text blocks 2016-03-13 15:33:23 -06:00
Jason Turner
7dcd6b8447 Implement member pointer value support
closes #245
2016-03-12 22:04:01 -07:00
Jason Turner
de63529887 Add failing test for pointer based member data
Issue #245
2016-03-12 20:08:15 -07:00
Jason Turner
d95f59fa97 Add test for dynamic object assignments 2016-03-12 19:50:58 -07:00
Jason Turner
d5ae30191d Add =, ==, and != for Dynamic_Objects
closes #251
2016-03-12 12:44:05 -07:00
Jason Turner
16ffbca6d6 Simplify type_info comparisons 2016-03-12 08:36:53 -07:00
Jason Turner
afa3f2249c Mark i as unused for the sake of MSVC 0th case 2016-03-12 08:16:25 -07:00
Jason Turner
c5f4a4dfd8 various c++11/c++14 cleanups 2016-03-12 07:05:29 -07:00
Jason Turner
34a2001a7b Reduce lookups into stack indexes 2016-03-12 07:05:12 -07:00
Jason Turner
16c4a11990 More C++11/C++14 updates 2016-03-11 18:17:04 -07:00
Jason Turner
6f01568a9a Fix function_member call from last commit 2016-03-11 15:28:33 -07:00
Jason Turner
a363ef5e0e C++11/14 updates 2016-03-11 14:45:40 -07:00
Jason Turner
a3365a9c4a Enable use of shared_mutex now on C++14 2016-03-11 13:45:01 -07:00
Jason Turner
9a5ef38d4a Simplify exception_specification types
* move to variadic
 * delete lots of implementation details
2016-03-11 10:57:20 -07:00
Jason Turner
5247de7d1b use a global void value for returning unknown values 2016-03-11 10:21:39 -07:00
Jason Turner
cd1b3f8887 Virtual / override / public cleanups 2016-03-11 09:24:00 -07:00
Jason Turner
11ee71ba27 Fix index type 2016-03-10 14:45:07 -07:00
Jason Turner
91ba9e25c0 Remove g++ 4.8 from builds 2016-03-10 14:06:43 -07:00
Jason Turner
978f80751f Update proxy_functions_detail to c++14 2016-03-10 12:33:07 -07:00
Jason Turner
0ac5657661 Merge branch 'update_travis_toolchain' of github.com:ChaiScript/ChaiScript into update_travis_toolchain 2016-03-07 21:24:53 -07:00
Jason Turner
cfc8a3d214 Warning cleanups and simplification 2016-03-07 21:24:21 -07:00
Jason Turner
85163e08cc Add missing <array> header include 2016-03-07 16:19:40 -07:00
Jason Turner
019c6b2830 Cleanup of ChaiScript_Parser
From episode 1 of C++ Weekly.
2016-03-07 15:36:12 -07:00
Jason Turner
c71dd8051b Merge branch 'update_travis_toolchain' of github.com:ChaiScript/ChaiScript into update_travis_toolchain 2016-03-07 14:25:47 -07:00
Jason Turner
fe8f571f47 Add test_module to set of required modules during build 2016-03-07 07:16:57 -07:00
Jason Turner
947d7c2591 Merge branch 'develop' into update_travis_toolchain
Conflicts:
	.decent_ci-Windows.yaml
	CMakeLists.txt
	include/chaiscript/chaiscript_defines.hpp
2016-03-05 21:12:14 -07:00
Jason Turner
6f6227879a Merge branch 'release-5.x' into develop 2016-03-05 20:28:44 -07:00
Jason Turner
e014308154 Create supporters.md 2016-03-05 18:32:44 -07:00
Jason Turner
467392e17d Update readme.md 2016-03-05 18:26:15 -07:00
Jason Turner
cf5913f890 Add gitter appveyor webhook 2016-03-05 17:45:11 -07:00
Jason Turner
71c67bc763 Move debug over to windows build 2016-03-05 12:04:30 -07:00
Jason Turner
539ee3c84f Ignore unknown pragmas in older apple clang 2016-03-05 10:44:40 -07:00
Jason Turner
594958ea8b Address MSVC2013 specific warnings 2016-03-05 07:46:28 -07:00
Jason Turner
83b966df47 Address g++4.8 warnings 2016-03-05 07:45:33 -07:00
Jason Turner
c24004c70e Disable more warnings for catch/gcc 2016-03-04 22:09:26 -07:00
Jason Turner
a0ee8d1137 Address more catch/msvc warnings 2016-03-04 21:48:08 -07:00
Jason Turner
765e6ed8df Update release notes for 5.8.1 2016-03-04 18:26:14 -07:00
Jason Turner
0cb4c18638 Fix some more windows warnings 2016-03-04 18:22:21 -07:00
Jason Turner
ad7e2138d9 Various Windows fixes 2016-03-04 17:39:32 -07:00
Jason Turner
0eee23109e Upgrade catch to new version 2016-03-04 16:05:08 -07:00
Jason Turner
b663654a6d Add missing header for locale 2016-03-04 15:49:31 -07:00
Jason Turner
2a8c248167 Implement locale dependent float parser
closes #250
2016-03-04 15:18:12 -07:00
Jason Turner
457367ea7b Add failing tests for locale changes
re #250
2016-03-04 14:31:19 -07:00
Jason Turner
33e27b4f85 Reorganize builds run on decent_ci 2016-03-04 13:48:20 -07:00
Jason Turner
b5b6e5a5a3 Drop ifdef'd code for gcc4.6 and msvc12 2016-03-04 11:15:39 -07:00
Jason Turner
a0f3eafe30 Merge branch 'develop' into update_travis_toolchain 2016-03-04 10:33:54 -07:00
Jason Turner
8feff5bc76 Clean up some more warnings 2016-03-04 10:03:39 -07:00
Jason Turner
463f688978 Update to C++14 compiler flags 2016-03-04 09:48:35 -07:00
Jason Turner
70c6ed713b Add new compilers and remove deprecated ones 2016-03-04 09:24:50 -07:00
Jason Turner
a6dcbb1f1c Fix multithreaded test 2016-03-04 08:28:49 -07:00
Jason Turner
d4f02b5e67 Address sign promotion warnings, add todo test 2016-03-04 07:58:21 -07:00
Jason Turner
645377e191 Remove memory_order_relaxed usage 2016-03-02 20:36:05 -07:00
Jason Turner
5a03c88ee3 Add -Wconvert and address the warnings from it
closes #254
2016-03-02 17:40:15 -07:00
Jason Turner
abc30ba573 Create CONTRIBUTING.md 2016-02-23 14:08:22 -07:00
Jason Turner
f36b1fc5eb Rename PULL_REQUEST_TEMPLATE to PULL_REQUEST_TEMPLATE.md 2016-02-23 13:39:07 -07:00
Jason Turner
feb7775d21 Rename ISSUE_TEMPLATE to ISSUE_TEMPLATE.md 2016-02-23 13:38:50 -07:00
Jason Turner
8d50160cd9 Create ISSUE_TEMPLATE 2016-02-23 13:37:42 -07:00
Jason Turner
871ad10e0e Create PULL_REQUEST_TEMPLATE 2016-02-23 13:31:38 -07:00
Jason Turner
649edf1dd1 Add g++ 4.9 and 5 to travis ... hopefully 2016-02-18 10:26:58 -07:00
Jason Turner
c0664d778c Merge pull request #248 from ChaiScript/release-5.x
Release 5.x
2016-02-16 17:52:50 -07:00
Jason Turner
6c483bd6f6 Update release notes and prepare for 5.8.0 2016-02-16 15:00:13 -07:00
Jason Turner
7f8a6f24f9 Fix a few warnings from old gcc 2016-02-16 11:13:14 -07:00
Jason Turner
07fa8010e4 Ack! Rollback debug statement print out 2016-02-16 11:06:20 -07:00
Jason Turner
e024b99b36 Fixes for type_conversion handling 2016-02-16 08:29:01 -07:00
Jason Turner
ed65ad72d0 Update copyrights 2016-02-14 20:04:17 -07:00
Jason Turner
bc0eaa5d15 Fix some issues found by cppcheck 2016-02-14 20:01:49 -07:00
Jason Turner
e0827634bb Add some cpp<->chai performance tests 2016-02-05 16:18:54 -07:00
Jason Turner
08ba646200 Enable thread local in MSVC 2015 2016-02-02 09:18:08 -07:00
Jason Turner
caf0a8b5d1 Remove extra version of push_back async vector 2016-02-02 07:25:41 -07:00
Jason Turner
357df5c8ec Remove async test from list_push_back 2016-02-01 15:38:32 -07:00
Jason Turner
d0630d5edd Attempt to fix warning from MSVC 2016-02-01 15:24:08 -07:00
Jason Turner
c562d0d78b Fix MSVC build 2016-01-31 21:18:23 -07:00
Jason Turner
bff30278e1 Fix string parsing 2016-01-31 19:35:40 -07:00
Jason Turner
b104b26f11 Also allow lcase global keyword
Closes #221
2016-01-31 19:15:32 -07:00
Jason Turner
03ef44f415 Merge branch 'develop' of github.com:ChaiScript/ChaiScript into develop 2016-01-31 19:12:37 -07:00
Jason Turner
1a06e53c58 Add some compiler identification info to build 2016-01-31 19:06:44 -07:00
Jason Turner
c438a388d7 Add workaround for msvc 2015 update 1 with 1 CPU. 2016-01-31 19:05:37 -07:00
Jason Turner
7923c3e0c7 Add docs on set_global 2016-01-31 14:05:44 -07:00
Jason Turner
872f16e45a Add some tests that were laying around 2016-01-30 06:56:01 -07:00
Jason Turner
7688c14d43 Parse strings in ${} closes #131 2016-01-29 21:34:04 -07:00
Jason Turner
bde2a45384 Add map conversions
closes #57
2016-01-29 20:41:12 -07:00
Jason Turner
7f4ef8d8fd Fix cppcheck warnings 2016-01-29 20:00:20 -07:00
Jason Turner
0dab950ebf Merge branch 'develop' of github.com:ChaiScript/ChaiScript into develop 2016-01-29 19:43:12 -07:00
Jason Turner
485482b2be Fix tabs in source code 2016-01-29 19:42:50 -07:00
Jason Turner
b2ae317877 Seperate out async moves into a separate test 2016-01-29 19:13:10 -07:00
Jason Turner
5b1b1dbcb4 Added appveyor.yml 2016-01-29 17:20:19 -07:00
Jason Turner
7222390c96 Fix build 2016-01-29 16:12:10 -07:00
Jason Turner
b33f0a08bc Remove initializer_list conversion due to the issues mentioned here:
http://stackoverflow.com/questions/18895583/convert-a-vectort-to-initializer-listt
2016-01-29 16:04:06 -07:00
Jason Turner
140a90f72a Fix g++4.6 build issues 2016-01-29 15:35:40 -07:00
Jason Turner
f697384028 Merge pull request #243 from vrennert/feature_initializer_list_conversion
Added initializer_list<T> conversion as possible function call argument or return type.
2016-01-29 15:20:38 -07:00
Jason Turner
dfd04c8291 Clean up formatting from last merge
Closes #238
2016-01-29 15:16:35 -07:00
Jason Turner
209d6ed2e4 Merge remote-tracking branch 'ktm/set-global' into develop 2016-01-29 15:14:32 -07:00
Jason Turner
d8fa6061a2 Merge branch 'develop' of github.com:ChaiScript/ChaiScript into develop 2016-01-29 13:57:57 -07:00
Jason Turner
651eed8d7a Add no-threads build for testing
Closes #60
2016-01-29 13:57:14 -07:00
Viktor Rennert
af1eba1b0e Added type fix for gcc/clang and tiny formating fixes. 2016-01-26 18:36:45 +01:00
Jason Turner
f82f6c2068 Some fixes found by resharper c++ 2016-01-25 16:41:11 -07:00
Viktor Rennert
fcca453223 Added initializer_list<T> conversion as possible function call argument or return type. 2016-01-26 00:06:57 +01:00
Jason Turner
7ed5c18a86 Merge pull request #241 from ChaiScript/add_performance_tests
Add performance tests
2016-01-20 18:30:35 -07:00
Jason Turner
c067575ac4 Merge branch 'develop' into add_performance_tests 2016-01-20 18:24:50 -07:00
Jason Turner
52c96de6a8 Merge pull request #239 from ChaiScript/assign_to_result_of_map
Add test for assignment of map() return vector
2016-01-20 18:20:04 -07:00
Jason Turner
907e6d74e0 Merge pull request #240 from ChaiScript/add_custom_checks
Add a custom check-for-tabs test to CI
2016-01-20 18:19:31 -07:00
Jason Turner
12cbbd2097 Add test for assignment of map() return vector 2016-01-19 10:00:26 -07:00
ktm
4aa370fbfd restore newline to bottom of file 2016-01-18 13:33:38 -05:00
ktm
3587c3e165 fixed comment on set_global 2016-01-18 13:24:59 -05:00
Jason Turner
acc4345b65 Add a custom check-for-tabs test to CI 2016-01-18 10:36:21 -07:00
ktm
43def57852 add set_global, update unit test 2016-01-17 00:01:51 -05:00
Jason Turner
561b47e463 More explicit int/bool conversions 2016-01-16 09:27:16 -07:00
Jason Turner
9885534b5b Merge branch 'develop' into add_performance_tests 2016-01-16 09:02:52 -07:00
ktm
ad3f111e13 Merge remote-tracking branch 'upstream/master' 2016-01-14 07:52:38 -05:00
Jason Turner
452f71b51f Merge pull request #235 from mlamby/patch-1
Fix user_type example in cheatsheet.md
2016-01-11 20:39:36 -07:00
Michael Lamb
a97cb1530d Fix user_type example in cheatsheet.md
Fixed example code as chaiscript::user_type is a function.
2016-01-08 14:23:09 +11:00
Jason Turner
21048b9e65 Merge pull request #233 from vrennert/feature_enum_utility_helper
Added template specialization in chaiscript::utility::add_class<Enum> to register bulk constants.
2016-01-05 14:03:32 -07:00
Viktor Rennert
d73e715997 Merge branch 'ChaiScript-feature_enum_utility_helper' into feature_enum_utility_helper 2016-01-04 16:00:57 +01:00
Jason Turner
353a077c6b Merge branch 'feature_enum_utility_helper' of github.com:vrennert/ChaiScript into feature_enum_utility_helper 2016-01-03 18:40:34 -07:00
Jason Turner
373a3688c9 Merge branch 'feature_enum_utility_helper' into Fix_Crash_From_CppCon 2016-01-03 18:13:48 -07:00
Jason Turner
208107fd7e Add additional tests for vector conversion 2016-01-03 17:58:05 -07:00
Jason Turner
e19a8e31ea Merge pull request #234 from Bobhostern/patch-1
Fix formatting error in cheatsheet.md
2016-01-03 17:07:24 -07:00
Bobhostern
b55eff95cf Fix formatting error in cheatsheet.md 2016-01-03 13:34:27 -06:00
Viktor Rennert
b6287a194c Merge pull request #1 from ChaiScript/feature_enum_utility_helper
Feature enum utility helper
2016-01-03 10:09:05 +01:00
Jason Turner
888d897a3e Simplify use of enum helper 2016-01-02 19:59:54 -07:00
Jason Turner
e32714c456 Add some operators for Enums made with helper class 2016-01-02 19:45:10 -07:00
Jason Turner
e1c40f3e8f Automatically add copy constuctor for enums added with utility 2016-01-02 19:26:53 -07:00
Jason Turner
d7489358f3 Add failing test for vector of enum values 2016-01-02 19:24:14 -07:00
Viktor Rennert
316ba45e3c Added unittest to cover utility::add_class<Enum> registration. 2016-01-02 20:54:55 +01:00
Viktor Rennert
f0796b51c8 Added template specialization in chaiscript::utility::add_class<Enum> to register bulk constants. 2016-01-02 14:25:44 +01:00
Jason Turner
e638d450ed Merge pull request #232 from RaptorFactor/develop
Fix multiply defined symbols.
2015-12-30 13:09:57 -07:00
Joshua Boyce
e60eabbeb2 Fix another multiply defined symbol. 2015-12-26 03:04:05 -08:00
Joshua Boyce
c249bef27d Fix multiply defined symbols. 2015-12-26 03:03:24 -08:00
Jason Turner
4e69e5a3d2 Merge branch 'Fix_Crash_From_CppCon' of github.com:ChaiScript/ChaiScript into Fix_Crash_From_CppCon 2015-11-25 07:51:12 -07:00
Jason Turner
49c89a3b88 un-break ** cast operation 2015-11-25 09:49:26 -05:00
Jason Turner
7507223c8b Merge pull request #228 from ChristianKaeser/ckfix
String escape sequence bug fix
2015-11-23 12:12:58 -05:00
Jason Turner
681b7db727 Merge branch 'Fix_Crash_From_CppCon' of github.com:ChaiScript/ChaiScript into Fix_Crash_From_CppCon 2015-11-20 06:49:35 -07:00
Jason Turner
4826bddb5b Add overloads for cosnt *& casts 2015-11-20 07:46:52 -06:00
Jason Turner
49436e5740 Merge branch 'develop' into Fix_Crash_From_CppCon 2015-11-20 05:53:44 -07:00
Christian Kaeser
202204a82a Limit hexadecimal escape sequence length
Helps with cases like "\xFFecho" by limiting the number of hex digits
that will be parsed to maximum suitable for the char type.
This rule differs from the C/C++ standard, but ChaiScript does not offer
the same workaround options.
Furthermore, without it having hexadecimal sequences longer than can fit
into the char type is undefined behavior anyway.
2015-11-08 18:36:16 +01:00
Christian Kaeser
34c6b17215 Fix broken escape sequence parsing after octal/hex escape
The parser code just added the first character after an octal/hex sequence
as raw text, resulting in erroneous data whenever another escape
sequence follows directly after.
2015-11-08 18:07:04 +01:00
Jason Turner
6fe7f5ce98 Don't return reference to copied values 2015-11-03 16:02:25 -07:00
Jason Turner
d9f86a96f0 Add initial failing test 2015-11-03 15:59:43 -07:00
Jason Turner
da1511a092 Enable collection of performance results where possible 2015-10-23 20:38:51 -06:00
Jason Turner
8bd7ccfa9f Only run performance tests on linux 2015-10-23 16:38:04 -06:00
Jason Turner
0806df11d2 Performance test reorg to run automatically 2015-10-23 16:25:16 -06:00
Jason Turner
40b1549b3b Fix use of broken bitset implementation in g++ 2015-10-21 09:30:22 -06:00
Jason Turner
c9a5bf6f83 fix warning from GCC for unknown flag 2015-10-20 18:19:03 -06:00
Jason Turner
8496a86043 Use a bitset instead of bools for type_info flags 2015-10-20 18:14:42 -06:00
Jason Turner
bc388e59da Fix style warning from cppcheck 2015-10-17 09:23:05 -06:00
Jason Turner
09748275db Fix warnings from clang 2015-10-17 09:22:13 -06:00
Jason Turner
eec0299cbc Merge branch 'develop' of github.com:ChaiScript/ChaiScript into develop 2015-10-17 09:04:48 -06:00
Jason Turner
19ecfdfec5 Merge branch 'add_examples' into develop 2015-10-17 09:04:02 -06:00
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
3e62a99f82 Add factory example with scripted callbacks 2015-10-07 09:55:15 -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
7d3c23fc22 Merge pull request #196 from ChaiScript/develop
Make release v5.7.1
2015-07-17 15:40:54 -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 83281bff52a4ceb7a2a479a42efd5795c54924ac.
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 59eecab0e80c9754e7545b152187934dce82d87d.
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 bb0d1005138e53cb2d414401f0338f22fbbc636b.

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
Jason Turner
fd2539145a Merge branch 'develop' of github.com:ChaiScript/ChaiScript into develop 2015-05-06 14:16:04 -06:00
Jason Turner
25f9dcf13e Add release notes for 5.7.0 2015-05-06 14:15:29 -06:00
Jason Turner
fc4b739839 Merge pull request #175 from totalgee/develop
Added elapsed time helper to chai executable
2015-05-06 09:50:06 -06:00
Glen Fraser
bd176cfde2 Renamed timer function to now(), added perf unit test 2015-05-06 11:37:37 +02:00
Jason Turner
04f01eee98 Add notes about literal numerics 2015-05-05 09:51:16 -06:00
Jason Turner
cf4efacbe8 Add 'GLOBAL' keyword #122
Also provides functionality that makes things like overriding the built in
'print' possible. See #67
2015-05-04 11:47:36 -06:00
Glen Fraser
b818799800 Added getTimeInSeconds() helper to chai executable 2015-05-04 19:41:25 +02:00
Jason Turner
fdcc5959c7 Fix tests failing w/MSVC2013 because of formatting 2015-05-03 10:31:10 -06:00
Jason Turner
74a992fad9 VS2015 thread_local doesn't seem ready for primetime yet 2015-05-03 08:43:43 -06:00
Jason Turner
d210f0e4e1 Enable thread_local in more cases, ignore clang warnings 2015-05-02 21:05:45 -06:00
Jason Turner
c0dd0a3041 Use static const true/false on platforms with magic statics 2015-05-02 15:27:51 -06:00
Jason Turner
45baf6f8e9 Global const values for booleans
- Reduces number of Boxed_Value constructions greatly
2015-05-02 13:08:23 -06:00
Jason Turner
e64e4b0877 Fix tests broken by last cleanup 2015-05-01 19:54:14 -06:00
Jason Turner
e286b9a9aa Never access data after moving it! 2015-05-01 07:22:43 -06:00
Jason Turner
d77921f1b5 Reorg of parsing code for maintainability / performance 2015-04-30 22:05:56 -06:00
Jason Turner
ebc6468178 Remove all /analyze from VS12, it's too slow
But still use it on VS14
2015-04-29 16:59:17 -06:00
Jason Turner
3e5034ecf8 Merge branch 'smaller_make_shared' into develop 2015-04-29 16:58:34 -06:00
Jason Turner
c52ad3d827 Merge pull request #174 from totalgee/develop
Support scientific notation for floating point (issue #173)
2015-04-29 16:50:39 -06:00
Glen Fraser
8fc61bf51c Fixing build error with tolower() on Windows 2015-04-29 21:52:34 +02:00
Jason Turner
dc6d039a72 Add documentation note workaround for libc++ 2015-04-29 13:41:58 -06:00
Jason Turner
2e72fde0ba Horrible workaround for libc++
Libc++ appears to have a problem with dynamic_casting between types
where one of them is a template that has been forward declared. This is
the only case that I see this problem coming up.

Due to the existing interdependencies between header files, I *must*
forward declare the Assignable_Proxy_Function_Impl. I don't see any
other way around this than to work around the standard library bug.
2015-04-29 13:39:57 -06:00
Glen Fraser
d762ef08b6 Support scientific notation for floating point 2015-04-29 19:40:58 +02:00
Jason Turner
8bbcceed88 Attempt better data layout of AST_Node 2015-04-28 08:56:20 -06:00
Jason Turner
aaf80ac8cf Merge branch 'develop' into smaller_make_shared 2015-04-27 16:24:17 -06:00
Jason Turner
86ec14c2c8 Merge branch 'develop' of github.com:ChaiScript/ChaiScript into develop 2015-04-27 16:19:41 -06:00
Jason Turner
dbe546fefb Simplify and reduce eval code where possible 2015-04-27 16:17:01 -06:00
Jason Turner
50e0ce36be Clean up missing <string> include 2015-04-27 14:12:23 -06:00
Jason Turner
986699a3fe Merge branch 'develop' into smaller_make_shared
And also apply cleanups suggested from resharper

Conflicts:
	include/chaiscript/language/chaiscript_parser.hpp
2015-04-27 11:55:12 -06:00
Jason Turner
8889324b2d Code simplifications and spelling fixes found by clion 2015-04-27 08:09:31 -06:00
Jason Turner
7a13b6b801 Merge branch 'develop' into smaller_make_shared 2015-04-25 08:53:47 -06:00
Jason Turner
b2b604e2ad Merge branch 'reduce_function_scope_creation' into develop 2015-04-25 08:52:00 -06:00
Jason Turner
4f5f46a2e5 Don't use scopes around arithmetic operators 2015-04-24 22:36:22 -06:00
Jason Turner
dde7d27b96 A smaller make_shared derived types 2015-04-24 21:35:56 -06:00
Jason Turner
fa16bcd08e More warning management 2015-04-24 16:10:44 -06:00
Jason Turner
5c4de7e43c More catch() analysis warning cleanups 2015-04-24 14:29:15 -06:00
Jason Turner
bc7668c700 More windows warning fixes because of Catch 2015-04-24 09:53:06 -06:00
Jason Turner
a9d94968d0 Remove redundant /analyze on msvc configs 2015-04-24 07:39:04 -06:00
Jason Turner
1a37343e8b Check more compiler/analyzer warnings 2015-04-24 06:50:34 -06:00
Jason Turner
ddc6ac8e00 Eliminate unnecessary warnings on MSVC (catch)
Mostly caused by catch
2015-04-23 16:27:43 -06:00
Jason Turner
0e41e373c6 Clean up warnings generated by catch 2015-04-23 15:29:14 -06:00
Jason Turner
9ab0b1108a Wrap up method_missing docs and tests 2015-04-23 15:03:08 -06:00
Jason Turner
606c1d9d00 Merge remote-tracking branch 'origin/method_missing' into develop 2015-04-23 09:13:28 -06:00
Jason Turner
28f89475b0 Reduce build time for tests 2015-04-22 22:19:57 -06:00
Jason Turner
1a396be69d Minor unitest cleanups #168 2015-04-22 12:40:17 -06:00
Jason Turner
a542ec01f6 Update method_missing support to reduce exceptions 2015-04-22 12:15:15 -06:00
Jason Turner
f3943f215f Merge remote-tracking branch 'origin/develop' into method_missing 2015-04-22 07:29:46 -06:00
Jason Turner
0f4bd2b889 Merge pull request #172 from ChaiScript/libcxx_ubuntu_14_04
Libcxx ubuntu 14 04
2015-04-22 07:26:10 -06:00
Jason Turner
650889eae7 Fix issue affecting function ordering for vector 2015-04-21 23:19:15 -06:00
Jason Turner
90102cebd7 Full dynamic object system built on method_missing working 2015-04-21 22:36:48 -06:00
Jason Turner
dc746ee131 Merge branch 'method_missing' of https://github.com/arBmind/ChaiScript into method_missing
PR #164

Conflicts:
	include/chaiscript/dispatchkit/dispatchkit.hpp
2015-04-21 14:38:15 -06:00
Jason Turner
059c7bcca1 Merge branch 'fix_attr_function_calls' into develop
Conflicts:
	src/test_module.cpp
2015-04-21 12:45:59 -06:00
Jason Turner
1b7b7d6e2c Enable libc++ builds on dashboard 2015-04-21 12:39:54 -06:00
Jason Turner
7830085f5e Merge remote-tracking branch 'origin/add_array_type_support' into develop 2015-04-21 12:28:26 -06:00
Jason Turner
0ed9602ba9 Get libc++ on ubuntu 14.04 working
The std::is_member_function_pointer<> template is broken on this version
of the libc++ standard library for const member functions.

To get ChaiScript to work with this, we had to work around the use of
automatically generated std::function wrappers in many cases. This
actually cleaned up the code in a few places and muddied it up in one.
2015-04-21 12:01:29 -06:00
Jason Turner
2f531355cd Boxed_Value changes necessary for libc++ 2015-04-20 20:30:25 -06:00
Jason Turner
db34899225 Address msvc issues with #167 #165
The best we can get it down to is 2 moves in MSVC, it does not
elide the moves/copies as well as GCC and Clang do

It's not possible for us to support registering of array types in
MSVC12, but we can in MSVC14 with the latest release of the
compiler.
2015-04-18 20:51:45 -06:00
Jason Turner
71245aa703 Add array type support #167 2015-04-17 20:02:09 -06:00
Jason Turner
ecd2e523f7 attributes / members holding functions works fully now
Issue #155
2015-04-17 16:32:59 -06:00
Jason Turner
d2ed8fdcf1 Get class members that are functions working
Automatic conversion of return values into Proxy_Function objects
Issue: #155
2015-04-17 12:18:47 -06:00
Jason Turner
2f444542ab Add test for attr calls specifically 2015-04-17 07:35:12 -06:00
Jason Turner
268868f102 Add failing tests 2015-04-16 20:00:48 -06:00
Jason Turner
f3090c3857 Add test for number of moves/copies made
For #165
2015-04-12 19:20:24 -06:00
Jason Turner
3c7b0ea069 Revert change to example.cpp library loading 2015-04-10 10:38:49 -06:00
Jason Turner
2e769d81cf Get return_value_handling fully working 2015-04-10 09:32:01 -06:00
Jason Turner
a3f88b43ce Merge branch 'return_value_handling' into develop 2015-04-10 08:20:55 -06:00
Jason Turner
b489ffe3ed Fix errors with eval/use of scripts 2015-04-10 08:20:30 -06:00
Andreas Reischuck
cbeeadd6f3 Merge branch 'develop' into method_missing 2015-04-08 16:52:34 +02:00
Jason Turner
63684d0042 Add the ability to get the return value from 'use' 2015-04-08 08:17:33 -06:00
Jason Turner
1f74bfd9b3 Attempt to create the concept of "return values"
to reduce clones of values. This doesn't quite work
2015-04-07 13:54:38 -06:00
Jason Turner
5114ca9d35 Fix double pointer cast test 2015-04-07 11:09:47 -06:00
Jason Turner
79181fe41e Reduce copies of UDTs 2015-04-07 10:23:43 -06:00
Jason Turner
962bdf4b3c Reduce exceptions on startup to minimum
This still has some exceptions thrown during the loading of modules
since I have no way of knowing where the operating system
`dlopen` and `LoadLibrary` functions will search for me to pre-check
it.

Closes #158
2015-04-06 13:17:41 -06:00
Jason Turner
f953f9b297 Merge branch 'develop' of github.com:ChaiScript/ChaiScript into develop 2015-04-06 07:22:55 -06:00
Jason Turner
1557dabf4f Fixes array access with arithmetic conversions
Closes #156
2015-04-06 07:21:32 -06:00
Jason Turner
9422bc7b2d Add failing test for size_t vector access 2015-04-06 06:40:03 -06:00
Jason Turner
7f1cd29a2c Various cleanups 2015-04-02 15:40:45 -06:00
Jason Turner
8f2e56a681 Initial sublime text support 2015-04-01 09:47:27 -06:00
Jason Turner
88e765bd4e Create LICENSE 2015-04-01 08:07:19 -06:00
Jason Turner
59103b5a22 Apply some IIFE to reduce copies 2015-03-29 21:58:14 -06:00
Andreas Reischuck
b67dc4e09a Merge branch 'develop' into method_missing 2015-03-27 21:36:25 +01:00
Jason Turner
d514fa3346 Create cheatsheet.md 2015-03-27 10:24:47 -06:00
Jason Turner
95ead0dbfb Various warning cleanups 2015-03-25 17:30:19 -06:00
Jason Turner
c32a944b9d Fix macos clang builds 2015-03-25 14:04:42 -06:00
Jason Turner
62337062bf Reduce the number of exceptions created at runtime 2015-03-25 13:36:02 -06:00
Jason Turner
a75117c007 Merge branch 'master' of github.com:ChaiScript/ChaiScript into ast_optimizations 2015-03-25 11:58:43 -06:00
Jason Turner
4fe536e65b Add performance test for type conversions 2015-03-25 11:58:24 -06:00
Jason Turner
d396f8e6a0 Enhancements for > 1 param function dispatch 2015-03-25 10:01:36 -06:00
Jason Turner
6ba3e92d6e Various tree optimizations 2015-03-24 14:15:47 -06:00
Jason Turner
bd1b5c0687 Disable block optimization - it didn't handle stack 2015-03-24 10:15:08 -06:00
Jason Turner
40e2bf4099 Test optimizing the AST 2015-03-23 21:43:57 -06:00
Jason Turner
5b9878b070 Minor speed improvements 2015-03-23 20:07:07 -06:00
Jason Turner
0b28603cdc Merge branch 'develop' of github.com:ChaiScript/ChaiScript into develop 2015-03-23 14:16:48 -06:00
Jason Turner
91bcaaa037 Reduce use of mem_fn when possible 2015-03-23 14:16:23 -06:00
Jason Turner
04bceedf64 Reduce versions of shared_ptr created 2015-03-23 13:44:40 -06:00
Jason Turner
9326539f3b Fix gcc 4.6 errors/issues 2015-03-22 08:14:59 -06:00
Jason Turner
1113cafca2 Merge branch 'develop' of github.com:ChaiScript/ChaiScript into develop
Conflicts:
	CMakeLists.txt
2015-03-21 21:04:03 -06:00
Jason Turner
98e36ab836 Minor cleanups, increment to 5.7.0 2015-03-21 20:56:28 -06:00
Jason Turner
976e4ec46c Enable parsing of lambda captures
Closes #161
2015-03-21 20:30:52 -06:00
Jason Turner
c416ca1e4d Add failing lambda test with bind variable 2015-03-21 19:52:03 -06:00
Jason Turner
9963933f51 Normalize the number of child nodes in a Lambda node 2015-03-21 19:50:04 -06:00
Andreas Reischuck
4e614729dc using copy construction 2015-03-22 00:23:49 +01:00
Andreas Reischuck
d0e763d77e fixed method_missing parameter order 2015-03-22 00:17:53 +01:00
Jason Turner
63c243dec8 Set CMake policy, closes #162 2015-03-21 16:35:59 -06:00
Andreas Reischuck
c15e0174c9 added "method_missing" feature 2015-03-21 22:29:16 +01:00
Jason Turner
ec47a35e9f Merge branch 'master' into develop 2015-03-21 14:15:31 -06:00
Jason Turner
9c1f5b6830 Merge branch 'develop' of github.com:ChaiScript/ChaiScript into develop 2015-03-21 14:15:06 -06:00
Jason Turner
735088dc96 Merge branch 'master' into develop 2015-03-21 14:14:33 -06:00
Jason Turner
f14be9660a Update biicode and get master updated to v5.6.0 2015-03-19 20:03:12 -06:00
Jason Turner
6a5f78240a Merge tag 'v5.6.0' 2015-03-19 20:02:56 -06:00
Jason Turner
230e399d92 Merge branch 'master' of github.com:ChaiScript/ChaiScript 2015-03-18 19:26:29 -06:00
Jason Turner
dace26cae1 add support for biicode 2015-03-18 19:23:04 -06:00
Jason Turner
e6d71373b8 Correct travis yaml 2015-03-18 09:04:36 -06:00
Jason Turner
27e861c7b9 Hook travis up to gitter 2015-03-18 07:49:06 -06:00
Jason Turner
516ca8eec2 Merge branch 'master' into develop 2015-03-13 22:28:24 -06:00
Jason Turner
b71f9db5c2 MSVC Fixes 2015-03-13 22:27:51 -06:00
Jason Turner
aa0ed17e43 Merge tag 'v5.6.0' 2015-03-13 21:59:37 -06:00
Jason Turner
34e3551ebd Fix spelling error in document examples 2015-02-19 08:27:22 -07:00
Jason Turner
c584c29951 Simplification 2015-01-31 16:12:19 -07:00
Jason Turner
c285c4d40b Reduce code in assignment oper eval 2015-01-31 15:07:17 -07:00
Jason Turner
b5188b9eda Cleanup assignment eval 2015-01-31 14:40:26 -07:00
Jason Turner
d558019bb3 Simplify logical && || operator eval 2015-01-31 13:41:29 -07:00
Jason Turner
722e9ed3d1 Various code cleanups 2015-01-31 10:10:35 -07:00
Jason Turner
76ac7c36fe Simplify redundant bool condition checking 2015-01-31 07:28:37 -07:00
Jason Turner
f0ed3a5cf7 Add 'var' 'auto' and typed param documentation 2015-01-19 09:19:31 -07:00
Jason Turner
343264944a Update releasenotes.md 2015-01-17 14:28:06 -07:00
Jason Turner
b436791272 Change to TBZ2 for MacOS packages 2015-01-17 07:09:47 -07:00
Jason Turner
9b19aa3b6e Get ready for 5.6.0 release
- Update copyrights to 2015
 - Set version to 5.6.0
 - Update release notes
2015-01-17 07:05:10 -07:00
Jason Turner
e86fc96b2f Merge branch 'AddMoreWarningFlags' into develop
Conflicts:
	include/chaiscript/dispatchkit/boxed_number.hpp
	include/chaiscript/dispatchkit/proxy_functions.hpp
	include/chaiscript/language/chaiscript_eval.hpp
2015-01-16 19:32:53 -07:00
Jason Turner
66801349a8 Merge remote-tracking branch 'origin/OptionalTypedArgs' into develop 2015-01-16 10:19:27 -07:00
Jason Turner
bde4eb04b6 Merge remote-tracking branch 'origin/DivideByZeroProtection' into develop 2015-01-16 10:18:50 -07:00
Jason Turner
c3f343450d Fix issues found with cppcheck inconclusive 2015-01-16 10:10:14 -07:00
Jason Turner
8dc2c55acd Merge branch 'AddMoreWarningFlags' of https://github.com/ChaiScript/ChaiScript into AddMoreWarningFlags 2015-01-15 17:51:23 -07:00
Jason Turner
adfc56db8b Warning cleanups 2015-01-15 17:49:26 -07:00
Jason Turner
c7b2b3095a Merge branch 'develop' of https://github.com/ChaiScript/ChaiScript into AddMoreWarningFlags 2015-01-15 15:45:45 -07:00
Jason Turner
9449fca22f Memory leak error fixes. Various compiler fixes. 2015-01-15 15:42:35 -07:00
Jason Turner
759d6fc42f Remove [[ noreturn ]], MSVC14 doesn't yet support attributes? 2015-01-15 15:15:02 -07:00
Jason Turner
f95ca75aca Clean up more warnings with stricter warning levels 2015-01-15 14:24:39 -07:00
Jason Turner
41a45ce8b5 Enable warnings (and fix up some things) 2015-01-14 21:07:40 -07:00
Jason Turner
5b6e6042f3 Work around MSVC 2014 issue with future
have to wrap std::future::valid in a lambda due to noexcept?!
2015-01-14 20:41:41 -07:00
Jason Turner
1552d36d7a Fix spelling of ANALYZE to analyze 2015-01-14 20:01:32 -07:00
Jason Turner
26bf531cab Remove unused parameter 2015-01-13 17:07:46 -07:00
Jason Turner
7761ceb736 Clean up some numeric processing code 2015-01-13 17:04:34 -07:00
Jason Turner
497dd89046 Add typed exception unit tests 2015-01-13 14:08:46 -07:00
Jason Turner
ef69e4a2f1 Allow typing of exception handlers 2015-01-13 14:05:41 -07:00
Jason Turner
3f23e57a3d Fix build error 2015-01-13 12:07:08 -07:00
Jason Turner
f66b4aafc1 Fix g++ 4.6 initializers 2015-01-13 11:58:23 -07:00
Jason Turner
3d1edbf38f Add missing dynamic_object_detail 2015-01-13 11:44:13 -07:00
Jason Turner
c1f47cbc16 Update prelude to use new typed params 2015-01-13 11:39:24 -07:00
Jason Turner
4761a68d06 Enable optional typing of function params 2015-01-13 11:24:40 -07:00
Jason Turner
31ef683ced Use SFINAE to clean up divide by zero protection 2015-01-12 10:06:42 -07:00
Jason Turner
9b3bb493e9 Clean up some MSVC warnings 2015-01-10 07:18:10 -07:00
Jason Turner
2f90b3ae6b Correct exception specifier for arithmetic_error 2015-01-09 20:31:40 -07:00
Jason Turner
420ba68b94 Make sure floating point returns Infinity 2015-01-09 20:20:38 -07:00
Jason Turner
576816e3b1 Add unit test for divide by zero protection 2015-01-09 20:17:20 -07:00
Jason Turner
25b15a3449 Only apply divide by zero protection to integers
Also allow arithmetic error to bubble up to the caller.
2015-01-09 20:06:04 -07:00
Jason Turner
8746a9eea5 Make divide by zero protection the default 2015-01-09 19:38:27 -07:00
Jason Turner
0695eec3ca Limit scope of #ifdefs, remove macros
Macros do not fit within the ChaiScript coding standards because
they do not respect namespaces and are more difficult to debug
of something goes wrong.
2015-01-09 19:30:28 -07:00
Jason Turner
1a4dec0df0 Remove redundant/unnecessary constructors and object copies. 2015-01-09 19:06:08 -07:00
Jason Turner
de09489355 Fix formatting (tabs vs spaces) in divide/0 protection 2015-01-09 19:02:56 -07:00
Jason Turner
440ceeebbb Merge branch 'develop' of https://github.com/lufinkey/ChaiScript into DivideByZeroProtection 2015-01-09 19:01:58 -07:00
Jason Turner
12533ce3e1 Add note about State tracking of Type_Conversions 2015-01-09 16:14:47 -07:00
Jason Turner
2e02273673 Add .bundle to module search extensions 2015-01-09 10:40:20 -07:00
Jason Turner
d91294b989 Add warning for c-style casts to gcc 2015-01-07 13:56:48 -07:00
Jason Turner
52d03a66b1 Add future support, and fix returning of r-values 2015-01-06 15:31:06 -07:00
Jason Turner
a32a180a06 wq
Merge branch 'develop' of https://github.com/ChaiScript/ChaiScript into develop
2015-01-06 14:25:44 -07:00
Jason Turner
e61612e416 Fix Doxygen configuration 2015-01-06 13:35:52 -07:00
Jason Turner
7478d57264 Merge remote-tracking branch 'origin/master' into develop 2014-12-21 13:15:12 -07:00
Jason Turner
bab3701c2f Update release notes 2014-12-21 13:14:47 -07:00
Jason Turner
e225654289 Tick version up to 5.5.1 2014-12-21 13:12:56 -07:00
Jason Turner
019ea57cb6 Merge pull request #151 from ChaiScript/performance_test
Performance test
2014-12-17 09:46:28 -07:00
Jason Turner
60fe242fb6 Skip packaging of MSVC 14 builds 2014-12-12 06:52:47 -07:00
Jason Turner
6c10f18e4c Merge pull request #149 from gitter-badger/gitter-badge
Add a Gitter chat badge to readme.md
2014-12-11 08:50:51 -07:00
The Gitter Badger
d5a221a468 Added Gitter badge 2014-12-11 15:47:26 +00:00
Jason Turner
6ec3afc687 Only package 4.8 gcc on linux 2014-12-02 14:33:56 -07:00
Jason Turner
049cd12127 Add "skip_packaging" to macos debug build 2014-12-02 11:23:29 -07:00
Jason Turner
8b34066dd5 Put to use new skip_packaging and build_tag features 2014-12-01 21:22:45 -07:00
Jason Turner
9fb74762ad Remove extraneous std::cout messages 2014-11-23 20:14:12 -07:00
Jason Turner
7b7e7176f5 Merge remote-tracking branch 'origin/develop' into performance_test 2014-11-17 14:17:28 -07:00
Jason Turner
81146d6b0f Clean up compiler warnings 2014-11-17 14:17:07 -07:00
Jason Turner
423e872720 Work around bug in gcc 4.6 for initializer_list
Hopefully also fixes MSVC 2012
2014-11-17 07:02:52 -07:00
Jason Turner
1e8c0ab93e Reduce redundant parsing / error code 2014-11-16 21:22:55 -07:00
Jason Turner
c90fe16858 Clean up Prefix() implementation
Reducing redundant code
2014-11-16 21:02:28 -07:00
Jason Turner
161652b5d9 Reworking of binary operators
- Eliminates re-parsing of operator strings
- Reduces much redundant code

Results

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

View File

@ -1,13 +1,53 @@
compilers:
- name: "clang"
version: "3.5"
cmake_extra_flags: -DUSE_LIBCXX:BOOL=OFF -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON
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 -DRUN_PERFORMANCE_TESTS:BOOL=ON
collect_performance_results: true
- name: "clang"
build_tag: "LibC++"
version: "3.6"
skip_packaging: true
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.6"
skip_packaging: true
cmake_extra_flags: -DRUN_FUZZY_TESTS:BOOL=TRUE -DUSE_LIBCXX:BOOL=OFF -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DENABLE_ADDRESS_SANITIZER:BOOL=ON
- name: "clang"
build_tag: ThreadSanitizer
version: "3.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: "clang"
version: "3.7"
skip_packaging: true
cmake_extra_flags: -DUSE_LIBCXX:BOOL=OFF -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DRUN_PERFORMANCE_TESTS:BOOL=ON
collect_performance_results: true
- name: "clang"
build_tag: "LibC++"
version: "3.7"
skip_packaging: true
cmake_extra_flags: -DUSE_LIBCXX:BOOL=ON -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON
- name: "gcc"
version: "4.8"
cmake_extra_flags: -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DBUILD_TESTING:BOOL=ON
version: "4.9"
cmake_extra_flags: -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DBUILD_TESTING:BOOL=ON -DRUN_PERFORMANCE_TESTS:BOOL=ON
collect_performance_results: true
- name: "gcc"
version: "4.6"
cmake_extra_flags: -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON
version: "4.9"
skip_packaging: true
build_tag: "NoThreads"
cmake_extra_flags: -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DBUILD_TESTING:BOOL=ON -DRUN_PERFORMANCE_TESTS:BOOL=ON -DMULTITHREAD_SUPPORT_ENABLED:BOOL=OFF
collect_performance_results: true
- name: "gcc"
version: "5"
skip_packaging: true
cmake_extra_flags: -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DRUN_PERFORMANCE_TESTS:BOOL=ON
collect_performance_results: true
- name: cppcheck
compiler_extra_flags: --enable=all -I include --inline-suppr
compiler_extra_flags: --enable=all -I include --inline-suppr -Umax --suppress="*:unittests/catch.hpp" --force --suppress="unusedFunction:*"
- name: custom_check
commands:
- ./contrib/check_for_tabs.rb
- ./contrib/check_for_todos.rb

View File

@ -1,7 +1,5 @@
compilers:
- name: clang
cmake_extra_flags: -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DCOMMIT_SHA=$COMMIT_SHA
- name: clang
build_type: Debug
cmake_extra_flags: -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DCOMMIT_SHA=$COMMIT_SHA
build_package_generator: TBZ2

View File

@ -2,19 +2,20 @@ compilers:
- name: Visual Studio
version: 14
cmake_extra_flags: -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DCOMMIT_SHA=%COMMIT_SHA%
compiler_extra_flags: /ANALYZE
compiler_extra_flags: /analyze
skip_packaging: true
- name: Visual Studio
version: 14
architecture: Win64
cmake_extra_flags: -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DCOMMIT_SHA=%COMMIT_SHA%
compiler_extra_flags: /ANALYZE
compiler_extra_flags: /analyze
skip_packaging: true
- name: Visual Studio
version: 12
cmake_extra_flags: -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DCOMMIT_SHA=%COMMIT_SHA%
compiler_extra_flags: /ANALYZE
- name: Visual Studio
version: 12
version: 14
build_type: Debug
architecture: Win64
cmake_extra_flags: -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DCOMMIT_SHA=%COMMIT_SHA%
compiler_extra_flags: /ANALYZE
compiler_extra_flags: /analyze
skip_packaging: true

41
.github/CONTRIBUTING.md vendored Normal file
View File

@ -0,0 +1,41 @@
# Contributing to ChaiScript
Thank you for contributing!
# Pull Requests
Please follow the existing style in the code you are patching.
- two space indent
- no tabs EVER
- match the existing indentation level
All ChaiScript commits are run through a large set of builds and analysis on all supported platforms. Those results are posted on the
[build dashboard](http://chaiscript.com/ChaiScript-BuildResults/index.html). No PR will be accepted until all tests pass.
The build system has full integration with GitHub and you will be notified automatically if all tests have passed.
# Issues
Please do not post a "chaiscript is too slow", "chaiscript compiles too slowly", or "chaiscript needs more documentation" issue
without first reading the following notes.
## ChaiScript is Too Slow
We are actively working on constently improving the runtime performance of ChaiScript. With the performance being
[monitored with each commit](http://chaiscript.com/ChaiScript-BuildResults/performance.html).
If you feel you *must* post an issue about performance, please post a complete example that illustrates the exact case you
feel should be better optimized.
Any issue request regarding performance without a complete example of the issue experienced will be closed.
## ChaiScript Compiles Too Slowly
This is also something we are actively working on. If you need highly optimized build times, please see [this discussion
on the discourse site](http://discourse.chaiscript.com/t/slow-build-times/94).
## ChaiScript Needs More Documentation
If you have a question that is not addressed in the [cheatsheet](https://github.com/ChaiScript/ChaiScript/blob/develop/cheatsheet.md)
please open an issue so we can get the Cheatsheet updated.

10
.github/ISSUE_TEMPLATE.md vendored Normal file
View File

@ -0,0 +1,10 @@
* Compiler Used:
* Operating System:
* Architecture (ARM/x86/32bit/64bit/etc):
### Expected Behavior
### Actual Behavior
### Minimal Example to Reproduce Behavior

8
.github/PULL_REQUEST_TEMPLATE.md vendored Normal file
View File

@ -0,0 +1,8 @@
Issue this pull request references: #
Changes proposed in this pull request
-
-
-

View File

@ -1,31 +1,73 @@
language: cpp
compiler:
- gcc
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- g++-4.9
- g++-5
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
matrix:
include:
- os: linux
sudo: false
env: GCC_VER="4.9"
compiler: gcc
- os: linux
sudo: false
env: GCC_VER="4.9" CMAKE_OPTIONS="-D DYNLOAD_ENABLED:BOOL=FALSE -D MULTITHREAD_SUPPORT_ENABLED:BOOL=FALSE -D USE_STD_MAKE_SHARED:BOOL=TRUE" BUILD_ONLY=1
compiler: gcc
- os: linux
sudo: false
env: GCC_VER="5" CPPCHECK=1 COVERAGE=1 CMAKE_OPTIONS="-D RUN_FUZZY_TESTS:BOOL=TRUE"
compiler: gcc
- os: osx
compiler: clang
osx_image: xcode8
- os: osx
compiler: clang
osx_image: xcode8
env: CMAKE_OPTIONS="-D DYNLOAD_ENABLED:BOOL=FALSE -D MULTITHREAD_SUPPORT_ENABLED:BOOL=FALSE -D USE_STD_MAKE_SHARED:BOOL=TRUE" BUILD_ONLY=1
env:
- 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:
- 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
- if [ "${GCC_VER}" != "" ]; then export CXX="g++-$GCC_VER" CC="gcc-$GCC_VER" GCOV="gcov-$GCC_VER" ; fi
- pip install --user cpp-coveralls
script:
- cmake -D ENABLE_COVERAGE:BOOL=TRUE -D CMAKE_BUILD_TYPE:STRING=Debug .
- make -j2
- make test
- mkdir gcov
- find CMakeFiles/ -name "*.gc*" -exec mv {} gcov/ \;
- $GCOV -d -o gcov gcov/*.gcda
- coveralls -n -E ".*\.cpp"
after_script:
- contrib/codeanalysis/runcppcheck.sh
- cmake -D ENABLE_COVERAGE:BOOL=TRUE -D CMAKE_BUILD_TYPE:STRING=Debug $CMAKE_OPTIONS .
- cmake --build . -- -j2
- if [ "${BUILD_ONLY}" != "1" ]; then ctest; fi
- if [ "${COVERAGE}" = "1" ]; then bash <(curl -s https://raw.githubusercontent.com/codecov/codecov-bash/master/codecov) -x $GCOV -a "-s `pwd`" ; fi
#after_script:
# - if [ ${CPPCHECK} = 1 ]; then contrib/codeanalysis/runcppcheck.sh ; fi
notifications:
email:
recipients:
- jason@emptycrate.com
on_success: always
on_failure: always
env:
global:
secure: eiaR6pXiiEpyB8+LLQ1NvZdl0Yylru1BLy9lMoHl+IpUNGGQGywmW/2WAn77rFfmR1OPA2qWQLfgPwgK0HxUA9HHlot9tre5QhiN2Lw8NOT8tCZ6tTm2+QntDBjBGJyal/knRvQkn/6qs6GxlXRerz4ArnnuPL1vESt3zwB0YtU=
webhooks:
urls:
- https://webhooks.gitter.im/e/4be9a2720eaa1bb2a6c9
on_success: change # options: [always|never|change] default: always
on_failure: always # options: [always|never|change] default: always
on_start: false # default: false

View File

@ -1,18 +1,33 @@
cmake_minimum_required(VERSION 2.8)
if(NOT ${CMAKE_VERSION} VERSION_LESS "3.1")
cmake_policy(SET CMP0054 NEW)
endif()
IF(BIICODE)
INIT_BIICODE_BLOCK()
ADD_BIICODE_TARGETS()
ELSE()
# Your regular CMakeLists configuration here
project(chaiscript)
# MINGW does not yet support C++11's concurrency features
if(MINGW)
option(MULTITHREAD_SUPPORT_ENABLED "Multithreaded Support Enabled" FALSE)
else()
option(MULTITHREAD_SUPPORT_ENABLED "Multithreaded Support Enabled" TRUE)
endif()
option(MULTITHREAD_SUPPORT_ENABLED "Multithreaded Support Enabled" TRUE)
option(DYNLOAD_ENABLED "Dynamic Loading Support Enabled" TRUE)
option(BUILD_MODULES "Build Extra Modules (stl)" TRUE)
option(BUILD_SAMPLES "Build Samples Folder" FALSE)
option(RUN_FUZZY_TESTS "Run tests generated by AFL" FALSE)
option(USE_STD_MAKE_SHARED "Use std::make_shared instead of chaiscript::make_shared" FALSE)
option(RUN_PERFORMANCE_TESTS "Run Performance Tests" FALSE)
mark_as_advanced(USE_STD_MAKE_SHARED)
if(USE_STD_MAKE_SHARED)
add_definitions(-DCHAISCRIPT_USE_STD_MAKE_SHARED)
endif()
if(CMAKE_COMPILER_IS_GNUCC)
option(ENABLE_COVERAGE "Enable Coverage Reporting in GCC" FALSE)
@ -36,11 +51,45 @@ if(CMAKE_COMPILER_IS_GNUCC OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
set(LINKER_FLAGS "${LINKER_FLAGS} -fsanitize=address")
endif()
option(ENABLE_MEMORY_SANITIZER "Enable memory sanitizer testing in gcc/clang" FALSE)
if(ENABLE_MEMORY_SANITIZER)
add_definitions(-fsanitize=memory -g)
set(LINKER_FLAGS "${LINKER_FLAGS} -fsanitize=memory")
endif()
option(ENABLE_UNDEFINED_SANITIZER "Enable undefined behavior sanitizer testing in gcc/clang" FALSE)
if(ENABLE_UNDEFINED_SANITIZER)
add_definitions(-fsanitize=undefined -g)
set(LINKER_FLAGS "${LINKER_FLAGS} -fsanitize=undefined")
endif()
option(ENABLE_LTO "Enable Link Time Optimization" FALSE)
if (ENABLE_LTO)
add_definitions(-flto)
set(LINKER_FLAGS "${LINKER_FLAGS} -flto")
endif()
option(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)
set(LINKER_FLAGS "${LINKER_FLAGS} -fprofile-generate")
endif()
option(PROFILE_USE "Use profile data" FALSE)
if (PROFILE_USE)
add_definitions(-fprofile-use)
set(LINKER_FLAGS "${LINKER_FLAGS} -fprofile-use")
endif()
endif()
list(APPEND CPACK_SOURCE_IGNORE_FILES "${CMAKE_CURRENT_BINARY_DIR}")
@ -53,8 +102,8 @@ set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/license.txt")
set(CPACK_RESOURCE_FILE_README "${CMAKE_CURRENT_SOURCE_DIR}/readme.md")
set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/description.txt")
set(CPACK_PACKAGE_VERSION_MAJOR 5)
set(CPACK_PACKAGE_VERSION_MINOR 4)
set(CPACK_PACKAGE_VERSION_MAJOR 6)
set(CPACK_PACKAGE_VERSION_MINOR 0)
set(CPACK_PACKAGE_VERSION_PATCH 0)
set(CPACK_PACKAGE_EXECUTABLES "chai;ChaiScript Eval")
@ -75,16 +124,12 @@ configure_file(Doxyfile.in ${CMAKE_BINARY_DIR}/Doxyfile)
include(CTest)
include(CPack)
include(cmake/CheckCXX11Features.cmake)
if(NOT MINGW)
find_library(READLINE_LIBRARY NAMES readline PATH /usr/lib /usr/local/lib /opt/local/lib)
endif()
if(HAS_CXX11_VARIADIC_TEMPLATES)
message(STATUS "Variadic Template support detected")
else()
message(SEND_ERROR "The selected compiler does not support the C++11 feature Variadic Templates.")
if (UNIX AND NOT APPLE)
find_program(VALGRIND NAMES valgrind PATH /usr/bin /usr/local/bin)
endif()
enable_testing()
@ -104,17 +149,26 @@ endif()
if(CMAKE_COMPILER_IS_GNUCC)
execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpversion OUTPUT_VARIABLE GCC_VERSION)
if(GCC_VERSION VERSION_LESS 4.8)
set(CPP11_FLAG "-std=c++0x")
if(GCC_VERSION VERSION_LESS 4.9)
set(CPP11_FLAG "-std=c++1y")
else()
set(CPP11_FLAG "-std=c++11")
set(CPP11_FLAG "-std=c++14")
endif()
else()
set(CPP11_FLAG "-std=c++11")
set(CPP11_FLAG "-std=c++14")
endif()
if(MSVC)
add_definitions(/W4 /w44640)
add_definitions(/W4 /w14545 /w34242 /w34254 /w34287 /w44263 /w44265 /w44296 /w44311 /w44826 /we4289 /w14546 /w14547 /w14549 /w14555 /w14619 /w14905 /w14906 /w14928)
if (MSVC_VERSION STREQUAL "1800")
# VS2013 doesn't have magic statics
add_definitions(/w44640)
else()
# enum warnings are too noisy on MSVC2013
add_definitions(/w34062)
endif()
add_definitions(/bigobj)
# Note on MSVC compiler flags.
# The code base selective disables warnings as necessary when the compiler is complaining too much
@ -125,7 +179,13 @@ if(MSVC)
# how to workaround or fix the error. So I'm disabling it globally.
add_definitions(/wd4503)
else()
add_definitions(-Wall -Wextra -Wshadow -Wnon-virtual-dtor -pedantic ${CPP11_FLAG})
add_definitions(-Wall -Wextra -Wconversion -Wshadow -Wnon-virtual-dtor -Wold-style-cast -Wcast-align -Wcast-qual -Wunused -Woverloaded-virtual -pedantic ${CPP11_FLAG})
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
add_definitions(-Weverything -Wno-c++98-compat-pedantic -Wno-c++98-compat -Wno-documentation -Wno-switch-enum -Wno-weak-vtables -Wno-missing-prototypes -Wno-padded -Wno-missing-noreturn -Wno-exit-time-destructors -Wno-documentation-unknown-command)
else()
add_definitions(-Wnoexcept)
endif()
if(APPLE)
add_definitions(-Wno-sign-compare)
@ -154,7 +214,7 @@ endif()
include_directories(include)
set(Chai_INCLUDES include/chaiscript/chaiscript.hpp include/chaiscript/chaiscript_threading.hpp include/chaiscript/dispatchkit/bad_boxed_cast.hpp include/chaiscript/dispatchkit/bind_first.hpp include/chaiscript/dispatchkit/bootstrap.hpp include/chaiscript/dispatchkit/bootstrap_stl.hpp include/chaiscript/dispatchkit/boxed_cast.hpp include/chaiscript/dispatchkit/boxed_cast_helper.hpp include/chaiscript/dispatchkit/boxed_number.hpp include/chaiscript/dispatchkit/boxed_value.hpp include/chaiscript/dispatchkit/dispatchkit.hpp include/chaiscript/dispatchkit/dynamic_cast_conversion.hpp include/chaiscript/dispatchkit/dynamic_object.hpp include/chaiscript/dispatchkit/exception_specification.hpp include/chaiscript/dispatchkit/function_call.hpp include/chaiscript/dispatchkit/function_call_detail.hpp include/chaiscript/dispatchkit/handle_return.hpp include/chaiscript/dispatchkit/operators.hpp include/chaiscript/dispatchkit/proxy_constructors.hpp include/chaiscript/dispatchkit/proxy_functions.hpp include/chaiscript/dispatchkit/proxy_functions_detail.hpp include/chaiscript/dispatchkit/register_function.hpp include/chaiscript/dispatchkit/type_info.hpp include/chaiscript/language/chaiscript_algebraic.hpp include/chaiscript/language/chaiscript_common.hpp include/chaiscript/language/chaiscript_engine.hpp include/chaiscript/language/chaiscript_eval.hpp include/chaiscript/language/chaiscript_parser.hpp include/chaiscript/language/chaiscript_prelude.chai include/chaiscript/language/chaiscript_prelude_docs.hpp include/chaiscript/utility/utility.hpp)
set(Chai_INCLUDES include/chaiscript/chaiscript.hpp include/chaiscript/chaiscript_threading.hpp include/chaiscript/dispatchkit/bad_boxed_cast.hpp include/chaiscript/dispatchkit/bind_first.hpp include/chaiscript/dispatchkit/bootstrap.hpp include/chaiscript/dispatchkit/bootstrap_stl.hpp include/chaiscript/dispatchkit/boxed_cast.hpp include/chaiscript/dispatchkit/boxed_cast_helper.hpp include/chaiscript/dispatchkit/boxed_number.hpp include/chaiscript/dispatchkit/boxed_value.hpp include/chaiscript/dispatchkit/dispatchkit.hpp include/chaiscript/dispatchkit/type_conversions.hpp include/chaiscript/dispatchkit/dynamic_object.hpp include/chaiscript/dispatchkit/exception_specification.hpp include/chaiscript/dispatchkit/function_call.hpp include/chaiscript/dispatchkit/function_call_detail.hpp include/chaiscript/dispatchkit/handle_return.hpp include/chaiscript/dispatchkit/operators.hpp include/chaiscript/dispatchkit/proxy_constructors.hpp include/chaiscript/dispatchkit/proxy_functions.hpp include/chaiscript/dispatchkit/proxy_functions_detail.hpp include/chaiscript/dispatchkit/register_function.hpp include/chaiscript/dispatchkit/type_info.hpp include/chaiscript/language/chaiscript_algebraic.hpp include/chaiscript/language/chaiscript_common.hpp include/chaiscript/language/chaiscript_engine.hpp include/chaiscript/language/chaiscript_eval.hpp include/chaiscript/language/chaiscript_parser.hpp include/chaiscript/language/chaiscript_prelude.hpp include/chaiscript/language/chaiscript_prelude_docs.hpp include/chaiscript/utility/utility.hpp include/chaiscript/utility/json.hpp include/chaiscript/utility/json_wrap.hpp)
set_source_files_properties(${Chai_INCLUDES} PROPERTIES HEADER_FILE_ONLY TRUE)
@ -162,9 +222,15 @@ if(NOT MULTITHREAD_SUPPORT_ENABLED)
add_definitions(-DCHAISCRIPT_NO_THREADS)
endif()
if(NOT DYNLOAD_ENABLED)
add_definitions(-DCHAISCRIPT_NO_DYNLOAD)
endif()
if(CMAKE_HOST_UNIX)
if(NOT ${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD" AND NOT ${CMAKE_SYSTEM_NAME} MATCHES "Haiku")
list(APPEND LIBS "dl")
if(DYNLOAD_ENABLED)
if(NOT ${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD" AND NOT ${CMAKE_SYSTEM_NAME} MATCHES "Haiku")
list(APPEND LIBS "dl")
endif()
endif()
if(MULTITHREAD_SUPPORT_ENABLED)
@ -190,25 +256,37 @@ set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${LINKER_FLAGS}")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${LINKER_FLAGS}")
set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${LINKER_FLAGS}")
add_library(stdlib STATIC static_libs/chaiscript_stdlib.cpp)
add_library(parser STATIC static_libs/chaiscript_parser.cpp)
add_library(chaiscript_stdlib-${CHAI_VERSION} MODULE src/chaiscript_stdlib.cpp)
add_library(chaiscript_stdlib-${CHAI_VERSION} MODULE src/chaiscript_stdlib_module.cpp)
target_link_libraries(chaiscript_stdlib-${CHAI_VERSION} ${LIBS} ${CMAKE_THREAD_LIBS_INIT})
set(CHAISCRIPT_LIBS stdlib parser)
add_executable(chai src/main.cpp ${Chai_INCLUDES})
target_link_libraries(chai ${LIBS})
add_dependencies(chai chaiscript_stdlib-${CHAI_VERSION})
target_link_libraries(chai ${LIBS} ${CHAISCRIPT_LIBS})
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} ${CHAISCRIPT_LIBS})
add_executable(memory_leak_test samples/memory_leak_test.cpp)
target_link_libraries(memory_leak_test ${LIBS})
target_link_libraries(memory_leak_test ${LIBS} ${CHAISCRIPT_LIBS})
add_executable(inheritance samples/inheritance.cpp)
target_link_libraries(inheritance ${LIBS})
target_link_libraries(inheritance ${LIBS} ${CHAISCRIPT_LIBS})
add_executable(factory samples/factory.cpp)
target_link_libraries(factory ${LIBS} ${CHAISCRIPT_LIBS})
add_executable(fun_call_performance samples/fun_call_performance.cpp)
target_link_libraries(fun_call_performance ${LIBS} ${CHAISCRIPT_LIBS})
endif()
if(BUILD_MODULES)
add_library(test_module MODULE src/test_module.cpp)
target_link_libraries(test_module ${LIBS})
add_library(stl_extra MODULE src/stl_extra.cpp)
target_link_libraries(stl_extra ${LIBS})
@ -216,10 +294,87 @@ if(BUILD_MODULES)
endif()
file(GLOB UNIT_TESTS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/unittests/ ${CMAKE_CURRENT_SOURCE_DIR}/unittests/*.chai ${CMAKE_CURRENT_SOURCE_DIR}/unittests/3.x/*.chai)
list(SORT UNIT_TESTS)
file(GLOB PERFORMANCE_TESTS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/performance_tests/ ${CMAKE_CURRENT_SOURCE_DIR}/performance_tests/*.chai)
list(SORT PERFORMANCE_TESTS)
if (RUN_FUZZY_TESTS)
file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/unittests")
execute_process(
COMMAND ${CMAKE_COMMAND} -E tar xjf ${CMAKE_CURRENT_SOURCE_DIR}/unittests/fuzzy_tests-2016-06-29.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
macro(ADD_CATCH_TESTS executable)
if (MSVC)
file(TO_NATIVE_PATH "${QT_LIBRARY_DIR}" QT_LIB_PATH)
set(NEWPATH "${QT_LIB_PATH};$ENV{PATH}")
else()
set(NEWPATH $ENV{PATH})
endif()
get_target_property(target_files ${executable} SOURCES)
foreach(source ${target_files})
if(NOT "${source}" MATCHES "/moc_.*cxx")
string(REGEX MATCH .*cpp source "${source}")
if(source)
file(READ "${source}" contents)
string(REGEX MATCHALL "TEST_CASE\\([ ]*\"[^\"]+\"" found_tests ${contents})
foreach(hit ${found_tests})
string(REGEX REPLACE "TEST_CASE\\([ ]*(\"[^\"]+\").*" "\\1" test_name ${hit})
add_test(compiled.${test_name} "${executable}" ${test_name})
set_tests_properties(compiled.${test_name} PROPERTIES TIMEOUT 660 ENVIRONMENT "PATH=${NEWPATH}")
endforeach()
endif()
endif()
endforeach()
endmacro()
option(UNIT_TEST_LIGHT "Unit tests light (expect module loading failures)" FALSE)
add_test(version_check chai -c "if(\"\\\${ version() };\\\${version_major()};\\\${version_minor()};\\\${version_patch()}\" != \"${CHAI_VERSION};${CPACK_PACKAGE_VERSION_MAJOR};${CPACK_PACKAGE_VERSION_MINOR};${CPACK_PACKAGE_VERSION_PATCH}\") { exit(-1) }")
@ -229,96 +384,76 @@ if(BUILD_TESTING)
"CHAI_MODULE_PATH=${CMAKE_CURRENT_BINARY_DIR}/"
)
add_test(version_check_2 chai --version )
set_property(TEST version_check_2
PROPERTY ENVIRONMENT
"CHAI_MODULE_PATH=${CMAKE_CURRENT_BINARY_DIR}/"
PROPERTY PASS_REGULAR_EXPRESSION "${CHAI_VERSION}"
)
add_test(help chai --help )
set_property(TEST help
PROPERTY ENVIRONMENT
"CHAI_MODULE_PATH=${CMAKE_CURRENT_BINARY_DIR}/"
)
set(TESTS "")
foreach(filename ${UNIT_TESTS})
message(STATUS "Adding test ${filename}")
add_test(${filename} chai ${CMAKE_CURRENT_SOURCE_DIR}/unittests/unit_test.inc ${CMAKE_CURRENT_SOURCE_DIR}/unittests/${filename})
message(STATUS "Adding unit test ${filename}")
add_test(unit.${filename} chai ${CMAKE_CURRENT_SOURCE_DIR}/unittests/unit_test.inc ${CMAKE_CURRENT_SOURCE_DIR}/unittests/${filename})
list(APPEND TESTS unit.${filename})
endforeach()
set_property(TEST ${UNIT_TESTS}
if (RUN_PERFORMANCE_TESTS)
foreach(filename ${PERFORMANCE_TESTS})
message(STATUS "Adding performance test ${filename}")
add_test(NAME performance.${filename} COMMAND ${VALGRIND} --tool=callgrind --callgrind-out-file=callgrind.performance.${filename} $<TARGET_FILE:chai> ${CMAKE_CURRENT_SOURCE_DIR}/performance_tests/${filename})
list(APPEND TESTS performance.${filename})
endforeach()
add_executable(profile_cpp_calls_2 performance_tests/profile_cpp_calls_2.cpp)
target_link_libraries(profile_cpp_calls_2 ${LIBS})
add_test(NAME performance.profile_cpp_calls_2 COMMAND ${VALGRIND} --tool=callgrind --callgrind-out-file=callgrind.performance.profile_cpp_calls_2 $<TARGET_FILE:profile_cpp_calls_2>)
add_executable(profile_fun_wrappers performance_tests/profile_fun_wrappers.cpp)
target_link_libraries(profile_fun_wrappers ${LIBS})
add_test(NAME performance.profile_fun_wrappers COMMAND ${VALGRIND} --tool=callgrind --callgrind-out-file=callgrind.performance.profile_fun_wrappers $<TARGET_FILE:profile_fun_wrappers>)
endif()
set_property(TEST ${TESTS}
PROPERTY ENVIRONMENT
"CHAI_USE_PATH=${CMAKE_CURRENT_SOURCE_DIR}/unittests/"
"CHAI_MODULE_PATH=${CMAKE_CURRENT_BINARY_DIR}/"
)
if(NOT UNIT_TEST_LIGHT)
# commented out because uniform initializer syntax is not working properly in MSVC 2013
add_executable(utility_test unittests/utility_test.cpp)
target_link_libraries(utility_test ${LIBS})
add_test(NAME Utility_Test COMMAND utility_test)
add_executable(compiled_tests unittests/compiled_tests.cpp)
target_link_libraries(compiled_tests ${LIBS} ${CHAISCRIPT_LIBS})
ADD_CATCH_TESTS(compiled_tests)
add_executable(dynamic_object_test unittests/dynamic_object_test.cpp)
target_link_libraries(dynamic_object_test ${LIBS})
add_test(NAME Dynamic_Object_Test COMMAND dynamic_object_test)
add_executable(functor_creation_test unittests/functor_creation_test.cpp)
target_link_libraries(functor_creation_test ${LIBS})
add_test(NAME Functor_Creation_Test COMMAND functor_creation_test)
add_executable(functor_cast_test unittests/functor_cast_test.cpp)
target_link_libraries(functor_cast_test ${LIBS})
add_test(NAME Functor_Cast_Test COMMAND functor_cast_test)
add_executable(static_chaiscript_test unittests/static_chaiscript.cpp)
target_link_libraries(static_chaiscript_test ${LIBS})
add_test(NAME Static_ChaiScript_Test COMMAND static_chaiscript_test)
add_executable(boxed_cast_test unittests/boxed_cast_test.cpp)
target_link_libraries(boxed_cast_test ${LIBS})
add_test(NAME Boxed_Cast_Test COMMAND boxed_cast_test)
add_executable(object_lifetime_test unittests/object_lifetime_test.cpp)
target_link_libraries(object_lifetime_test ${LIBS})
add_test(NAME Object_Lifetime_Test COMMAND object_lifetime_test)
add_executable(function_ordering_test unittests/function_ordering_test.cpp)
target_link_libraries(function_ordering_test ${LIBS})
add_test(NAME Function_Ordering_Test COMMAND function_ordering_test)
add_executable(type_info_test unittests/type_info_test.cpp)
target_link_libraries(type_info_test ${LIBS})
add_test(NAME Type_Info_Test COMMAND type_info_test)
add_executable(type_name_test unittests/type_name_test.cpp)
target_link_libraries(type_name_test ${LIBS})
add_test(NAME Type_Name_Test COMMAND type_name_test)
add_executable(eval_catch_exception_test unittests/eval_catch_exception_test.cpp)
target_link_libraries(eval_catch_exception_test ${LIBS})
add_test(NAME Eval_Catch_Exception_Test COMMAND eval_catch_exception_test)
add_executable(short_comparison_test unittests/short_comparison_test.cpp)
target_link_libraries(short_comparison_test ${LIBS})
add_test(NAME Short_Comparison_Test COMMAND short_comparison_test)
add_executable(cpp_lambda_test unittests/cpp_lambda_test.cpp)
target_link_libraries(cpp_lambda_test ${LIBS})
add_test(NAME cpp_lambda_test COMMAND cpp_lambda_test)
add_executable(expected_eval_errors_test unittests/expected_eval_errors_test.cpp)
target_link_libraries(expected_eval_errors_test ${LIBS})
add_test(NAME Expected_Eval_Errors_Test COMMAND expected_eval_errors_test)
add_executable(set_state_test unittests/set_state_test.cpp)
target_link_libraries(set_state_test ${LIBS})
add_test(NAME Set_State_Test COMMAND set_state_test)
add_executable(simultaneous_chaiscript_test unittests/simultaneous_chaiscript_test.cpp)
target_link_libraries(simultaneous_chaiscript_test ${LIBS})
add_test(NAME Simultaneous_ChaiScript_Test COMMAND simultaneous_chaiscript_test)
add_executable(heap_allocated_chaiscript_test unittests/heap_allocated_chaiscript_test.cpp)
target_link_libraries(heap_allocated_chaiscript_test ${LIBS})
add_test(NAME Heap_Allocated_ChaiScript_Test COMMAND heap_allocated_chaiscript_test)
add_executable(c_linkage_test unittests/c_linkage_test.cpp)
target_link_libraries(c_linkage_test ${LIBS})
target_link_libraries(c_linkage_test ${LIBS} ${CHAISCRIPT_LIBS})
add_test(NAME C_Linkage_Test COMMAND c_linkage_test)
add_executable(integer_literal_test unittests/integer_literal_test.cpp)
target_link_libraries(integer_literal_test ${LIBS})
target_link_libraries(integer_literal_test ${LIBS} ${CHAISCRIPT_LIBS})
add_test(NAME Integer_Literal_Test COMMAND integer_literal_test)
add_executable(arithmetic_conversions_test unittests/arithmetic_conversions_test.cpp)
target_link_libraries(arithmetic_conversions_test ${LIBS})
add_test(NAME Arithmetic_Conversions_Test COMMAND arithmetic_conversions_test)
if(MULTITHREAD_SUPPORT_ENABLED)
add_executable(multithreaded_test unittests/multithreaded_test.cpp)
target_link_libraries(multithreaded_test ${LIBS})
@ -340,9 +475,6 @@ if(BUILD_TESTING)
target_link_libraries(multifile_test ${LIBS})
add_test(NAME MultiFile_Test COMMAND multifile_test)
add_library(test_module MODULE src/test_module.cpp)
target_link_libraries(test_module ${LIBS})
install(TARGETS test_module RUNTIME DESTINATION bin LIBRARY DESTINATION lib/chaiscript)
endif()
endif()
@ -370,3 +502,6 @@ configure_file(contrib/pkgconfig/chaiscript.pc.in lib/pkgconfig/chaiscript.pc @O
install(FILES "${chaiscript_BINARY_DIR}/lib/pkgconfig/chaiscript.pc"
DESTINATION lib/pkgconfig)
ENDIF()

28
DesignGoals.md Normal file
View File

@ -0,0 +1,28 @@
# Introduction
This document outlines the principles that drive the development of ChaiScript. ChaiScript does not intent to be the perfect tool for *every* situation, but it does intend to be a good general purpose tool for *most* situations.
# Goals
1. Trivially easy to integrate with C++ projects
2. 0 external depenencies
3. "Perfect" integration with C++
* Direct mapping between ChaiScript objects and C++ objects
* Direct mapping between ChaiScript functions and C++ functions
* Direct mapping between ChaiScript exceptions and C++ exceptions
3. Never surprise the C++ developer
* Object lifetimes managed by the stack
* Familiar syntax to C++ developers
4. Perform "well enough" to not get in the way
# Alternatives
## Sol2
If you are looking for the fastest performing scripting language and don't mind Lua, you might want to consider [sol2](https://github.com/ThePhD/sol2).
## SWIG
If you are looking for the most flexible solution to be able to support multiple target languages, consider [SWIG](http://swig.org)

View File

@ -40,7 +40,7 @@ PROJECT_NUMBER = ${CHAI_VERSION}
# for a project that appears at the top of each page and should give viewer
# a quick idea about the purpose of the project. Keep the description short.
PROJECT_BRIEF = ${CMAKE_BINARY_DIR}/docs
PROJECT_BRIEF = "An easy to use embedded scripting language for C++."
# With the PROJECT_LOGO tag one can specify an logo or icon that is
# included in the documentation. The maximum height of the logo should not

29
LICENSE Normal file
View File

@ -0,0 +1,29 @@
Copyright 2009-2016 Jason Turner
Copyright 2009-2012 Jonathan Turner.
All Rights Reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.
* Neither the name of Jason Turner nor Jonathan Turner nor the
name of contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

22
appveyor.yml Normal file
View File

@ -0,0 +1,22 @@
version: 5.8.x.{build}
os: Visual Studio 2015
environment:
matrix:
- {}
build_script:
- cmd: >-
mkdir build
cd build
cmake c:\Projects\chaiscript -G "Visual Studio 14"
cmake --build . --config Debug
test_script:
- cmd: ctest -C Debug
notifications:
- provider: Webhook
url: https://webhooks.gitter.im/e/9ff725a985b5679d1d5d
on_build_success: true
on_build_failure: true
on_build_status_changed: false

5
biicode.conf Normal file
View File

@ -0,0 +1,5 @@
[paths]
include
[parent]
ChaiScript/ChaiScript: 0

552
cheatsheet.md Normal file
View File

@ -0,0 +1,552 @@
# 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
```
chaiscript::ChaiScript chai; // loads stdlib from loadable module on file system
chaiscript::ChaiScript chai(chaiscript::Std_Lib::library()); // compiles in stdlib
```
# Adding Things To The Engine
## Adding a Function / Method / Member
### General
```
chai.add(chaiscript::fun(&function_name), "function_name");
chai.add(chaiscript::fun(&Class::method_name), "method_name");
chai.add(chaiscript::fun(&Class::member_name), "member_name");
```
### Bound Member Functions
```
chai.add(chaiscript::fun(&Class::method_name, Class_instance_ptr), "method_name");
chai.add(chaiscript::fun(&Class::member_name, Class_instance_ptr), "member_name");
```
### With Overloads
#### Preferred
```
chai.add(chaiscript::fun<ReturnType (ParamType1, ParamType2)>(&function_with_overloads), "function_name");
```
#### Alternative
```
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
```
chai.add(
chaiscript::fun<std::string (bool)>(
[](bool type) {
if (type) { return "x"; }
else { return "y"; }
}), "function_name");
```
### Constructors
```
chai.add(chaiscript::constructor<MyType ()>(), "MyType");
chai.add(chaiscript::constructor<MyType (const MyType &)>(), "MyType");
```
## Adding Types
It's not strictly necessary to add types, but it helps with many things. Cloning, better errors, etc.
```
chai.add(chaiscript::user_type<MyClass>(), "MyClass");
```
## Adding Type Conversions
User defined type conversions are possible, defined in either script or in C++.
### ChaiScript Defined Conversions
Function objects (including lambdas) can be used to add type conversions
from inside of ChaiScript:
```
add_type_conversion(type("string"), type("Type_Info"), fun(s) { return type(s); });
```
### C++ Defined Conversions
Invoking a C++ type conversion possible with `static_cast`
```
chai.add(chaiscript::type_conversion<T, bool>());
```
Calling a user defined type conversion that takes a lambda
```
chai.add(chaiscript::type_conversion<TestBaseType, Type2>([](const TestBaseType &t_bt) { /* return converted thing */ }));
```
### Class Hierarchies
If you want objects to be convertable between base and derived classes, you must tell ChaiScritp about the relationship.
```
chai.add(chaiscript::base_class<Base, Derived>());
```
If you have multiple classes in your inheritance graph, you will probably want to tell ChaiScript about all relationships.
```
chai.add(chaiscript::base_class<Base, Derived>());
chai.add(chaiscript::base_class<Derived, MoreDerived>());
chai.add(chaiscript::base_class<Base, MoreDerived>());
```
### Helpers
A helper function exists for strongly typed and ChaiScript `Vector` function conversion definition:
```
chai.add(chaiscript::vector_conversion<std::vector<int>>());
```
A helper function also exists for strongly typed and ChaiScript `Map` function conversion definition:
```
chai.add(chaiscript::map_conversion<std::map<std::string, int>>());
```
This allows you to pass a ChaiScript function to a function requiring `std::vector<int>`
## Adding Objects
```
chai.add(chaiscript::var(somevar), "somevar"); // copied in
chai.add(chaiscript::var(std::ref(somevar), "somevar"); // by reference, shared between C++ and chai
auto shareddouble = std::make_shared<double>(4.3);
chai.add(chaiscript::var(shareddouble), "shareddouble"); // by shared_ptr, shared between c++ and chai
chai.add(chaiscript::const_var(somevar), "somevar"); // copied in and made const
chai.add_global_const(chaiscript::const_var(somevar), "somevar"); // global const. Throws if value is non-const, throws if object exists
chai.add_global(chaiscript::var(somevar), "somevar"); // global non-const, throws if object exists
chai.set_global(chaiscript::var(somevar), "somevar"); // global non-const, overwrites existing object
```
# Using STL
ChaiScript recognize many types from STL, but you have to add specific instantiation yourself.
```
typedef std::vector<std::pair<int, std::string>> data_list;
data_list my_list{ make_pair(0, "Hello"), make_pair(1, "World") };
chai.add(chaiscript::bootstrap::standard_library::vector_type<data_list>("DataList"));
chai.add(chaiscript::bootstrap::standard_library::pair_type<data_list::value_type>("DataElement"));
chai.add(chaiscript::var(&my_list), "data_list");
chai.eval(R"_(
for(var i=0; i<data_list.size(); ++i)
{
print(to_string(data_list[i].first) + " " + data_list[i].second)
}
)_");
```
# Executing Script
## General
```
chai.eval("print(\"Hello World\")");
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
```
chai.eval<double>("5.3 + 2.1"); // returns 7.4 as a C++ double
```
### Alternative
```
auto v = chai.eval("5.3 + 2.1");
chai.boxed_cast<double>(v); // extracts double value from boxed_value and applies known conversions
chaiscript::boxed_cast<double>(v); // free function version, does not know about conversions
```
### Converting Between Algebraic Types
```
chaiscript::Boxed_Number(chai.eval("5.3 + 2.1")).get_as<int>(); // works with any number type
// which is equivalent to, but much more automatic than:
static_cast<int>(chai.eval<double>("5.3+2.1")); // this version only works if we know that it's a double
```
### Conversion Caveats
Conversion to `std::shared_ptr<T> &` is supported for function calls, but if you attempt to keep a reference to a `shared_ptr<>` you might invoke undefined behavior
```cpp
// ok this is supported, you can register it with chaiscript engine
void nullify_shared_ptr(std::shared_ptr<int> &t) {
t = nullptr
}
```
```cpp
int main()
{
// do some stuff and create a chaiscript instance
std::shared_ptr<int> &ptr = chai.eval<std::shared_ptr<int> &>(somevalue);
// DO NOT do this. Taking a non-const reference to a shared_ptr is not
// supported and causes undefined behavior in the chaiscript engine
}
```
## Sharing Values
```
double &d = chai.eval("var i = 5.2; i"); // d is now a reference to i in the script
std::shared_ptr<double> d = chai.eval("var i = 5.2; i"); // same result but reference counted
d = 3;
chai.eval("print(i)"); // prints 3
```
## Catching Eval Errors
```
try {
chai.eval("2.3 + \"String\"");
} catch (const chaiscript::exception::eval_error &e) {
std::cout << "Error\n" << e.pretty_print() << '\n';
}
```
## Catching Errors Thrown From Script
```
try {
chai.eval("throw(runtime_error(\"error\"))", chaiscript::exception_specification<int, double, float, const std::string &, const std::exception &>());
} catch (const double e) {
} catch (int) {
} catch (float) {
} catch (const std::string &) {
} catch (const std::exception &e) {
// This is the one what will be called in the specific throw() above
}
```
## Sharing Functions
```
auto p = chai.eval<std::function<std::string (double)>>("to_string");
p(5); // calls chaiscript's 'to_string' function, returning std::string("5")
```
Note: backtick treats operators as normal functions
```
auto p = chai.eval<std::function<int (int, int)>>(`+`);
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); }");
p(3,4.2); // evaluates the lambda function, returning the string "34.2" to C++
```
# Language Reference
## Variables
```
var i; // uninitialized variable, can take any value on first assignment;
auto j; // equiv to var
var k = 5; // initialized to 5 (integer)
var l := k; // reference to k
auto &m = k; // reference to k
global g = 5; // creates a global variable. If global already exists, it is not re-added
global g = 2; // global 'g' now equals 2
global g2;
if (g2.is_var_undef()) { g2 = 4; } // only initialize g2 once, if global decl hit more than once
GLOBAL g3; // all upper case version also accepted
```
## Looping
```
// c-style for loops
for (var i = 0; i < 100; ++i) { print(i); }
```
```
// while
while (some_condition()) { /* do something */ }
```
```
// ranged for
for (x : [1,2,3]) { print(i); }
```
Each of the loop styles can be broken using the `break` statement. For example:
```
while (some_condition()) {
/* do something */
if (another_condition()) { break; }
}
```
## Conditionals
```
if (expression) { }
```
```
// C++17-style init-if blocks
// Value of 'statement' is scoped for entire `if` block
if (statement; expression) { }
```
## Built in Types
```
var v = [1,2,3u,4ll,"16", `+`]; // creates vector of heterogenous values
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 notation are supported
```
1.0 // double
1.0f // float
1.0l // long double
1 // int
1u // unsigned int
1ul // unsigned long
1ull // unsigned long long
```
Literals are automatically sized, just as in C++. For example: `10000000000` is > 32bits and the appropriate type is used to hold it
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
```
def myfun(x, y) { x + y; } // last statement in body is the return value
def myfun(x, y) { return x + y; } // equiv
```
### Optionally Typed
```
def myfun(x, int y) { x + y; } // requires y to be an int
```
### With Guards
```
def myfun(x, int y) : y > 5 { x - y; } // only called if y > 5
```
### Methods
Methods and functions are mostly equivalent
```
def string::add(int y) { this + to_string(y); }
def add(string s, int y) { s + to_string(y); } //equiv functionality
// calling new function/method
"a".add(1); // returns a1
add("a", 1); // returns a1, either calling syntax works with either def above
```
### Lambdas
```
var l = fun(x) { x * 15; }
l(2) // returns 30
var a = 13
var m = fun[a](x) { x * a; }
m(3); // a was captured (by reference), returns 39
var n = bind(fun(x,y) { x * y; }, _, 10);
n(2); // returns 20
```
## ChaiScript Defined Types
Define a type called "MyType" with one member value "a" and a getter
### Preferred
```
class MyType {
var value;
def MyType() { this.value = "a"; }
def get_value() { "Value Is: " + this.value; }
};
```
### Alternative
```
attr MyType::value;
def MyType::MyType() { this.value = "a"; }
def MyType::get_value() { "Value Is: " + this.value; }
```
### Using
```
var m = MyType(); // calls constructor
print(m.get_value()); // prints "Value Is: a"
print(get_value(m)); // prints "Value Is: a"
```
## Dynamic Objects
All ChaiScript defined types and generic Dynamic_Object support dynamic parameters
```
var o = Dynamic_Object();
o.f = fun(x) { print(x); }
o.f(3); // prints "3"
```
Implicit 'this' is allowed:
```
var o = Dynamic_Object();
o.x = 3;
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
method cannot be found
```
def method_missing(int i, string name, Vector v) {
print("method_missing(${i}, ${name}), ${v.size()} params");
}
5.bob(1,2,3); // prints "method_missing(5, bob, 3 params)"
```
`method_missing` signature can be either 2 parameters or 3 parameters. If the signature contains two parameters
it is treated as a property. If the property contains a function then additional parameters are passed to
the contained function.
If both a 2 parameter and a 3 parameter signature match, the 3 parameter function always wins.
## Context
* `__LINE__` Current file line number
* `__FILE__` Full path of current file
* `__CLASS__` Name of current class
* `__FUNC__` Mame of current function
# Built In Functions
## Disabling Built-Ins
When constructing a ChaiScript object, a vector of parameters can be passed in to disable or enable various built-in methods.
Current options:
```
enum class Options
{
Load_Modules,
No_Load_Modules,
External_Scripts,
No_External_Scripts
};
```
## Evaluation
```
eval("4 + 5") // dynamically eval script string and returns value of last statement
eval_file("filename") // evals file and returns value of last statement
use("filename") // evals file exactly once and returns value of last statement
// if the file had already been 'used' nothing happens and undefined is returned
```
Both `use` and `eval_file` search the 'usepaths' passed to the ChaiScript constructor
## JSON
* `from_json` converts a JSON string into its strongly typed (map, vector, int, double, string) representations
* `to_json` converts a ChaiScript object (either a `Object` or one of map, vector, int, double, string) tree into its JSON string representation

View File

@ -1,103 +0,0 @@
# Checks for C++11 features
# CXX11_FEATURE_LIST - a list containing all supported features
# HAS_CXX11_AUTO - auto keyword
# HAS_CXX11_NULLPTR - nullptr
# HAS_CXX11_LAMBDA - lambdas
# HAS_CXX11_STATIC_ASSERT - static_assert()
# HAS_CXX11_RVALUE_REFERENCES - rvalue references
# HAS_CXX11_DECLTYPE - decltype keyword
# HAS_CXX11_CSTDINT_H - cstdint header
# HAS_CXX11_LONG_LONG - long long signed & unsigned types
# HAS_CXX11_VARIADIC_TEMPLATES - variadic templates
# HAS_CXX11_CONSTEXPR - constexpr keyword
# HAS_CXX11_SIZEOF_MEMBER - sizeof() non-static members
# HAS_CXX11_FUNC - __func__ preprocessor constant
#
# Original script by Rolf Eike Beer
# Modifications by Andreas Weis
#
CMAKE_MINIMUM_REQUIRED(VERSION 2.8.3)
SET(CHECK_CXX11_OLD_CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS})
IF(CMAKE_COMPILER_IS_GNUCXX)
SET(CMAKE_CXX_FLAGS "-std=c++0x")
endif()
MACRO(CXX11_CHECK_FEATURE FEATURE_NAME FEATURE_NUMBER RESULT_VAR)
IF (NOT DEFINED ${RESULT_VAR})
SET(_bindir "${CMAKE_CURRENT_BINARY_DIR}/cxx11/cxx11_${FEATURE_NAME}")
IF (${FEATURE_NUMBER})
SET(_SRCFILE_BASE ${CMAKE_CURRENT_LIST_DIR}/c++11-test-${FEATURE_NAME}-N${FEATURE_NUMBER})
SET(_LOG_NAME "\"${FEATURE_NAME}\" (N${FEATURE_NUMBER})")
ELSE (${FEATURE_NUMBER})
SET(_SRCFILE_BASE ${CMAKE_CURRENT_LIST_DIR}/c++11-test-${FEATURE_NAME})
SET(_LOG_NAME "\"${FEATURE_NAME}\"")
ENDIF (${FEATURE_NUMBER})
MESSAGE(STATUS "Checking C++11 support for ${_LOG_NAME}")
SET(_SRCFILE "${_SRCFILE_BASE}.cpp")
SET(_SRCFILE_FAIL "${_SRCFILE_BASE}_fail.cpp")
SET(_SRCFILE_FAIL_COMPILE "${_SRCFILE_BASE}_fail_compile.cpp")
IF (CROSS_COMPILING)
try_compile(${RESULT_VAR} "${_bindir}" "${_SRCFILE}")
IF (${RESULT_VAR} AND EXISTS ${_SRCFILE_FAIL})
try_compile(${RESULT_VAR} "${_bindir}_fail" "${_SRCFILE_FAIL}")
ENDIF (${RESULT_VAR} AND EXISTS ${_SRCFILE_FAIL})
ELSE (CROSS_COMPILING)
try_run(_RUN_RESULT_VAR _COMPILE_RESULT_VAR
"${_bindir}" "${_SRCFILE}")
IF (_COMPILE_RESULT_VAR AND NOT _RUN_RESULT_VAR)
SET(${RESULT_VAR} TRUE)
ELSE (_COMPILE_RESULT_VAR AND NOT _RUN_RESULT_VAR)
SET(${RESULT_VAR} FALSE)
ENDIF (_COMPILE_RESULT_VAR AND NOT _RUN_RESULT_VAR)
IF (${RESULT_VAR} AND EXISTS ${_SRCFILE_FAIL})
try_run(_RUN_RESULT_VAR _COMPILE_RESULT_VAR
"${_bindir}_fail" "${_SRCFILE_FAIL}")
IF (_COMPILE_RESULT_VAR AND _RUN_RESULT_VAR)
SET(${RESULT_VAR} TRUE)
ELSE (_COMPILE_RESULT_VAR AND _RUN_RESULT_VAR)
SET(${RESULT_VAR} FALSE)
ENDIF (_COMPILE_RESULT_VAR AND _RUN_RESULT_VAR)
ENDIF (${RESULT_VAR} AND EXISTS ${_SRCFILE_FAIL})
ENDIF (CROSS_COMPILING)
IF (${RESULT_VAR} AND EXISTS ${_SRCFILE_FAIL_COMPILE})
try_compile(_TMP_RESULT "${_bindir}_fail_compile" "${_SRCFILE_FAIL_COMPILE}")
IF (_TMP_RESULT)
SET(${RESULT_VAR} FALSE)
ELSE (_TMP_RESULT)
SET(${RESULT_VAR} TRUE)
ENDIF (_TMP_RESULT)
ENDIF (${RESULT_VAR} AND EXISTS ${_SRCFILE_FAIL_COMPILE})
IF (${RESULT_VAR})
MESSAGE(STATUS "Checking C++11 support for ${_LOG_NAME} -- works")
LIST(APPEND CXX11_FEATURE_LIST ${RESULT_VAR})
ELSE (${RESULT_VAR})
MESSAGE(STATUS "Checking C++11 support for ${_LOG_NAME} -- not supported")
ENDIF (${RESULT_VAR})
SET(${RESULT_VAR} ${${RESULT_VAR}} CACHE INTERNAL "C++11 support for ${_LOG_NAME}")
ENDIF (NOT DEFINED ${RESULT_VAR})
ENDMACRO(CXX11_CHECK_FEATURE)
CXX11_CHECK_FEATURE("auto" 2546 HAS_CXX11_AUTO)
CXX11_CHECK_FEATURE("nullptr" 2431 HAS_CXX11_NULLPTR)
CXX11_CHECK_FEATURE("lambda" 2927 HAS_CXX11_LAMBDA)
CXX11_CHECK_FEATURE("static_assert" 1720 HAS_CXX11_STATIC_ASSERT)
CXX11_CHECK_FEATURE("rvalue_references" 2118 HAS_CXX11_RVALUE_REFERENCES)
CXX11_CHECK_FEATURE("decltype" 2343 HAS_CXX11_DECLTYPE)
CXX11_CHECK_FEATURE("cstdint" "" HAS_CXX11_CSTDINT_H)
CXX11_CHECK_FEATURE("long_long" 1811 HAS_CXX11_LONG_LONG)
CXX11_CHECK_FEATURE("variadic_templates" 2555 HAS_CXX11_VARIADIC_TEMPLATES)
CXX11_CHECK_FEATURE("constexpr" 2235 HAS_CXX11_CONSTEXPR)
CXX11_CHECK_FEATURE("sizeof_member" 2253 HAS_CXX11_SIZEOF_MEMBER)
CXX11_CHECK_FEATURE("__func__" 2340 HAS_CXX11_FUNC)
SET(CXX11_FEATURE_LIST ${CXX11_FEATURE_LIST} CACHE STRING "C++11 feature support list")
MARK_AS_ADVANCED(FORCE CXX11_FEATURE_LIST)
SET(CMAKE_CXX_FLAGS ${CHECK_CXX11_OLD_CMAKE_CXX_FLAGS})
UNSET(CHECK_CXX11_OLD_CMAKE_CXX_FLAGS)

View File

@ -1,8 +0,0 @@
#include <cstring>
int main()
{
if (!__func__) { return 1; }
if(std::strlen(__func__) <= 0) { return 1; }
return 0;
}

View File

@ -1,12 +0,0 @@
int main()
{
auto i = 5;
auto f = 3.14159f;
auto d = 3.14159;
bool ret = (
(sizeof(f) < sizeof(d)) &&
(sizeof(i) == sizeof(int))
);
return ret ? 0 : 1;
}

View File

@ -1,19 +0,0 @@
constexpr int square(int x)
{
return x*x;
}
constexpr int the_answer()
{
return 42;
}
int main()
{
int test_arr[square(3)];
bool ret = (
(square(the_answer()) == 1764) &&
(sizeof(test_arr)/sizeof(test_arr[0]) == 9)
);
return ret ? 0 : 1;
}

View File

@ -1,10 +0,0 @@
#include <cstdint>
int main()
{
bool test =
(sizeof(int8_t) == 1) &&
(sizeof(int16_t) == 2) &&
(sizeof(int32_t) == 4) &&
(sizeof(int64_t) == 8);
return test ? 0 : 1;
}

View File

@ -1,11 +0,0 @@
bool check_size(int i)
{
return sizeof(int) == sizeof(decltype(i));
}
int main()
{
bool ret = check_size(42);
return ret ? 0 : 1;
}

View File

@ -1,5 +0,0 @@
int main()
{
int ret = 0;
return ([&ret]() -> int { return ret; })();
}

View File

@ -1,7 +0,0 @@
int main(void)
{
long long l;
unsigned long long ul;
return ((sizeof(l) >= 8) && (sizeof(ul) >= 8)) ? 0 : 1;
}

View File

@ -1,5 +0,0 @@
int main()
{
int* test = nullptr;
return test ? 1 : 0;
}

View File

@ -1,5 +0,0 @@
int main()
{
int i = nullptr;
return 1;
}

View File

@ -1,15 +0,0 @@
int foo(int& lvalue)
{
return 123;
}
int foo(int&& rvalue)
{
return 321;
}
int main()
{
int i = 42;
return ((foo(i) == 123) && (foo(42) == 321)) ? 0 : 1;
}

View File

@ -1,14 +0,0 @@
struct foo {
char bar;
int baz;
};
int main(void)
{
bool ret = (
(sizeof(foo::bar) == 1) &&
(sizeof(foo::baz) >= sizeof(foo::bar)) &&
(sizeof(foo) >= sizeof(foo::bar)+sizeof(foo::baz))
);
return ret ? 0 : 1;
}

View File

@ -1,5 +0,0 @@
int main()
{
static_assert(0 < 1, "your ordering of integers is screwed");
return 0;
}

View File

@ -1,5 +0,0 @@
int main()
{
static_assert(1 < 0, "this should fail");
return 0;
}

View File

@ -1,23 +0,0 @@
int Accumulate()
{
return 0;
}
template<typename T, typename... Ts>
int Accumulate(T v, Ts... vs)
{
return v + Accumulate(vs...);
}
template<int... Is>
int CountElements()
{
return sizeof...(Is);
}
int main()
{
int acc = Accumulate(1, 2, 3, 4, -5);
int count = CountElements<1,2,3,4,5>();
return ((acc == 5) && (count == 5)) ? 0 : 1;
}

11
contrib/check_for_tabs.rb Executable file
View File

@ -0,0 +1,11 @@
#!/usr/bin/env ruby
require 'json'
`grep -rPIHn '\t' src/* include/* samples/*`.lines { |line|
if /(?<filename>.+(hpp|cpp|chai)):(?<linenumber>[0-9]+):(?<restofline>.+)/ =~ line
puts(JSON.dump({:line => linenumber, :filename => filename, :tool => "tab_checker", :message => "Source Code Line Contains Tabs", :messagetype => "warning"}))
end
}

11
contrib/check_for_todos.rb Executable file
View File

@ -0,0 +1,11 @@
#!/usr/bin/env ruby
require 'json'
`grep -rPIHni 'todo' src/* include/* samples/*`.lines { |line|
if /(?<filename>.+(hpp|cpp|chai)):(?<linenumber>[0-9]+):(?<restofline>.+)/ =~ line
puts(JSON.dump({:line => linenumber, :filename => filename, :tool => "todo_checker", :message => "todo: #{restofline.strip}", :messagetype => "info"}))
end
}

View File

@ -0,0 +1,61 @@
# My dict
for="for"
while="while"
def="def"
fun="fun"
if="if"
else="else"
and="&&"
or="||"
auto="auto"
var="var"
begin_block="{"
end_block="}"
empty_vec="[]"
string="string"
vector="Vector"
map="Map"
return="return"
break="break"
true="true"
false="false"
class="class"
attr="attr"
var="var"
global="global"
empty_lambda=" fun(){} "
empty_fun=" def empty_fun() {} "
continue="continue"
float=" 1.1f "
double=" 2.2 "
long_double=" 2.2ll "
unsigned=" 3u "
unsigned_long=" 4ul "
unsigned_long_long=" 4ull "
long_long=" 5ll "
attr="attr"
reference_del="auto &"
int8=" int8_t(1) "
int16=" int16_t(2) "
int32=" int32_t(3) "
int64=" int64_t(4) "
uint8=" uint8_t(1) "
uint16=" uint16_t(2) "
uint32=" uint32_t(3) "
uint64=" uint64_t(4) "
int8t="int8_t"
int16t="int16_t"
int32t="int32_t"
int64t="int64_t"
uint8t="uint8_t"
uint16t="uint16_t"
uint32t="uint32_t"
uint64t="uint64_t"

View File

@ -0,0 +1,17 @@
Command line used to find this crash:
../../Downloads/afl-1.80b/afl-fuzz -i- -o findings -x chaiscript.dict -- ../a.out unit_test.inc @@
If you can't reproduce a bug outside of afl-fuzz, be sure to set the same
memory limit. The limit used for this fuzzing session was 50.0 MB.
Need a tool to minimize test cases before investigating the crashes or sending
them to a vendor? Check out the afl-tmin that comes with the fuzzer!
Found any cool bugs in open-source tools using afl-fuzz? If yes, please drop
me a mail at <lcamtuf@coredump.cx> once the issues are fixed - I'd love to
add your finds to the gallery at:
http://lcamtuf.coredump.cx/afl/
Thanks :-)

View File

@ -0,0 +1,5 @@
def greet {
return("hello")
}
fun(){ "world" }

View File

@ -1,10 +0,0 @@
var my_array=["1", 4, 6.6l, 10ul, "1000", 100, 10.9f ];
for (var j = 0; j < 10000; ++j)
{
for (var i = 0; i < 6; ++i)
{
to_string(my_array[i]);
}
}

View File

@ -4,7 +4,7 @@ pushd ..
wget http://sourceforge.net/projects/cppcheck/files/cppcheck/1.66/cppcheck-1.66.tar.bz2
tar -xvf cppcheck-1.66.tar.bz2
cd cppcheck-1.66
CXX=g++-4.8 make -j2
make -j2
popd
../cppcheck-1.66/cppcheck --enable=all -I include --inline-suppr --suppress=missingIncludeSystem --std=c++11 --platform=unix64 src/main.cpp src/chai*.cpp --template ' - __{severity}__: [{file}:{line}](../blob/TRAVIS_COMMIT/{file}#L{line}) {message} ({id})' 2>output
sed -i "s/TRAVIS_COMMIT/${TRAVIS_COMMIT}/g" output

View File

@ -1,9 +1,13 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_HPP_
#define CHAISCRIPT_HPP_
@ -65,7 +69,7 @@
/// int main()
/// {
/// chaiscript::ChaiScript chai;
/// chai.add(&function, "function");
/// chai.add(chaiscript::fun(&function), "function");
///
/// double d = chai.eval<double>("function(3, 4.75);");
/// }
@ -170,7 +174,7 @@
///
/// ~~~~~~~~~{.cpp}
/// chai.add_global_const(const_var(i), "i");
/// chai("def somefun() { print(i); }; sumfun();");
/// chai("def somefun() { print(i); }; somefun();");
/// ~~~~~~~~~
///
/// @subsubsection adding_functions Adding Functions
@ -663,6 +667,19 @@
///
/// @sa @ref LangObjectSystemRef
///
///
/// -----------------------------------------------------------------------
///
/// @section keywordauto auto
///
/// Defines a variable
///
/// ~~~~~~~~
/// Variable ::= "auto" identifier
/// ~~~~~~~~
///
/// Synonym for @ref keywordvar
///
/// -----------------------------------------------------------------------
///
/// @section keywordbreak break
@ -682,13 +699,12 @@
/// Begins a function or method definition
///
/// ~~~~~~~~
/// Function Definition ::= [annotation + CR/LF] "def" identifier "(" [arg ("," arg)*] ")" [":" guard] block
/// Method Definition ::= [annotation + CR/LF] "def" class_name "::" method_name "(" [arg ("," arg)*] ")" [":" guard] block
/// Function Definition ::= "def" identifier "(" [[type] arg ("," [type] arg)*] ")" [":" guard] block
/// Method Definition ::= "def" class_name "::" method_name "(" [[type] arg ("," [type] arg)*] ")" [":" guard] block
/// ~~~~~~~~
///
/// annotation: meta-annotation on function, currently used as documentation. Optional.
/// identifier: name of function. Required.
/// args: comma-delimited list of parameter names. Optional.
/// args: comma-delimited list of parameter names with optional type specifiers. Optional.
/// guards: guarding statement that act as a prerequisite for the function. Optional.
/// { }: scoped block as function body. Required.
///
@ -765,12 +781,13 @@
/// @section keywordtry try
/// ~~~~~~~~
/// Try Block ::= "try" block
/// ("catch" ["(" variable ")"] [":" guards] block)+
/// ("catch" ["(" [type] variable ")"] [":" guards] block)+
/// ["finally" block]
/// ~~~~~~~~
///
/// @sa ChaiScript_Language::throw
///
///
/// -----------------------------------------------------------------------
///
/// @section keywordwhile while
@ -782,6 +799,19 @@
/// ~~~~~~~~
///
/// This loop can be broken using the @ref keywordbreak command.
///
///
/// -----------------------------------------------------------------------
///
/// @section keywordvar var
///
/// Defines a variable
///
/// ~~~~~~~~
/// Variable ::= "var" identifier
/// ~~~~~~~~
///
/// Synonym for @ref keywordauto
/// @namespace chaiscript
@ -790,16 +820,26 @@
/// @namespace chaiscript::detail
/// @brief Classes and functions reserved for internal use. Items in this namespace are not supported.
#include "chaiscript_defines.hpp"
#include "dispatchkit/dispatchkit.hpp"
#include "dispatchkit/function_call.hpp"
#include "dispatchkit/dynamic_object.hpp"
#include "dispatchkit/boxed_number.hpp"
#include "language/chaiscript_eval.hpp"
#include "language/chaiscript_engine.hpp"
#include "chaiscript_basic.hpp"
#include "language/chaiscript_parser.hpp"
#include "chaiscript_stdlib.hpp"
namespace chaiscript
{
class ChaiScript : public ChaiScript_Basic
{
public:
ChaiScript(std::vector<std::string> t_modulepaths = {},
std::vector<std::string> t_usepaths = {},
const std::vector<Options> &t_opts = {})
: ChaiScript_Basic(
chaiscript::Std_Lib::library(),
std::make_unique<parser::ChaiScript_Parser<eval::Noop_Tracer, optimizer::Optimizer_Default>>(),
t_modulepaths, t_usepaths, t_opts)
{
}
};
}
#endif /* CHAISCRIPT_HPP_ */

View File

@ -0,0 +1,39 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_BASIC_HPP_
#define CHAISCRIPT_BASIC_HPP_
#include "chaiscript_defines.hpp"
#include "dispatchkit/dispatchkit.hpp"
#include "dispatchkit/function_call.hpp"
#include "dispatchkit/dynamic_object.hpp"
#include "dispatchkit/boxed_number.hpp"
#include "language/chaiscript_eval.hpp"
#include "language/chaiscript_engine.hpp"
// This file includes all of the basic requirements for ChaiScript,
// to use, you might do something like:
//
/*
#include "chaiscript_stdlib.hpp"
#include "language/chaiscript_parser.hpp"
ChaiScript_Basic chai(
chaiscript::Std_Lib::library(),
std::make_unique<parser::ChaiScript_Parser<eval::Noop_Tracer, optimizer::Optimizer_Default>>());
*/
// If you want a fully packaged ready to go ChaiScript, use chaiscript.hpp
#endif /* CHAISCRIPT_BASIC_HPP_ */

View File

@ -1,31 +1,56 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_DEFINES_HPP_
#define CHAISCRIPT_DEFINES_HPP_
#ifdef _MSC_VER
#define CHAISCRIPT_STRINGIZE(x) "" #x
#define CHAISCRIPT_STRINGIZE_EXPANDED(x) CHAISCRIPT_STRINGIZE(x)
#define CHAISCRIPT_COMPILER_VERSION CHAISCRIPT_STRINGIZE_EXPANDED(_MSC_FULL_VER)
#define CHAISCRIPT_MSVC _MSC_VER
#define CHAISCRIPT_HAS_DECLSPEC
static_assert(_MSC_FULL_VER >= 190024210, "Visual C++ 2015 Update 3 or later required");
#else
#define CHAISCRIPT_COMPILER_VERSION __VERSION__
#endif
#include <vector>
#if defined( _LIBCPP_VERSION )
#define CHAISCRIPT_LIBCPP
#endif
#if defined(_WIN32) || defined(__CYGWIN__)
#define CHAISCRIPT_WINDOWS
#endif
#if (defined(__GNUC__) && __GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)
/// Currently only g++>=4.8supports this natively
/// \todo Make this support other compilers when possible
#define CHAISCRIPT_HAS_THREAD_LOCAL
#if defined(_WIN32)
#if defined(__llvm__)
#define CHAISCRIPT_COMPILER_NAME "clang(windows)"
#elif defined(__GNUC__)
#define CHAISCRIPT_COMPILER_NAME "gcc(mingw)"
#else
#define CHAISCRIPT_COMPILER_NAME "msvc"
#endif
#else
#if defined(__llvm__)
#define CHAISCRIPT_COMPILER_NAME "clang"
#elif defined(__GNUC__)
#define CHAISCRIPT_COMPILER_NAME "gcc"
#else
#define CHAISCRIPT_COMPILER_NAME "unknown"
#endif
#endif
#if (defined(__GNUC__) && __GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7) || defined(CHAISCRIPT_MSVC) || defined(__llvm__)
#define CHAISCRIPT_OVERRIDE override
#else
#define CHAISCRIPT_OVERRIDE
#if defined(__llvm__)
#define CHAISCRIPT_CLANG
#endif
@ -35,19 +60,168 @@
#define CHAISCRIPT_MODULE_EXPORT extern "C"
#endif
#ifdef CHAISCRIPT_MSVC
#define CHAISCRIPT_NOEXCEPT throw()
#define CHAISCRIPT_CONSTEXPR
#else
#define CHAISCRIPT_NOEXCEPT noexcept
#define CHAISCRIPT_CONSTEXPR constexpr
#if defined(CHAISCRIPT_MSVC) || (defined(__GNUC__) && __GNUC__ >= 5) || defined(CHAISCRIPT_CLANG)
#define CHAISCRIPT_UTF16_UTF32
#endif
#ifdef _DEBUG
#define CHAISCRIPT_DEBUG true
#else
#define CHAISCRIPT_DEBUG false
#endif
#include <memory>
#include <string>
#include <cmath>
namespace chaiscript {
static const int version_major = 5;
static const int version_minor = 4;
static const int version_major = 6;
static const int version_minor = 0;
static const int version_patch = 0;
}
static const char *compiler_version = CHAISCRIPT_COMPILER_VERSION;
static const char *compiler_name = CHAISCRIPT_COMPILER_NAME;
static const bool debug_build = CHAISCRIPT_DEBUG;
template<typename B, typename D, typename ...Arg>
inline std::shared_ptr<B> make_shared(Arg && ... arg)
{
#ifdef CHAISCRIPT_USE_STD_MAKE_SHARED
return std::make_shared<D>(std::forward<Arg>(arg)...);
#else
return std::shared_ptr<B>(static_cast<B*>(new D(std::forward<Arg>(arg)...)));
#endif
}
struct Build_Info {
static int version_major()
{
return chaiscript::version_major;
}
static int version_minor()
{
return chaiscript::version_minor;
}
static int version_patch()
{
return chaiscript::version_patch;
}
static std::string version()
{
return std::to_string(version_major()) + '.' + std::to_string(version_minor()) + '.' + std::to_string(version_patch());
}
static std::string compiler_id()
{
return compiler_name() + '-' + compiler_version();
}
static std::string build_id()
{
return compiler_id() + (debug_build()?"-Debug":"-Release");
}
static std::string compiler_version()
{
return chaiscript::compiler_version;
}
static std::string compiler_name()
{
return chaiscript::compiler_name;
}
static bool debug_build()
{
return chaiscript::debug_build;
}
};
template<typename T>
auto parse_num(const char *t_str) -> typename std::enable_if<std::is_integral<T>::value, T>::type
{
T t = 0;
for (char c = *t_str; (c = *t_str) != 0; ++t_str) {
if (c < '0' || c > '9') {
return t;
}
t *= 10;
t += c - '0';
}
return t;
}
template<typename T>
auto parse_num(const char *t_str) -> typename std::enable_if<!std::is_integral<T>::value, T>::type
{
T t = 0;
T base = 0;
T decimal_place = 0;
bool exponent = false;
bool neg_exponent = false;
const auto final_value = [](const T val, const T baseval, const bool hasexp, const bool negexp) -> T {
if (!hasexp) {
return val;
} else {
return baseval * std::pow(T(10), val*T(negexp?-1:1));
}
};
for(; *t_str != '\0'; ++t_str) {
char c = *t_str;
if (c == '.') {
decimal_place = 10;
} else if (c == 'e' || c == 'E') {
exponent = true;
decimal_place = 0;
base = t;
t = 0;
} else if (c == '-' && exponent) {
neg_exponent = true;
} else if (c == '+' && exponent) {
neg_exponent = false;
} else if (c < '0' || c > '9') {
return final_value(t, base, exponent, neg_exponent);
} else if (decimal_place < T(10)) {
t *= T(10);
t += T(c - '0');
} else {
t += (T(c - '0') / (T(decimal_place)));
decimal_place *= 10;
}
}
return final_value(t, base, exponent, neg_exponent);
}
template<typename T>
T parse_num(const std::string &t_str)
{
return parse_num<T>(t_str.c_str());
}
enum class Options
{
No_Load_Modules,
Load_Modules,
No_External_Scripts,
External_Scripts
};
static inline std::vector<Options> default_options()
{
#ifdef CHAISCRIPT_NO_DYNLOAD
return {Options::No_Load_Modules, Options::External_Scripts};
#else
return {Options::Load_Modules, Options::External_Scripts};
#endif
}
}
#endif

View File

@ -14,10 +14,23 @@
#include <vector>
#include "chaiscript_defines.hpp"
#include "dispatchkit/dispatchkit.hpp"
#include "language/chaiscript_common.hpp"
#include "dispatchkit/function_call.hpp"
//#include "dispatchkit/dispatchkit.hpp"
#include "dispatchkit/operators.hpp"
#include "dispatchkit/bootstrap.hpp"
#include "dispatchkit/bootstrap_stl.hpp"
#include "dispatchkit/boxed_value.hpp"
//#include "dispatchkit/boxed_value.hpp"
#include "language/chaiscript_prelude.hpp"
#include "dispatchkit/register_function.hpp"
#include "utility/json_wrap.hpp"
#ifndef CHAISCRIPT_NO_THREADS
#include <future>
#endif
/// @file
///
@ -31,14 +44,22 @@ namespace chaiscript
static ModulePtr library()
{
using namespace bootstrap;
auto lib = std::make_shared<Module>();
bootstrap::Bootstrap::bootstrap(*lib);
ModulePtr lib = Bootstrap::bootstrap();
bootstrap::standard_library::vector_type<std::vector<Boxed_Value> >("Vector", *lib);
bootstrap::standard_library::string_type<std::string>("string", *lib);
bootstrap::standard_library::map_type<std::map<std::string, Boxed_Value> >("Map", *lib);
bootstrap::standard_library::pair_type<std::pair<Boxed_Value, Boxed_Value > >("Pair", *lib);
lib->add(standard_library::vector_type<std::vector<Boxed_Value> >("Vector"));
lib->add(standard_library::string_type<std::string>("string"));
lib->add(standard_library::map_type<std::map<std::string, Boxed_Value> >("Map"));
lib->add(standard_library::pair_type<std::pair<Boxed_Value, Boxed_Value > >("Pair"));
#ifndef CHAISCRIPT_NO_THREADS
bootstrap::standard_library::future_type<std::future<chaiscript::Boxed_Value>>("future", *lib);
lib->add(chaiscript::fun([](const std::function<chaiscript::Boxed_Value ()> &t_func){ return std::async(std::launch::async, t_func);}), "async");
#endif
json_wrap::library(*lib);
lib->eval(ChaiScript_Prelude::chaiscript_prelude() /*, "standard prelude"*/ );
return lib;
}

View File

@ -1,20 +1,29 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_THREADING_HPP_
#define CHAISCRIPT_THREADING_HPP_
#include <unordered_map>
#ifndef CHAISCRIPT_NO_THREADS
#include <thread>
#include <mutex>
#else
#ifndef CHAISCRIPT_NO_THREADS_WARNING
#pragma message ("ChaiScript is compiling without thread safety.")
#endif
#endif
#include "chaiscript_defines.hpp"
/// \file
///
@ -37,125 +46,92 @@ namespace chaiscript
#ifndef CHAISCRIPT_NO_THREADS
template<typename T>
class unique_lock : public std::unique_lock<T>
{
public:
unique_lock(T &t) : std::unique_lock<T>(t) {}
};
using unique_lock = std::unique_lock<T>;
template<typename T>
class shared_lock : public std::unique_lock<T>
{
public:
shared_lock(T &t) : std::unique_lock<T>(t) {}
void unlock() {}
};
using shared_lock = std::unique_lock<T>;
template<typename T>
class lock_guard : public std::lock_guard<T>
{
public:
lock_guard(T &t) : std::lock_guard<T>(t) {}
};
using lock_guard = std::lock_guard<T>;
class shared_mutex : public std::mutex { };
using shared_mutex = std::mutex;
using std::mutex;
using std::recursive_mutex;
#ifdef CHAISCRIPT_HAS_THREAD_LOCAL
/// Typesafe thread specific storage. If threading is enabled, this class uses a mutex protected map. If
/// threading is not enabled, the class always returns the same data, regardless of which thread it is called from.
template<typename T>
class Thread_Storage
{
public:
Thread_Storage(void *t_key)
: m_key(t_key)
{
}
Thread_Storage() = default;
Thread_Storage(const Thread_Storage &) = delete;
Thread_Storage(Thread_Storage &&) = delete;
Thread_Storage &operator=(const Thread_Storage &) = delete;
Thread_Storage &operator=(Thread_Storage &&) = delete;
~Thread_Storage()
{
t().erase(m_key);
if (!destroyed) {
t().erase(this);
}
}
inline T *operator->() const
inline const T *operator->() const
{
return &(t()[m_key]);
return &(t()[const_cast<Thread_Storage *>(this)]);
}
inline T &operator*() const
inline const T &operator*() const
{
return t()[m_key];
return t()[const_cast<Thread_Storage *>(this)];
}
void *m_key;
inline T *operator->()
{
return &(t()[this]);
}
inline T &operator*()
{
return t()[this];
}
private:
static std::unordered_map<void*, T> &t()
struct Map_Holder {
std::unordered_map<Thread_Storage<T> *, T> map;
Map_Holder() = default;
Map_Holder(const Map_Holder &) = delete;
Map_Holder(Map_Holder &&) = delete;
Map_Holder& operator=(Map_Holder &&) = delete;
Map_Holder& operator=(const Map_Holder &&) = delete;
~Map_Holder() {
// here is the theory:
// * If the Map_Holder is destroyed before the Thread_Storage, a flag will get set
// * If destroyed after the Thread_Storage, the * will have been removed from `map` and nothing will happen
for(auto &elem : map) { elem.first->destroyed = true; }
}
};
static std::unordered_map<Thread_Storage<T> *, T> &t()
{
thread_local static std::unordered_map<void *, T> my_t;
return my_t;
thread_local Map_Holder my_map;
return my_map.map;
}
bool destroyed{false};
};
#else
/// Typesafe thread specific storage. If threading is enabled, this class uses a mutex protected map. If
/// threading is not enabled, the class always returns the same data, regardless of which thread it is called from.
///
/// This version is used if the compiler does not support thread_local
template<typename T>
class Thread_Storage
{
public:
Thread_Storage(void *)
{
}
inline T *operator->() const
{
return get_tls().get();
}
inline T &operator*() const
{
return *get_tls();
}
private:
std::shared_ptr<T> get_tls() const
{
unique_lock<mutex> lock(m_mutex);
auto itr = m_instances.find(std::this_thread::get_id());
if (itr != m_instances.end()) { return itr->second; }
std::shared_ptr<T> new_instance(new T());
m_instances.insert(std::make_pair(std::this_thread::get_id(), new_instance));
return new_instance;
}
mutable mutex m_mutex;
mutable std::unordered_map<std::thread::id, std::shared_ptr<T> > m_instances;
};
#endif // threading enabled but no tls
#else // threading disabled
template<typename T>
class unique_lock
{
public:
unique_lock(T &) {}
explicit unique_lock(T &) {}
void lock() {}
void unlock() {}
};
@ -164,7 +140,7 @@ namespace chaiscript
class shared_lock
{
public:
shared_lock(T &) {}
explicit shared_lock(T &) {}
void lock() {}
void unlock() {}
};
@ -173,7 +149,7 @@ namespace chaiscript
class lock_guard
{
public:
lock_guard(T &) {}
explicit lock_guard(T &) {}
};
class shared_mutex { };
@ -185,7 +161,7 @@ namespace chaiscript
class Thread_Storage
{
public:
Thread_Storage(void *)
explicit Thread_Storage(void *)
{
}

View File

@ -21,21 +21,20 @@ namespace chaiscript {
class bad_any_cast : public std::bad_cast
{
public:
bad_any_cast() CHAISCRIPT_NOEXCEPT
: m_what("bad any cast")
{
}
bad_any_cast() = default;
virtual ~bad_any_cast() CHAISCRIPT_NOEXCEPT {}
bad_any_cast(const bad_any_cast &) = default;
~bad_any_cast() noexcept override = default;
/// \brief Description of what error occurred
virtual const char * what() const CHAISCRIPT_NOEXCEPT CHAISCRIPT_OVERRIDE
const char * what() const noexcept override
{
return m_what.c_str();
}
private:
std::string m_what;
std::string m_what = "bad any cast";
};
}
@ -44,16 +43,17 @@ namespace chaiscript {
private:
struct Data
{
Data(const std::type_info &t_type)
explicit Data(const std::type_info &t_type)
: m_type(t_type)
{
}
Data &operator=(const Data &) = delete;
virtual ~Data() {}
virtual ~Data() = default;
virtual void *data() = 0;
const std::type_info &type() const
{
return m_type;
@ -72,14 +72,12 @@ namespace chaiscript {
{
}
virtual ~Data_Impl() {}
virtual void *data() CHAISCRIPT_OVERRIDE
void *data() override
{
return &m_data;
}
std::unique_ptr<Data> clone() const CHAISCRIPT_OVERRIDE
std::unique_ptr<Data> clone() const override
{
return std::unique_ptr<Data>(new Data_Impl<T>(m_data));
}
@ -94,6 +92,8 @@ namespace chaiscript {
public:
// construct/copy/destruct
Any() = default;
Any(Any &&) = default;
Any &operator=(Any &&t_any) = default;
Any(const Any &t_any)
{
@ -105,10 +105,6 @@ namespace chaiscript {
}
}
#if _MSC_VER != 1800
Any(Any &&) = default;
Any &operator=(Any &&t_any) = default;
#endif
template<typename ValueType,
typename = typename std::enable_if<!std::is_same<Any, typename std::decay<ValueType>::type>::value>::type>
@ -137,10 +133,6 @@ namespace chaiscript {
}
~Any()
{
}
// modifiers
Any & swap(Any &t_other)
{
@ -156,8 +148,7 @@ namespace chaiscript {
const std::type_info & type() const
{
if (m_data)
{
if (m_data) {
return m_data->type();
} else {
return typeid(void);

View File

@ -1,15 +1,20 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_BAD_BOXED_CAST_HPP_
#define CHAISCRIPT_BAD_BOXED_CAST_HPP_
#include <string>
#include <typeinfo>
#include "../chaiscript_defines.hpp"
#include "type_info.hpp"
namespace chaiscript {
@ -28,32 +33,33 @@ namespace chaiscript
class bad_boxed_cast : public std::bad_cast
{
public:
bad_boxed_cast(const Type_Info &t_from, const std::type_info &t_to,
std::string t_what) CHAISCRIPT_NOEXCEPT
bad_boxed_cast(Type_Info t_from, const std::type_info &t_to,
std::string t_what) noexcept
: from(t_from), to(&t_to), m_what(std::move(t_what))
{
}
bad_boxed_cast(const Type_Info &t_from, const std::type_info &t_to) CHAISCRIPT_NOEXCEPT
: from(t_from), to(&t_to), m_what("Cannot perform boxed_cast")
bad_boxed_cast(Type_Info t_from, const std::type_info &t_to)
: from(t_from), to(&t_to), m_what("Cannot perform boxed_cast: " + t_from.name() + " to: " + t_to.name())
{
}
bad_boxed_cast(std::string t_what) CHAISCRIPT_NOEXCEPT
: to(nullptr), m_what(std::move(t_what))
explicit bad_boxed_cast(std::string t_what) noexcept
: m_what(std::move(t_what))
{
}
virtual ~bad_boxed_cast() CHAISCRIPT_NOEXCEPT {}
bad_boxed_cast(const bad_boxed_cast &) = default;
~bad_boxed_cast() noexcept override = default;
/// \brief Description of what error occurred
virtual const char * what() const CHAISCRIPT_NOEXCEPT CHAISCRIPT_OVERRIDE
const char * what() const noexcept override
{
return m_what.c_str();
}
Type_Info from; ///< Type_Info contained in the Boxed_Value
const std::type_info *to; ///< std::type_info of the desired (but failed) result type
const std::type_info *to = nullptr; ///< std::type_info of the desired (but failed) result type
private:
std::string m_what;

View File

@ -1,9 +1,13 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_BIND_FIRST_HPP_
#define CHAISCRIPT_BIND_FIRST_HPP_
@ -14,58 +18,65 @@ namespace chaiscript
namespace detail
{
struct Placeholder
{
static std::tuple<decltype(std::placeholders::_1),decltype(std::placeholders::_2),decltype(std::placeholders::_3),decltype(std::placeholders::_4),decltype(std::placeholders::_5),decltype(std::placeholders::_6),decltype(std::placeholders::_7),decltype(std::placeholders::_8),decltype(std::placeholders::_9),decltype(std::placeholders::_10)> placeholder() {
return std::tuple<decltype(std::placeholders::_1),decltype(std::placeholders::_2),decltype(std::placeholders::_3),decltype(std::placeholders::_4),decltype(std::placeholders::_5),decltype(std::placeholders::_6),decltype(std::placeholders::_7),decltype(std::placeholders::_8),decltype(std::placeholders::_9),decltype(std::placeholders::_10)>(std::placeholders::_1,std::placeholders::_2,std::placeholders::_3,std::placeholders::_4,std::placeholders::_5,std::placeholders::_6,std::placeholders::_7,std::placeholders::_8,std::placeholders::_9,std::placeholders::_10);
};
};
template<int count, int maxcount, typename Sig>
struct Bind_First
template<typename T>
T* get_pointer(T *t)
{
template<typename F, typename ... InnerParams>
static std::function<Sig> bind(F f, InnerParams ... innerparams)
{
return Bind_First<count - 1, maxcount, Sig>::bind(f, innerparams..., std::get<maxcount - count>(Placeholder::placeholder()));
}
};
template<int maxcount, typename Sig>
struct Bind_First<0, maxcount, Sig>
{
template<typename F, typename ... InnerParams>
static std::function<Sig> bind(F f, InnerParams ... innerparams)
{
return std::bind(f, innerparams...);
}
};
template<typename O, typename Ret, typename P1, typename ... Param>
std::function<Ret (Param...)> bind_first(Ret (*f)(P1, Param...), O o)
{
return Bind_First<sizeof...(Param), sizeof...(Param), Ret (Param...)>::bind(f, o);
return t;
}
template<typename O, typename Ret, typename Class, typename ... Param>
std::function<Ret (Param...)> bind_first(Ret (Class::*f)(Param...), O o)
template<typename T>
T* get_pointer(const std::reference_wrapper<T> &t)
{
return Bind_First<sizeof...(Param), sizeof...(Param), Ret (Param...)>::bind(f, o);
}
template<typename O, typename Ret, typename Class, typename ... Param>
std::function<Ret (Param...)> bind_first(Ret (Class::*f)(Param...) const, O o)
{
return Bind_First<sizeof...(Param), sizeof...(Param), Ret (Param...)>::bind(f, o);
return &t.get();
}
template<typename O, typename Ret, typename P1, typename ... Param>
std::function<Ret (Param...)> bind_first(const std::function<Ret (P1, Param...)> &f, O o)
auto bind_first(Ret (*f)(P1, Param...), O&& o)
{
return Bind_First<sizeof...(Param), sizeof...(Param), Ret (Param...)>::bind(f, o);
return [f, o](Param...param) -> Ret {
return f(std::forward<O>(o), std::forward<Param>(param)...);
};
}
template<typename O, typename Ret, typename Class, typename ... Param>
auto bind_first(Ret (Class::*f)(Param...), O&& o)
{
return [f, o](Param...param) -> Ret {
return (get_pointer(o)->*f)(std::forward<Param>(param)...);
};
}
template<typename O, typename Ret, typename Class, typename ... Param>
auto bind_first(Ret (Class::*f)(Param...) const, O&& o)
{
return [f, o](Param...param) -> Ret {
return (get_pointer(o)->*f)(std::forward<Param>(param)...);
};
}
template<typename O, typename Ret, typename P1, typename ... Param>
auto bind_first(const std::function<Ret (P1, Param...)> &f, O&& o)
{
return [f, o](Param...param) -> Ret {
return f(o, std::forward<Param>(param)...);
};
}
template<typename F, typename O, typename Ret, typename Class, typename P1, typename ... Param>
auto bind_first(const F &fo, O&& o, Ret (Class::*f)(P1, Param...) const)
{
return [fo, o, f](Param ...param) -> Ret {
return (fo.*f)(o, std::forward<Param>(param)...);
};
}
template<typename F, typename O>
auto bind_first(const F &f, O&& o)
{
return bind_first(f, std::forward<O>(o), &F::operator());
}
}
}

View File

@ -1,75 +1,75 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_BOOTSTRAP_HPP_
#define CHAISCRIPT_BOOTSTRAP_HPP_
#include <cstdint>
#include <exception>
#include <functional>
#include <iostream>
#include <map>
#include <memory>
#include <sstream>
#include <stdexcept>
#include <string>
#include <type_traits>
#include <vector>
#include "bad_boxed_cast.hpp"
#include "boxed_cast.hpp"
#include "boxed_number.hpp"
#include "boxed_value.hpp"
#include "dispatchkit.hpp"
#include "dynamic_cast_conversion.hpp"
#include "dynamic_object.hpp"
#include "operators.hpp"
#include "proxy_constructors.hpp"
#include "proxy_functions.hpp"
#include "proxy_functions_detail.hpp"
#include "register_function.hpp"
#include "type_info.hpp"
#include "../utility/utility.hpp"
#include "../language/chaiscript_common.hpp"
#include "register_function.hpp"
namespace chaiscript
{
/// \brief Classes and functions useful for bootstrapping of ChaiScript and adding of new types
namespace bootstrap
{
namespace detail
{
/// \brief Constructs a new POD value object from a Boxed_Number
/// \param[in] v Boxed_Number to copy into the new object
/// \returns The newly created object.
template<typename P1>
std::shared_ptr<P1> construct_pod(const Boxed_Number &v)
template<typename T, typename = typename std::enable_if<std::is_array<T>::value>::type >
void array(const std::string &type, Module& m)
{
return std::make_shared<P1>(v.get_as<P1>());
typedef typename std::remove_extent<T>::type ReturnType;
const auto extent = std::extent<T>::value;
m.add(user_type<T>(), type);
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));
} else {
return t[index];
}
}
), "[]"
);
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));
} else {
return t[index];
}
}
), "[]"
);
m.add(fun(
[extent](const T &) {
return extent;
}), "size");
}
}
/// \brief Adds a copy constructor for the given type to the given Model
/// \param[in] type The name of the type. The copy constructor will be named "type".
/// \param[in,out] m The Module to add the copy constructor to
/// \tparam T The type to add a copy constructor for
/// \returns The passed in ModulePtr, or the newly constructed one if the default param is used
/// \returns The passed in Module
template<typename T>
ModulePtr copy_constructor(const std::string &type, ModulePtr m = ModulePtr(new Module()))
void copy_constructor(const std::string &type, Module& m)
{
m->add(constructor<T (const T &)>(), type);
return m;
m.add(constructor<T (const T &)>(), type);
}
/// \brief Add all comparison operators for the templated type. Used during bootstrap, also available to users.
/// \tparam T Type to create comparison operators for
/// \param[in,out] m module to add comparison operators to
/// \returns the passed in ModulePtr or the newly constructed one if the default params are used.
/// \returns the passed in Module.
template<typename T>
ModulePtr opers_comparison(ModulePtr m = ModulePtr(new Module()))
void opers_comparison(Module& m)
{
operators::equal<T>(m);
operators::greater_than<T>(m);
@ -77,7 +77,6 @@ namespace chaiscript
operators::less_than<T>(m);
operators::less_than_equal<T>(m);
operators::not_equal<T>(m);
return m;
}
@ -86,15 +85,14 @@ namespace chaiscript
/// \param[in] type The name of the type to add the constructors for.
/// \param[in,out] m The Module to add the basic constructors to
/// \tparam T Type to generate basic constructors for
/// \returns The passed in ModulePtr, or the newly constructed one if the default param is used
/// \returns The passed in Module
/// \sa copy_constructor
/// \sa constructor
template<typename T>
ModulePtr basic_constructors(const std::string &type, ModulePtr m = ModulePtr(new Module()))
void basic_constructors(const std::string &type, Module& m)
{
m->add(constructor<T ()>(), type);
m.add(constructor<T ()>(), type);
copy_constructor<T>(type, m);
return m;
}
/// \brief Adds a constructor for a POD type
@ -102,26 +100,21 @@ namespace chaiscript
/// \param[in] type The name of the type
/// \param[in,out] m The Module to add the constructor to
template<typename T>
ModulePtr construct_pod(const std::string &type, ModulePtr m = ModulePtr(new Module()))
void construct_pod(const std::string &type, Module& m)
{
m->add(fun(&detail::construct_pod<T>), type);
return m;
m.add(fun([](const Boxed_Number &bn){ return bn.get_as<T>(); }), type);
}
/// to_string function for internal use. Uses ostream operator<<
template<typename Input>
std::string to_string(Input i)
{
std::stringstream ss;
ss << i;
return ss.str();
}
/// Internal function for converting from a string to a value
/// uses ostream operator >> to perform the conversion
template<typename Input>
Input parse_string(const std::string &i)
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;
@ -129,19 +122,28 @@ 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
template<typename T>
ModulePtr bootstrap_pod_type(const std::string &name, ModulePtr m = ModulePtr(new Module()))
void bootstrap_pod_type(const std::string &name, Module& m)
{
m->add(user_type<T>(), name);
m->add(constructor<T ()>(), name);
m.add(user_type<T>(), name);
m.add(constructor<T()>(), name);
construct_pod<T>(name, m);
m->add(fun(&to_string<T>), "to_string");
m->add(fun(&parse_string<T>), "to_" + name);
return m;
m.add(fun(&parse_string<T>), "to_" + name);
}
@ -151,28 +153,23 @@ namespace chaiscript
/// for handling of Proxy_Function object (that is,
/// function variables.
template<typename Type>
std::shared_ptr<Type> shared_ptr_clone(const std::shared_ptr<Type> &p)
auto shared_ptr_clone(const std::shared_ptr<Type> &p)
{
return p;
}
/**
* Specific version of shared_ptr_clone just for Proxy_Functions
*/
/// Specific version of shared_ptr_clone just for Proxy_Functions
template<typename Type>
std::shared_ptr<typename std::remove_const<Type>::type>
shared_ptr_unconst_clone(const std::shared_ptr<typename std::add_const<Type>::type> &p)
std::shared_ptr<typename std::remove_const<Type>::type> shared_ptr_unconst_clone(const std::shared_ptr<typename std::add_const<Type>::type> &p)
{
return std::const_pointer_cast<typename std::remove_const<Type>::type>(p);
}
/**
* Assignment function for shared_ptr objects, does not perform a copy of the
* object pointed to, instead maintains the shared_ptr concept.
* Similar to shared_ptr_clone. Used for Proxy_Function.
*/
/// Assignment function for shared_ptr objects, does not perform a copy of the
/// object pointed to, instead maintains the shared_ptr concept.
/// Similar to shared_ptr_clone. Used for Proxy_Function.
template<typename Type>
Boxed_Value ptr_assign(Boxed_Value lhs, const std::shared_ptr<Type> &rhs)
{
@ -186,16 +183,12 @@ namespace chaiscript
}
}
/**
* Class consisting of only static functions. All default bootstrapping occurs
* from this class.
*/
/// Class consisting of only static functions. All default bootstrapping occurs
/// from this class.
class Bootstrap
{
private:
/**
* Function allowing for assignment of an unknown type to any other value
*/
/// Function allowing for assignment of an unknown type to any other value
static Boxed_Value unknown_assign(Boxed_Value lhs, Boxed_Value rhs)
{
if (lhs.is_undef())
@ -208,72 +201,69 @@ namespace chaiscript
static void print(const std::string &s)
{
std::cout << s;
fwrite(s.c_str(), 1, s.size(), stdout);
}
static void println(const std::string &s)
{
std::cout << s << std::endl;
puts(s.c_str());
}
/**
* Add all arithmetic operators for PODs
*/
static void opers_arithmetic_pod(ModulePtr m = ModulePtr(new Module()))
/// Add all arithmetic operators for PODs
static void opers_arithmetic_pod(Module& m)
{
m->add(fun(&Boxed_Number::equals), "==");
m->add(fun(&Boxed_Number::less_than), "<");
m->add(fun(&Boxed_Number::greater_than), ">");
m->add(fun(&Boxed_Number::greater_than_equal), ">=");
m->add(fun(&Boxed_Number::less_than_equal), "<=");
m->add(fun(&Boxed_Number::not_equal), "!=");
m->add(fun(&Boxed_Number::pre_decrement), "--");
m->add(fun(&Boxed_Number::pre_increment), "++");
m->add(fun(&Boxed_Number::sum), "+");
m->add(fun(&Boxed_Number::unary_plus), "+");
m->add(fun(&Boxed_Number::unary_minus), "-");
m->add(fun(&Boxed_Number::difference), "-");
m->add(fun(&Boxed_Number::assign_bitwise_and), "&=");
m->add(fun(&Boxed_Number::assign), "=");
m->add(fun(&Boxed_Number::assign_bitwise_or), "|=");
m->add(fun(&Boxed_Number::assign_bitwise_xor), "^=");
m->add(fun(&Boxed_Number::assign_remainder), "%=");
m->add(fun(&Boxed_Number::assign_shift_left), "<<=");
m->add(fun(&Boxed_Number::assign_shift_right), ">>=");
m->add(fun(&Boxed_Number::bitwise_and), "&");
m->add(fun(&Boxed_Number::bitwise_complement), "~");
m->add(fun(&Boxed_Number::bitwise_xor), "^");
m->add(fun(&Boxed_Number::bitwise_or), "|");
m->add(fun(&Boxed_Number::assign_product), "*=");
m->add(fun(&Boxed_Number::assign_quotient), "/=");
m->add(fun(&Boxed_Number::assign_sum), "+=");
m->add(fun(&Boxed_Number::assign_difference), "-=");
m->add(fun(&Boxed_Number::quotient), "/");
m->add(fun(&Boxed_Number::shift_left), "<<");
m->add(fun(&Boxed_Number::product), "*");
m->add(fun(&Boxed_Number::remainder), "%");
m->add(fun(&Boxed_Number::shift_right), ">>");
m.add(fun(&Boxed_Number::equals), "==");
m.add(fun(&Boxed_Number::less_than), "<");
m.add(fun(&Boxed_Number::greater_than), ">");
m.add(fun(&Boxed_Number::greater_than_equal), ">=");
m.add(fun(&Boxed_Number::less_than_equal), "<=");
m.add(fun(&Boxed_Number::not_equal), "!=");
m.add(fun(&Boxed_Number::pre_decrement), "--");
m.add(fun(&Boxed_Number::pre_increment), "++");
m.add(fun(&Boxed_Number::sum), "+");
m.add(fun(&Boxed_Number::unary_plus), "+");
m.add(fun(&Boxed_Number::unary_minus), "-");
m.add(fun(&Boxed_Number::difference), "-");
m.add(fun(&Boxed_Number::assign_bitwise_and), "&=");
m.add(fun(&Boxed_Number::assign), "=");
m.add(fun(&Boxed_Number::assign_bitwise_or), "|=");
m.add(fun(&Boxed_Number::assign_bitwise_xor), "^=");
m.add(fun(&Boxed_Number::assign_remainder), "%=");
m.add(fun(&Boxed_Number::assign_shift_left), "<<=");
m.add(fun(&Boxed_Number::assign_shift_right), ">>=");
m.add(fun(&Boxed_Number::bitwise_and), "&");
m.add(fun(&Boxed_Number::bitwise_complement), "~");
m.add(fun(&Boxed_Number::bitwise_xor), "^");
m.add(fun(&Boxed_Number::bitwise_or), "|");
m.add(fun(&Boxed_Number::assign_product), "*=");
m.add(fun(&Boxed_Number::assign_quotient), "/=");
m.add(fun(&Boxed_Number::assign_sum), "+=");
m.add(fun(&Boxed_Number::assign_difference), "-=");
m.add(fun(&Boxed_Number::quotient), "/");
m.add(fun(&Boxed_Number::shift_left), "<<");
m.add(fun(&Boxed_Number::product), "*");
m.add(fun(&Boxed_Number::remainder), "%");
m.add(fun(&Boxed_Number::shift_right), ">>");
}
/**
* Create a bound function object. The first param is the function to bind
* the remaining parameters are the args to bind into the
* result
*/
/// Create a bound function object. The first param is the function to bind
/// 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]);
return Boxed_Value(Const_Proxy_Function(new dispatch::Bound_Function(f,
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()))));
}
@ -281,56 +271,20 @@ namespace chaiscript
static bool has_guard(const Const_Proxy_Function &t_pf)
{
auto pf = std::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(t_pf);
if (pf)
{
if (pf->get_guard()) {
return true;
} else {
return false;
}
} else {
return false;
}
return pf && pf->get_guard();
}
static Const_Proxy_Function get_guard(const Const_Proxy_Function &t_pf)
{
auto pf = std::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(t_pf);
if (pf)
const auto pf = std::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(t_pf);
if (pf && pf->get_guard())
{
if (pf->get_guard())
{
return pf->get_guard();
} else {
throw std::runtime_error("Function does not have a guard");
}
return pf->get_guard();
} else {
throw std::runtime_error("Function does not have a guard");
}
}
static void throw_exception(const Boxed_Value &bv) {
throw bv;
}
static std::string what(const std::exception &e)
{
return e.what();
}
/**
* Boolean specialization of internal to_string function
*/
static std::string bool_to_string(bool b)
{
if (b)
{
return "true";
} else {
return "false";
}
}
template<typename FunctionType>
static std::vector<Boxed_Value> do_return_boxed_value_vector(FunctionType f,
const dispatch::Proxy_Function_Base *b)
@ -350,122 +304,166 @@ namespace chaiscript
static bool has_parse_tree(const chaiscript::Const_Proxy_Function &t_pf)
{
std::shared_ptr<const chaiscript::dispatch::Dynamic_Proxy_Function> pf
= std::dynamic_pointer_cast<const chaiscript::dispatch::Dynamic_Proxy_Function>(t_pf);
if (pf)
{
if (pf->get_parse_tree())
{
return true;
} else {
return false;
}
} else {
return false;
}
const auto pf = std::dynamic_pointer_cast<const chaiscript::dispatch::Dynamic_Proxy_Function>(t_pf);
return pf && pf->get_parse_tree();
}
static chaiscript::AST_NodePtr get_parse_tree(const chaiscript::Const_Proxy_Function &t_pf)
{
std::shared_ptr<const chaiscript::dispatch::Dynamic_Proxy_Function> pf
= std::dynamic_pointer_cast<const chaiscript::dispatch::Dynamic_Proxy_Function>(t_pf);
if (pf)
const auto pf = std::dynamic_pointer_cast<const chaiscript::dispatch::Dynamic_Proxy_Function>(t_pf);
if (pf && pf->get_parse_tree())
{
if (pf->get_parse_tree())
{
return pf->get_parse_tree();
} else {
throw std::runtime_error("Function does not have a parse tree");
}
return pf->get_parse_tree();
} else {
throw std::runtime_error("Function does not have a parse tree");
}
}
template<typename Function>
static std::function<std::vector<Boxed_Value> (const dispatch::Proxy_Function_Base*)> return_boxed_value_vector(const Function &f)
static auto return_boxed_value_vector(const Function &f)
{
return std::bind(&do_return_boxed_value_vector<Function>, f, std::placeholders::_1);
return [f](const dispatch::Proxy_Function_Base *b) {
return do_return_boxed_value_vector(f, b);
};
}
public:
/// \brief perform all common bootstrap functions for std::string, void and POD types
/// \param[in,out] m Module to add bootstrapped functions to
/// \returns passed in ModulePtr, or newly created one if default argument is used
static ModulePtr bootstrap(ModulePtr m = ModulePtr(new Module()))
/// \returns passed in Module
static void bootstrap(Module& m)
{
m->add(user_type<void>(), "void");
m->add(user_type<bool>(), "bool");
m->add(user_type<Boxed_Value>(), "Object");
m->add(user_type<Boxed_Number>(), "Number");
m->add(user_type<Proxy_Function>(), "Function");
m->add(user_type<std::exception>(), "exception");
m.add(user_type<void>(), "void");
m.add(user_type<bool>(), "bool");
m.add(user_type<Boxed_Value>(), "Object");
m.add(user_type<Boxed_Number>(), "Number");
m.add(user_type<Proxy_Function>(), "Function");
m.add(user_type<dispatch::Assignable_Proxy_Function>(), "Assignable_Function");
m.add(user_type<std::exception>(), "exception");
m->add(fun(&dispatch::Proxy_Function_Base::get_arity), "get_arity");
m->add(fun(&dispatch::Proxy_Function_Base::annotation), "get_annotation");
m->add(fun(&dispatch::Proxy_Function_Base::operator==), "==");
m.add(fun(&dispatch::Proxy_Function_Base::get_arity), "get_arity");
m.add(fun(&dispatch::Proxy_Function_Base::operator==), "==");
m->add(fun(return_boxed_value_vector(&dispatch::Proxy_Function_Base::get_param_types)), "get_param_types");
m->add(fun(return_boxed_value_vector(&dispatch::Proxy_Function_Base::get_contained_functions)), "get_contained_functions");
m.add(fun(return_boxed_value_vector(&dispatch::Proxy_Function_Base::get_param_types)), "get_param_types");
m.add(fun(return_boxed_value_vector(&dispatch::Proxy_Function_Base::get_contained_functions)), "get_contained_functions");
m.add(fun([](const std::exception &e){ return std::string(e.what()); }), "what");
m->add(user_type<std::runtime_error>(), "runtime_error");
m->add(chaiscript::base_class<std::exception, std::runtime_error>());
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(constructor<std::runtime_error (const std::string &)>(), "runtime_error");
m->add(fun(std::function<std::string (const std::runtime_error &)>(&what)), "what");
m.add(user_type<std::runtime_error>(), "runtime_error");
m.add(chaiscript::base_class<std::exception, std::runtime_error>());
m->add(user_type<dispatch::Dynamic_Object>(), "Dynamic_Object");
m->add(constructor<dispatch::Dynamic_Object (const std::string &)>(), "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::get_attr), "get_attr");
m.add(constructor<std::runtime_error (const std::string &)>(), "runtime_error");
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.add(user_type<dispatch::Dynamic_Object>(), "Dynamic_Object");
m.add(constructor<dispatch::Dynamic_Object (const std::string &)>(), "Dynamic_Object");
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(&dispatch::Dynamic_Object::has_attr), "has_attr");
m->add(fun(&has_guard), "has_guard");
m->add(fun(&get_guard), "get_guard");
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");
m->add(fun(&Boxed_Value::is_undef), "is_var_undef");
m->add(fun(&Boxed_Value::is_null), "is_var_null");
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_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(static_cast<Boxed_Value & (dispatch::Dynamic_Object::*)(const std::string &)>(&dispatch::Dynamic_Object::method_missing)), "method_missing");
m.add(fun(static_cast<const Boxed_Value & (dispatch::Dynamic_Object::*)(const std::string &) const>(&dispatch::Dynamic_Object::method_missing)), "method_missing");
m->add(fun(&Boxed_Value::get_type_info), "get_type_info");
m->add(user_type<Type_Info>(), "Type_Info");
m->add(constructor<Type_Info (const Type_Info &)>(), "Type_Info");
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(R"chaiscript(
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;
}
def `=`(Dynamic_Object lhs, Dynamic_Object rhs) : lhs.get_type_name() == rhs.get_type_name()
{
for_each(rhs.get_attrs(), fun[lhs](x) { lhs.get_attr(x.first) = clone(x.second); } );
}
def `!=`(Dynamic_Object lhs, Dynamic_Object rhs) : lhs.get_type_name() == rhs.get_type_name()
{
var rhs_attrs := rhs.get_attrs();
var lhs_attrs := lhs.get_attrs();
if (rhs_attrs.size() != lhs_attrs.size()) {
true;
} else {
return any_of(rhs_attrs, fun[lhs](x) { !lhs.has_attr(x.first) || lhs.get_attr(x.first) != x.second; } );
}
}
def `==`(Dynamic_Object lhs, Dynamic_Object rhs) : lhs.get_type_name() == rhs.get_type_name()
{
var rhs_attrs := rhs.get_attrs();
var lhs_attrs := lhs.get_attrs();
if (rhs_attrs.size() != lhs_attrs.size()) {
false;
} else {
return all_of(rhs_attrs, fun[lhs](x) { lhs.has_attr(x.first) && lhs.get_attr(x.first) == x.second; } );
}
}
)chaiscript");
m.add(fun(&has_guard), "has_guard");
m.add(fun(&get_guard), "get_guard");
m.add(fun(&Boxed_Value::is_undef), "is_var_undef");
m.add(fun(&Boxed_Value::is_null), "is_var_null");
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");
m.add(constructor<Type_Info (const Type_Info &)>(), "Type_Info");
operators::equal<Type_Info>(m);
m->add(fun(&Type_Info::is_const), "is_type_const");
m->add(fun(&Type_Info::is_reference), "is_type_reference");
m->add(fun(&Type_Info::is_void), "is_type_void");
m->add(fun(&Type_Info::is_undef), "is_type_undef");
m->add(fun(&Type_Info::is_pointer), "is_type_pointer");
m->add(fun(&Type_Info::is_arithmetic), "is_type_arithmetic");
m->add(fun(&Type_Info::name), "cpp_name");
m->add(fun(&Type_Info::bare_name), "cpp_bare_name");
m->add(fun(&Type_Info::bare_equal), "bare_equal");
m.add(fun(&Type_Info::is_const), "is_type_const");
m.add(fun(&Type_Info::is_reference), "is_type_reference");
m.add(fun(&Type_Info::is_void), "is_type_void");
m.add(fun(&Type_Info::is_undef), "is_type_undef");
m.add(fun(&Type_Info::is_pointer), "is_type_pointer");
m.add(fun(&Type_Info::is_arithmetic), "is_type_arithmetic");
m.add(fun(&Type_Info::name), "cpp_name");
m.add(fun(&Type_Info::bare_name), "cpp_bare_name");
m.add(fun(&Type_Info::bare_equal), "bare_equal");
basic_constructors<bool>("bool", m);
operators::assign<bool>(m);
operators::equal<bool>(m);
operators::not_equal<bool>(m);
m->add(fun(&to_string<const std::string &>), "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([](const std::string &s) { return s; }), "to_string");
m.add(fun([](const bool b) { return std::string(b?"true":"false"); }), "to_string");
m.add(fun(&unknown_assign), "=");
m.add(fun([](const Boxed_Value &bv) { throw bv; }), "throw");
m.add(fun([](const char c) { return std::string(1, c); }), "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);
@ -473,8 +471,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);
@ -484,46 +487,71 @@ namespace chaiscript
bootstrap_pod_type<std::uint32_t>("uint32_t", m);
bootstrap_pod_type<std::uint64_t>("uint64_t", m);
operators::logical_compliment<bool>(m);
opers_arithmetic_pod(m);
m->add(fun(&print), "print_string");
m->add(fun(&println), "println_string");
m->add(Proxy_Function(new dispatch::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(fun(&Boxed_Value::type_match), "type_match");
m.add(fun(&Build_Info::version_major), "version_major");
m.add(fun(&Build_Info::version_minor), "version_minor");
m.add(fun(&Build_Info::version_patch), "version_patch");
m.add(fun(&Build_Info::version), "version");
m.add(fun(&Build_Info::compiler_version), "compiler_version");
m.add(fun(&Build_Info::compiler_name), "compiler_name");
m.add(fun(&Build_Info::compiler_id), "compiler_id");
m.add(fun(&Build_Info::debug_build), "debug_build");
m->add(chaiscript::fun(&has_parse_tree), "has_parse_tree");
m->add(chaiscript::fun(&get_parse_tree), "get_parse_tree");
m.add(fun(&print), "print_string");
m.add(fun(&println), "println_string");
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(
[](dispatch::Assignable_Proxy_Function &t_lhs, const std::shared_ptr<const dispatch::Proxy_Function_Base> &t_rhs) {
t_lhs.assign(t_rhs);
}
), "="
);
m.add(fun(&Boxed_Value::type_match), "type_match");
m.add(chaiscript::fun(&has_parse_tree), "has_parse_tree");
m.add(chaiscript::fun(&get_parse_tree), "get_parse_tree");
m.add(chaiscript::base_class<std::runtime_error, chaiscript::exception::eval_error>());
m.add(chaiscript::base_class<std::exception, chaiscript::exception::eval_error>());
m.add(chaiscript::user_type<chaiscript::exception::arithmetic_error>(), "arithmetic_error");
m.add(chaiscript::base_class<std::runtime_error, chaiscript::exception::arithmetic_error>());
m.add(chaiscript::base_class<std::exception, chaiscript::exception::arithmetic_error>());
m->add(chaiscript::base_class<std::exception, chaiscript::exception::eval_error>());
// chaiscript::bootstrap::standard_library::vector_type<std::vector<std::shared_ptr<chaiscript::AST_Node> > >("AST_NodeVector", m);
chaiscript::utility::add_class<chaiscript::exception::eval_error>(*m,
chaiscript::utility::add_class<chaiscript::exception::eval_error>(m,
"eval_error",
{ },
{ {fun(&chaiscript::exception::eval_error::reason), "reason"},
{fun(std::function<std::vector<Boxed_Value> (const chaiscript::exception::eval_error &t_eval_error)>([](const chaiscript::exception::eval_error &t_eval_error) -> std::vector<Boxed_Value> {
std::vector<Boxed_Value> retval;
std::transform(t_eval_error.call_stack.begin(), t_eval_error.call_stack.end(),
std::back_inserter(retval),
&chaiscript::var<std::shared_ptr<const chaiscript::AST_Node>>);
return retval;
})), "call_stack"} }
{fun(&chaiscript::exception::eval_error::pretty_print), "pretty_print"},
{fun([](const chaiscript::exception::eval_error &t_eval_error) {
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"} }
);
chaiscript::utility::add_class<chaiscript::File_Position>(*m,
chaiscript::utility::add_class<chaiscript::File_Position>(m,
"File_Position",
{ constructor<File_Position()>(),
constructor<File_Position(int, int)>() },
@ -532,7 +560,7 @@ namespace chaiscript
);
chaiscript::utility::add_class<AST_Node>(*m,
chaiscript::utility::add_class<AST_Node>(m,
"AST_Node",
{ },
{ {fun(&AST_Node::text), "text"},
@ -541,28 +569,17 @@ namespace chaiscript
{fun(&AST_Node::start), "start"},
{fun(&AST_Node::end), "end"},
{fun(&AST_Node::to_string), "to_string"},
{fun(std::function<std::vector<Boxed_Value> (const chaiscript::AST_Node &t_node)>([](const chaiscript::AST_Node &t_node) -> std::vector<Boxed_Value> {
{fun([](const chaiscript::AST_Node &t_node) -> std::vector<Boxed_Value> {
std::vector<Boxed_Value> retval;
std::transform(t_node.children.begin(), t_node.children.end(),
const auto children = t_node.get_children();
std::transform(children.begin(), 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"}
}), "children"}
}
);
chaiscript::utility::add_class<parser::ChaiScript_Parser>(*m,
"ChaiScript_Parser",
{ constructor<parser::ChaiScript_Parser ()>() },
{ {fun(&parser::ChaiScript_Parser::parse), "parse"},
{fun(&parser::ChaiScript_Parser::ast), "ast"} }
);
return m;
}
};
}

View File

@ -1,9 +1,13 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
/// \file
/// This file contains utility functions for registration of STL container
/// classes. The methodology used is based on the SGI STL concepts.
@ -14,10 +18,8 @@
#define CHAISCRIPT_BOOTSTRAP_STL_HPP_
#include <functional>
#include <iterator>
#include <memory>
#include <stdexcept>
#include <string>
#include <typeinfo>
#include <vector>
@ -39,11 +41,10 @@ namespace chaiscript
/// Bidir_Range, based on the D concept of ranges.
/// \todo Update the Range code to base its capabilities on
/// the user_typetraits of the iterator passed in
template<typename Container>
template<typename Container, typename IterType>
struct Bidir_Range
{
typedef Container container_type;
typedef typename std::iterator_traits<typename Container::iterator>::reference reference_type;
Bidir_Range(Container &c)
: m_begin(c.begin()), m_end(c.end())
@ -73,86 +74,28 @@ namespace chaiscript
--m_end;
}
reference_type front() const
decltype(auto) front() const
{
if (empty())
{
throw std::range_error("Range empty");
}
return *m_begin;
return (*m_begin);
}
reference_type back() const
decltype(auto) back() const
{
if (empty())
{
throw std::range_error("Range empty");
}
typename Container::iterator pos = m_end;
auto pos = m_end;
--pos;
return *(pos);
return (*(pos));
}
typename Container::iterator m_begin;
typename Container::iterator m_end;
};
template<typename Container>
struct Const_Bidir_Range
{
typedef const Container container_type;
typedef typename std::iterator_traits<typename Container::const_iterator>::reference const_reference_type;
Const_Bidir_Range(const Container &c)
: m_begin(c.begin()), m_end(c.end())
{
}
bool empty() const
{
return m_begin == m_end;
}
void pop_front()
{
if (empty())
{
throw std::range_error("Range empty");
}
++m_begin;
}
void pop_back()
{
if (empty())
{
throw std::range_error("Range empty");
}
--m_end;
}
const_reference_type front() const
{
if (empty())
{
throw std::range_error("Range empty");
}
return *m_begin;
}
const_reference_type back() const
{
if (empty())
{
throw std::range_error("Range empty");
}
typename Container::const_iterator pos = m_end;
--pos;
return *(pos);
}
typename Container::const_iterator m_begin;
typename Container::const_iterator m_end;
IterType m_begin;
IterType m_end;
};
namespace detail {
@ -179,22 +122,20 @@ namespace chaiscript
/// Add Bidir_Range support for the given ContainerType
template<typename Bidir_Type>
ModulePtr input_range_type_impl(const std::string &type, ModulePtr m = ModulePtr(new Module()))
void input_range_type_impl(const std::string &type, Module& m)
{
m->add(user_type<Bidir_Type>(), type + "_Range");
m.add(user_type<Bidir_Type>(), type + "_Range");
copy_constructor<Bidir_Type>(type + "_Range", m);
m->add(constructor<Bidir_Type (typename Bidir_Type::container_type &)>(), "range_internal");
m.add(constructor<Bidir_Type (typename Bidir_Type::container_type &)>(), "range_internal");
m->add(fun(&Bidir_Type::empty), "empty");
m->add(fun(&Bidir_Type::pop_front), "pop_front");
m->add(fun(&Bidir_Type::front), "front");
m->add(fun(&Bidir_Type::pop_back), "pop_back");
m->add(fun(&Bidir_Type::back), "back");
return m;
}
m.add(fun(&Bidir_Type::empty), "empty");
m.add(fun(&Bidir_Type::pop_front), "pop_front");
m.add(fun(&Bidir_Type::front), "front");
m.add(fun(&Bidir_Type::pop_back), "pop_back");
m.add(fun(&Bidir_Type::back), "back");
}
/// Algorithm for inserting at a specific position into a container
@ -228,15 +169,20 @@ namespace chaiscript
std::advance(itr, pos);
container.erase(itr);
}
}
}
template<typename ContainerType>
ModulePtr input_range_type(const std::string &type, ModulePtr m = ModulePtr(new Module()))
void input_range_type(const std::string &type, Module& m)
{
detail::input_range_type_impl<Bidir_Range<ContainerType> >(type,m);
detail::input_range_type_impl<Const_Bidir_Range<ContainerType> >("Const_" + type, m);
detail::input_range_type_impl<Bidir_Range<ContainerType, typename ContainerType::iterator> >(type,m);
detail::input_range_type_impl<Bidir_Range<const ContainerType, typename ContainerType::const_iterator> >("Const_" + type,m);
}
template<typename ContainerType>
ModulePtr input_range_type(const std::string &type)
{
auto m = std::make_shared<Module>();
input_range_type<ContainerType>(type, *m);
return m;
}
@ -244,31 +190,83 @@ namespace chaiscript
/// Add random_access_container concept to the given ContainerType
/// http://www.sgi.com/tech/stl/RandomAccessContainer.html
template<typename ContainerType>
ModulePtr random_access_container_type(const std::string &/*type*/, ModulePtr m = ModulePtr(new Module()))
void random_access_container_type(const std::string &/*type*/, Module& m)
{
typedef typename ContainerType::reference(ContainerType::*indexoper)(size_t);
typedef typename ContainerType::const_reference(ContainerType::*constindexoper)(size_t) const;
//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)))), "[]");
m->add(
fun(std::function<typename ContainerType::const_reference (const ContainerType *, int)>
(std::mem_fn(static_cast<constindexoper>(&ContainerType::at)))), "[]");
m.add(
fun(
[](ContainerType &c, int index) -> typename ContainerType::reference {
/// \todo we are prefering to keep the key as 'int' to avoid runtime conversions
/// during dispatch. reevaluate
return c.at(static_cast<typename ContainerType::size_type>(index));
}), "[]");
m.add(
fun(
[](const ContainerType &c, int index) -> typename ContainerType::const_reference {
/// \todo we are prefering to keep the key as 'int' to avoid runtime conversions
/// during dispatch. reevaluate
return c.at(static_cast<typename ContainerType::size_type>(index));
}), "[]");
}
template<typename ContainerType>
ModulePtr random_access_container_type(const std::string &type)
{
auto m = std::make_shared<Module>();
random_access_container_type<ContainerType>(type, *m);
return m;
}
/// Add assignable concept to the given ContainerType
/// http://www.sgi.com/tech/stl/Assignable.html
template<typename ContainerType>
ModulePtr assignable_type(const std::string &type, ModulePtr m = ModulePtr(new Module()))
void assignable_type(const std::string &type, Module& m)
{
basic_constructors<ContainerType>(type, m);
copy_constructor<ContainerType>(type, m);
operators::assign<ContainerType>(m);
}
template<typename ContainerType>
ModulePtr assignable_type(const std::string &type)
{
auto m = std::make_shared<Module>();
assignable_type<ContainerType>(type, *m);
return m;
}
/// Add container resize concept to the given ContainerType
/// http://www.cplusplus.com/reference/stl/
template<typename ContainerType>
void resizable_type(const std::string &/*type*/, Module& m)
{
m.add(fun([](ContainerType *a, typename ContainerType::size_type n, const typename ContainerType::value_type& val) { return a->resize(n, val); } ), "resize");
m.add(fun([](ContainerType *a, typename ContainerType::size_type n) { return a->resize(n); } ), "resize");
}
template<typename ContainerType>
ModulePtr resizable_type(const std::string &type)
{
auto m = std::make_shared<Module>();
resizable_type<ContainerType>(type, *m);
return m;
}
/// Add container reserve concept to the given ContainerType
/// http://www.cplusplus.com/reference/stl/
template<typename ContainerType>
void reservable_type(const std::string &/*type*/, Module& m)
{
m.add(fun([](ContainerType *a, typename ContainerType::size_type n) { return a->reserve(n); } ), "reserve");
m.add(fun([](const ContainerType *a) { return a->capacity(); } ), "capacity");
}
template<typename ContainerType>
ModulePtr reservable_type(const std::string &type)
{
auto m = std::make_shared<Module>();
reservable_type<ContainerType>(type, *m);
return m;
}
@ -276,67 +274,102 @@ namespace chaiscript
/// Add container concept to the given ContainerType
/// http://www.sgi.com/tech/stl/Container.html
template<typename ContainerType>
ModulePtr container_type(const std::string &/*type*/, ModulePtr m = ModulePtr(new Module()))
void container_type(const std::string &/*type*/, Module& m)
{
m->add(fun( std::function<size_t (const ContainerType *)>( [](const ContainerType *a) { return a->size(); } ) ), "size");
m->add(fun( std::function<bool (const ContainerType *)>( [](const ContainerType *a) { return a->empty(); } ) ), "empty");
m->add(fun( std::function<void (ContainerType *)>( [](ContainerType *a) { a->clear(); } ) ), "clear");
return m;
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");
}
template <typename ContainerType>
ModulePtr container_type(const std::string& type)
{
auto m = std::make_shared<Module>();
container_type<ContainerType>(type, *m);
return m;
}
/// Add default constructable concept to the given Type
/// http://www.sgi.com/tech/stl/DefaultConstructible.html
template<typename Type>
ModulePtr default_constructible_type(const std::string &type, ModulePtr m = ModulePtr(new Module()))
void default_constructible_type(const std::string &type, Module& m)
{
m->add(constructor<Type ()>(), type);
m.add(constructor<Type ()>(), type);
}
template <typename Type>
ModulePtr default_constructible_type(const std::string& type)
{
auto m = std::make_shared<Module>();
default_constructible_type<Type>(type, *m);
return m;
}
/// Add sequence concept to the given ContainerType
/// http://www.sgi.com/tech/stl/Sequence.html
template<typename ContainerType>
ModulePtr sequence_type(const std::string &/*type*/, ModulePtr m = ModulePtr(new Module()))
void sequence_type(const std::string &/*type*/, Module& m)
{
std::string insert_name;
if (typeid(typename ContainerType::value_type) == typeid(Boxed_Value))
{
insert_name = "insert_ref_at";
} else {
insert_name = "insert_at";
}
m->add(fun(&detail::insert_at<ContainerType>), insert_name);
m->add(fun(&detail::erase_at<ContainerType>), "erase_at");
m.add(fun(&detail::insert_at<ContainerType>),
[]()->std::string{
if (typeid(typename ContainerType::value_type) == typeid(Boxed_Value)) {
return "insert_ref_at";
} else {
return "insert_at";
}
}());
m.add(fun(&detail::erase_at<ContainerType>), "erase_at");
}
template <typename ContainerType>
ModulePtr sequence_type(const std::string &type)
{
auto m = std::make_shared<Module>();
sequence_type<ContainerType>(type, *m);
return m;
}
/// Add back insertion sequence concept to the given ContainerType
/// http://www.sgi.com/tech/stl/BackInsertionSequence.html
template<typename ContainerType>
ModulePtr back_insertion_sequence_type(const std::string &/*type*/, ModulePtr m = ModulePtr(new Module()))
void back_insertion_sequence_type(const std::string &type, Module& m)
{
typedef typename ContainerType::reference (ContainerType::*backptr)();
m->add(fun(static_cast<backptr>(&ContainerType::back)), "back");
m.add(fun(static_cast<backptr>(&ContainerType::back)), "back");
std::string push_back_name;
if (typeid(typename ContainerType::value_type) == typeid(Boxed_Value))
{
push_back_name = "push_back_ref";
} else {
push_back_name = "push_back";
}
typedef void (ContainerType::*push_back)(const typename ContainerType::value_type &);
m->add(fun(static_cast<push_back>(&ContainerType::push_back)), push_back_name);
m->add(fun(&ContainerType::pop_back), "pop_back");
m.add(fun(static_cast<push_back>(&ContainerType::push_back)),
[&]()->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";
}
}());
m.add(fun(&ContainerType::pop_back), "pop_back");
}
template<typename ContainerType>
ModulePtr back_insertion_sequence_type(const std::string &type)
{
auto m = std::make_shared<Module>();
back_insertion_sequence_type<ContainerType>(type, *m);
return m;
}
@ -345,26 +378,44 @@ 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 = ModulePtr(new Module()))
void front_insertion_sequence_type(const std::string &type, Module& m)
{
typedef typename ContainerType::reference (ContainerType::*frontptr)();
typedef typename ContainerType::const_reference (ContainerType::*constfrontptr)() const;
typedef void (ContainerType::*pushptr)(typename ContainerType::const_reference);
typedef void (ContainerType::*popptr)();
typedef typename ContainerType::reference (ContainerType::*front_ptr)();
typedef typename ContainerType::const_reference (ContainerType::*const_front_ptr)() const;
typedef void (ContainerType::*push_ptr)(typename ContainerType::const_reference);
typedef void (ContainerType::*pop_ptr)();
m->add(fun(static_cast<frontptr>(&ContainerType::front)), "front");
m->add(fun(static_cast<constfrontptr>(&ContainerType::front)), "front");
m.add(fun(static_cast<front_ptr>(&ContainerType::front)), "front");
m.add(fun(static_cast<const_front_ptr>(&ContainerType::front)), "front");
std::string push_front_name;
if (typeid(typename ContainerType::value_type) == typeid(Boxed_Value))
{
push_front_name = "push_front_ref";
} else {
push_front_name = "push_front";
}
m.add(fun(static_cast<push_ptr>(&ContainerType::push_front)),
[&]()->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";
}
}());
m->add(fun(static_cast<pushptr>(&ContainerType::push_front)), push_front_name);
m->add(fun(static_cast<popptr>(&ContainerType::pop_front)), "pop_front");
m.add(fun(static_cast<pop_ptr>(&ContainerType::pop_front)), "pop_front");
}
template<typename ContainerType>
ModulePtr front_insertion_sequence_type(const std::string &type)
{
auto m = std::make_shared<Module>();
front_insertion_sequence_type<ContainerType>(type, *m);
return m;
}
@ -372,20 +423,21 @@ namespace chaiscript
/// bootstrap a given PairType
/// http://www.sgi.com/tech/stl/pair.html
template<typename PairType>
ModulePtr pair_type(const std::string &type, ModulePtr m = ModulePtr(new Module()))
void pair_type(const std::string &type, Module& m)
{
m->add(user_type<PairType>(), type);
m.add(user_type<PairType>(), type);
typename PairType::first_type PairType::* f = &PairType::first;
typename PairType::second_type PairType::* s = &PairType::second;
m->add(fun(f), "first");
m->add(fun(s), "second");
m.add(fun(&PairType::first), "first");
m.add(fun(&PairType::second), "second");
basic_constructors<PairType>(type, m);
m->add(constructor<PairType (const typename PairType::first_type &, const typename PairType::second_type &)>(), type);
m.add(constructor<PairType (const typename PairType::first_type &, const typename PairType::second_type &)>(), type);
}
template<typename PairType>
ModulePtr pair_type(const std::string &type)
{
auto m = std::make_shared<Module>();
pair_type<PairType>(type, *m);
return m;
}
@ -395,10 +447,15 @@ namespace chaiscript
/// http://www.sgi.com/tech/stl/PairAssociativeContainer.html
template<typename ContainerType>
ModulePtr pair_associative_container_type(const std::string &type, ModulePtr m = ModulePtr(new Module()))
void pair_associative_container_type(const std::string &type, Module& m)
{
pair_type<typename ContainerType::value_type>(type + "_Pair", m);
}
template<typename ContainerType>
ModulePtr pair_associative_container_type(const std::string &type)
{
auto m = std::make_shared<Module>();
pair_associative_container_type<ContainerType>(type, *m);
return m;
}
@ -406,25 +463,30 @@ namespace chaiscript
/// Add unique associative container concept to the given ContainerType
/// http://www.sgi.com/tech/stl/UniqueAssociativeContainer.html
template<typename ContainerType>
ModulePtr unique_associative_container_type(const std::string &/*type*/, ModulePtr m = ModulePtr(new Module()))
void unique_associative_container_type(const std::string &/*type*/, Module& m)
{
m->add(fun(detail::count<ContainerType>), "count");
m.add(fun(detail::count<ContainerType>), "count");
typedef size_t (ContainerType::*erase_ptr)(const typename ContainerType::key_type &);
m->add(fun(static_cast<erase_ptr>(&ContainerType::erase)), "erase");
m.add(fun(static_cast<erase_ptr>(&ContainerType::erase)), "erase");
m->add(fun(&detail::insert<ContainerType>), "insert");
m.add(fun(&detail::insert<ContainerType>), "insert");
std::string insert_name;
if (typeid(typename ContainerType::mapped_type) == typeid(Boxed_Value))
{
insert_name = "insert_ref";
} else {
insert_name = "insert";
}
m->add(fun(&detail::insert_ref<ContainerType>), insert_name);
m.add(fun(&detail::insert_ref<ContainerType>),
[]()->std::string{
if (typeid(typename ContainerType::mapped_type) == typeid(Boxed_Value)) {
return "insert_ref";
} else {
return "insert";
}
}());
}
template<typename ContainerType>
ModulePtr unique_associative_container_type(const std::string &type)
{
auto m = std::make_shared<Module>();
unique_associative_container_type<ContainerType>(type, *m);
return m;
}
@ -432,39 +494,78 @@ namespace chaiscript
/// Add a MapType container
/// http://www.sgi.com/tech/stl/Map.html
template<typename MapType>
ModulePtr map_type(const std::string &type, ModulePtr m = ModulePtr(new Module()))
void map_type(const std::string &type, Module& m)
{
m->add(user_type<MapType>(), type);
m.add(user_type<MapType>(), type);
typedef typename MapType::mapped_type &(MapType::*elemaccess)(const typename MapType::key_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<elemaccess>(&MapType::operator[])), "[]");
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);
unique_associative_container_type<MapType>(type, m);
pair_associative_container_type<MapType>(type, m);
input_range_type<MapType>(type, m);
}
template<typename MapType>
ModulePtr map_type(const std::string &type)
{
auto m = std::make_shared<Module>();
map_type<MapType>(type, *m);
return m;
}
/// hopefully working List type
/// http://www.sgi.com/tech/stl/List.html
template<typename ListType>
ModulePtr list_type(const std::string &type, ModulePtr m = ModulePtr(new Module()))
void list_type(const std::string &type, Module& m)
{
m->add(user_type<ListType>(), type);
m.add(user_type<ListType>(), type);
front_insertion_sequence_type<ListType>(type, m);
back_insertion_sequence_type<ListType>(type, m);
sequence_type<ListType>(type, m);
resizable_type<ListType>(type, m);
container_type<ListType>(type, m);
default_constructible_type<ListType>(type, m);
assignable_type<ListType>(type, m);
input_range_type<ListType>(type, m);
}
template<typename ListType>
ModulePtr list_type(const std::string &type)
{
auto m = std::make_shared<Module>();
list_type<ListType>(type, m);
return m;
}
@ -472,20 +573,22 @@ namespace chaiscript
/// Create a vector type with associated concepts
/// http://www.sgi.com/tech/stl/Vector.html
template<typename VectorType>
ModulePtr vector_type(const std::string &type, ModulePtr m = ModulePtr(new Module()))
void vector_type(const std::string &type, Module& m)
{
m->add(user_type<VectorType>(), type);
m.add(user_type<VectorType>(), type);
typedef typename VectorType::reference (VectorType::*frontptr)();
typedef typename VectorType::const_reference (VectorType::*constfrontptr)() const;
m->add(fun(static_cast<frontptr>(&VectorType::front)), "front");
m->add(fun(static_cast<constfrontptr>(&VectorType::front)), "front");
m.add(fun(static_cast<frontptr>(&VectorType::front)), "front");
m.add(fun(static_cast<constfrontptr>(&VectorType::front)), "front");
back_insertion_sequence_type<VectorType>(type, m);
sequence_type<VectorType>(type, m);
random_access_container_type<VectorType>(type, m);
resizable_type<VectorType>(type, m);
reservable_type<VectorType>(type, m);
container_type<VectorType>(type, m);
default_constructible_type<VectorType>(type, m);
assignable_type<VectorType>(type, m);
@ -493,35 +596,42 @@ namespace chaiscript
if (typeid(VectorType) == typeid(std::vector<Boxed_Value>))
{
m->eval("def Vector::`==`(rhs) : type_match(rhs, this) { \
if ( rhs.size() != this.size() ) { \
return false; \
} else { \
auto r1 = range(this); \
auto r2 = range(rhs); \
while (!r1.empty()) \
{ \
if (!eq(r1.front(), r2.front())) \
{ \
return false; \
} \
r1.pop_front(); \
r2.pop_front(); \
} \
return true; \
} \
}");
m.eval(R"(
def Vector::`==`(Vector rhs) {
if ( rhs.size() != this.size() ) {
return false;
} else {
auto r1 = range(this);
auto r2 = range(rhs);
while (!r1.empty())
{
if (!eq(r1.front(), r2.front()))
{
return false;
}
r1.pop_front();
r2.pop_front();
}
true;
}
} )"
);
}
}
template<typename VectorType>
ModulePtr vector_type(const std::string &type)
{
auto m = std::make_shared<Module>();
vector_type<VectorType>(type, *m);
return m;
}
/// Add a String container
/// http://www.sgi.com/tech/stl/basic_string.html
template<typename String>
ModulePtr string_type(const std::string &type, ModulePtr m = ModulePtr(new Module()))
void string_type(const std::string &type, Module& m)
{
m->add(user_type<String>(), type);
m.add(user_type<String>(), type);
operators::addition<String>(m);
operators::assign_sum<String>(m);
opers_comparison<String>(m);
@ -533,33 +643,57 @@ namespace chaiscript
input_range_type<String>(type, m);
//Special case: add push_back to string (which doesn't support other back_insertion operations
std::string push_back_name;
if (typeid(typename String::value_type) == typeid(Boxed_Value))
{
push_back_name = "push_back_ref";
} else {
push_back_name = "push_back";
}
m->add(fun(&String::push_back), push_back_name);
typedef std::function<size_t (const String *, const String &, size_t)> find_func;
m.add(fun(&String::push_back),
[]()->std::string{
if (typeid(typename String::value_type) == typeid(Boxed_Value)) {
return "push_back_ref";
} else {
return "push_back";
}
}());
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([](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( 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([](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( 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");
}
template<typename String>
ModulePtr string_type(const std::string &type)
{
auto m = std::make_shared<Module>();
string_type<String>(type, *m);
return m;
}
/// Add a MapType container
/// http://www.sgi.com/tech/stl/Map.html
template<typename FutureType>
void future_type(const std::string &type, Module& m)
{
m.add(user_type<FutureType>(), type);
m.add(fun([](const FutureType &t) { return t.valid(); }), "valid");
m.add(fun(&FutureType::get), "get");
m.add(fun(&FutureType::wait), "wait");
}
template<typename FutureType>
ModulePtr future_type(const std::string &type)
{
auto m = std::make_shared<Module>();
future_type<FutureType>(type, *m);
return m;
}
}

View File

@ -1,24 +1,25 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_BOXED_CAST_HPP_
#define CHAISCRIPT_BOXED_CAST_HPP_
#include <type_traits>
#include "../chaiscript_defines.hpp"
#include "../chaiscript_threading.hpp"
#include "bad_boxed_cast.hpp"
#include "boxed_cast_helper.hpp"
#include "boxed_value.hpp"
#include "dynamic_cast_conversion.hpp"
#include "type_conversions.hpp"
#include "type_info.hpp"
namespace chaiscript {
class Dynamic_Cast_Conversions;
class Type_Conversions;
namespace detail {
namespace exception {
class bad_any_cast;
@ -72,48 +73,36 @@ namespace chaiscript
/// assert(i == 5);
/// \endcode
template<typename Type>
typename detail::Cast_Helper<Type>::Result_Type boxed_cast(const Boxed_Value &bv, const Dynamic_Cast_Conversions *t_conversions = nullptr)
decltype(auto) boxed_cast(const Boxed_Value &bv, const Type_Conversions_State *t_conversions = nullptr)
{
try {
return detail::Cast_Helper<Type>::cast(bv, t_conversions);
} catch (const chaiscript::detail::exception::bad_any_cast &) {
#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 (std::is_polymorphic<typename detail::Bare_Type<Type>::type>::value && t_conversions)
{
try {
// std::cout << "trying an up conversion " << typeid(Type).name() << std::endl;
// We will not catch any bad_boxed_dynamic_cast that is thrown, let the user get it
// either way, we are not responsible if it doesn't work
return detail::Cast_Helper<Type>::cast(t_conversions->boxed_dynamic_cast<Type>(bv), t_conversions);
} catch (...) {
try {
// std::cout << "trying a down conversion " << typeid(Type).name() << std::endl;
// try going the other way - down the inheritance graph
return detail::Cast_Helper<Type>::cast(t_conversions->boxed_dynamic_down_cast<Type>(bv), t_conversions);
} catch (const chaiscript::detail::exception::bad_any_cast &) {
throw exception::bad_boxed_cast(bv.get_type_info(), typeid(Type));
}
}
} else {
// If it's not polymorphic, just throw the error, don't waste the time on the
// attempted dynamic_cast
throw exception::bad_boxed_cast(bv.get_type_info(), typeid(Type));
if (!t_conversions || bv.get_type_info().bare_equal(user_type<Type>()) || (t_conversions && !(*t_conversions)->convertable_type<Type>())) {
try {
return(detail::Cast_Helper<Type>::cast(bv, t_conversions));
} catch (const chaiscript::detail::exception::bad_any_cast &) {
}
#ifdef CHAISCRIPT_MSVC
#pragma warning(pop)
#endif
}
}
if (t_conversions && (*t_conversions)->convertable_type<Type>())
{
try {
// We will not catch any bad_boxed_dynamic_cast that is thrown, let the user get it
// either way, we are not responsible if it doesn't work
return(detail::Cast_Helper<Type>::cast((*t_conversions)->boxed_type_conversion<Type>(t_conversions->saves(), bv), t_conversions));
} catch (...) {
try {
// try going the other way
return(detail::Cast_Helper<Type>::cast((*t_conversions)->boxed_type_down_conversion<Type>(t_conversions->saves(), bv), t_conversions));
} catch (const chaiscript::detail::exception::bad_any_cast &) {
throw exception::bad_boxed_cast(bv.get_type_info(), typeid(Type));
}
}
} else {
// If it's not convertable, just throw the error, don't waste the time on the
// attempted dynamic_cast
throw exception::bad_boxed_cast(bv.get_type_info(), typeid(Type));
}
}
}

View File

@ -1,13 +1,16 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_BOXED_CAST_HELPER_HPP_
#define CHAISCRIPT_BOXED_CAST_HELPER_HPP_
#include <functional>
#include <memory>
#include <type_traits>
@ -17,7 +20,7 @@
namespace chaiscript
{
class Dynamic_Cast_Conversions;
class Type_Conversions_State;
namespace detail
{
@ -26,24 +29,54 @@ namespace chaiscript
template<typename T>
T* throw_if_null(T *t)
{
if (t) return t;
if (t) { return t; }
throw std::runtime_error("Attempted to dereference null Boxed_Value");
}
template<typename T>
static const T *verify_type_no_throw(const Boxed_Value &ob, const std::type_info &ti, const T *ptr) {
if (ob.get_type_info() == ti) {
return ptr;
} else {
throw chaiscript::detail::exception::bad_any_cast();
}
}
template<typename T>
static T *verify_type_no_throw(const Boxed_Value &ob, const std::type_info &ti, T *ptr) {
if (!ob.is_const() && ob.get_type_info() == ti) {
return ptr;
} else {
throw chaiscript::detail::exception::bad_any_cast();
}
}
template<typename T>
static const T *verify_type(const Boxed_Value &ob, const std::type_info &ti, const T *ptr) {
if (ob.get_type_info().bare_equal_type_info(ti)) {
return throw_if_null(ptr);
} else {
throw chaiscript::detail::exception::bad_any_cast();
}
}
template<typename T>
static T *verify_type(const Boxed_Value &ob, const std::type_info &ti, T *ptr) {
if (!ob.is_const() && ob.get_type_info().bare_equal_type_info(ti)) {
return throw_if_null(ptr);
} else {
throw chaiscript::detail::exception::bad_any_cast();
}
}
/// Generic Cast_Helper_Inner, for casting to any type
template<typename Result>
struct Cast_Helper_Inner
{
typedef typename std::reference_wrapper<typename std::add_const<Result>::type > Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *)
static Result cast(const Boxed_Value &ob, const Type_Conversions_State *)
{
if (ob.get_type_info().bare_equal_type_info(typeid(Result)))
{
return *(static_cast<const Result *>(throw_if_null(ob.get_const_ptr())));
} else {
throw chaiscript::detail::exception::bad_any_cast();
}
return *static_cast<const Result *>(verify_type(ob, typeid(Result), ob.get_const_ptr()));
}
};
@ -52,35 +85,14 @@ namespace chaiscript
{
};
/// Cast_Helper_Inner for casting to a const & type
template<typename Result>
struct Cast_Helper_Inner<const Result &> : Cast_Helper_Inner<Result>
{
};
/// Cast_Helper_Inner for casting to a const * type
template<typename Result>
struct Cast_Helper_Inner<const Result *>
{
typedef const Result * Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *)
static const Result * cast(const Boxed_Value &ob, const Type_Conversions_State *)
{
if (ob.is_ref())
{
if (!ob.get_type_info().is_const())
{
return &(ob.get().cast<std::reference_wrapper<Result> >()).get();
} else {
return &(ob.get().cast<std::reference_wrapper<const Result> >()).get();
}
} else {
if (!ob.get_type_info().is_const())
{
return (ob.get().cast<std::shared_ptr<Result> >()).get();
} else {
return (ob.get().cast<std::shared_ptr<const Result> >()).get();
}
}
return static_cast<const Result *>(verify_type_no_throw(ob, typeid(Result), ob.get_const_ptr()));
}
};
@ -88,43 +100,94 @@ namespace chaiscript
template<typename Result>
struct Cast_Helper_Inner<Result *>
{
typedef Result * Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *)
static Result * cast(const Boxed_Value &ob, const Type_Conversions_State *)
{
if (ob.is_ref())
{
return &(ob.get().cast<std::reference_wrapper<Result> >()).get();
} else {
return (ob.get().cast<std::shared_ptr<Result> >()).get();
}
return static_cast<Result *>(verify_type_no_throw(ob, typeid(Result), ob.get_ptr()));
}
};
template<typename Result>
struct Cast_Helper_Inner<Result * const &> : public Cast_Helper_Inner<Result *>
{
};
template<typename Result>
struct Cast_Helper_Inner<const Result * const &> : public Cast_Helper_Inner<const Result *>
{
};
/// Cast_Helper_Inner for casting to a & type
template<typename Result>
struct Cast_Helper_Inner<const Result &>
{
static const Result & cast(const Boxed_Value &ob, const Type_Conversions_State *)
{
return *static_cast<const Result *>(verify_type(ob, typeid(Result), ob.get_const_ptr()));
}
};
/// Cast_Helper_Inner for casting to a & type
template<typename Result>
struct Cast_Helper_Inner<Result &>
{
typedef Result& Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *)
static Result& cast(const Boxed_Value &ob, const Type_Conversions_State *)
{
if (!ob.get_type_info().is_const() && ob.get_type_info().bare_equal_type_info(typeid(Result)))
{
return *(static_cast<Result *>(throw_if_null(ob.get_ptr())));
} else {
throw chaiscript::detail::exception::bad_any_cast();
}
return *static_cast<Result *>(verify_type(ob, typeid(Result), ob.get_ptr()));
}
};
/// Cast_Helper_Inner for casting to a && type
template<typename Result>
struct Cast_Helper_Inner<Result &&>
{
static Result&& cast(const Boxed_Value &ob, const Type_Conversions_State *)
{
return std::move(*static_cast<Result *>(verify_type(ob, typeid(Result), ob.get_ptr())));
}
};
/// Cast_Helper_Inner for casting to a std::unique_ptr<> && type
/// \todo Fix the fact that this has to be in a shared_ptr for now
template<typename Result>
struct Cast_Helper_Inner<std::unique_ptr<Result> &&>
{
static std::unique_ptr<Result> &&cast(const Boxed_Value &ob, const Type_Conversions_State *)
{
return std::move(*(ob.get().cast<std::shared_ptr<std::unique_ptr<Result>>>()));
}
};
/// Cast_Helper_Inner for casting to a std::unique_ptr<> & type
/// \todo Fix the fact that this has to be in a shared_ptr for now
template<typename Result>
struct Cast_Helper_Inner<std::unique_ptr<Result> &>
{
static std::unique_ptr<Result> &cast(const Boxed_Value &ob, const Type_Conversions_State *)
{
return *(ob.get().cast<std::shared_ptr<std::unique_ptr<Result>>>());
}
};
/// Cast_Helper_Inner for casting to a std::unique_ptr<> & type
/// \todo Fix the fact that this has to be in a shared_ptr for now
template<typename Result>
struct Cast_Helper_Inner<const std::unique_ptr<Result> &>
{
static std::unique_ptr<Result> &cast(const Boxed_Value &ob, const Type_Conversions_State *)
{
return *(ob.get().cast<std::shared_ptr<std::unique_ptr<Result>>>());
}
};
/// Cast_Helper_Inner for casting to a std::shared_ptr<> type
template<typename Result>
struct Cast_Helper_Inner<typename std::shared_ptr<Result> >
struct Cast_Helper_Inner<std::shared_ptr<Result> >
{
typedef typename std::shared_ptr<Result> Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *)
static auto cast(const Boxed_Value &ob, const Type_Conversions_State *)
{
return ob.get().cast<std::shared_ptr<Result> >();
}
@ -132,11 +195,9 @@ namespace chaiscript
/// Cast_Helper_Inner for casting to a std::shared_ptr<const> type
template<typename Result>
struct Cast_Helper_Inner<typename std::shared_ptr<const Result> >
struct Cast_Helper_Inner<std::shared_ptr<const Result> >
{
typedef typename std::shared_ptr<const Result> Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *)
static auto cast(const Boxed_Value &ob, const Type_Conversions_State *)
{
if (!ob.get_type_info().is_const())
{
@ -158,6 +219,17 @@ namespace chaiscript
{
};
template<typename Result>
struct Cast_Helper_Inner<std::shared_ptr<Result> &>
{
static_assert(!std::is_const<Result>::value, "Non-const reference to std::shared_ptr<const T> is not supported");
static auto cast(const Boxed_Value &ob, const Type_Conversions_State *)
{
std::shared_ptr<Result> &res = ob.get().cast<std::shared_ptr<Result> >();
return ob.pointer_sentinel(res);
}
};
/// Cast_Helper_Inner for casting to a const std::shared_ptr<const> & type
template<typename Result>
@ -171,14 +243,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;
static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *)
static Boxed_Value cast(const Boxed_Value &ob, const Type_Conversions_State *)
{
return ob;
}
@ -188,11 +257,9 @@ namespace chaiscript
template<>
struct Cast_Helper_Inner<Boxed_Value &>
{
typedef Boxed_Value& Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *)
static std::reference_wrapper<Boxed_Value> cast(const Boxed_Value &ob, const Type_Conversions_State *)
{
return const_cast<Boxed_Value &>(ob);
return std::ref(const_cast<Boxed_Value &>(ob));
}
};
@ -244,11 +311,9 @@ namespace chaiscript
template<typename T>
struct Cast_Helper
{
typedef typename Cast_Helper_Inner<T>::Result_Type Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *t_conversions)
static decltype(auto) cast(const Boxed_Value &ob, const Type_Conversions_State *t_conversions)
{
return Cast_Helper_Inner<T>::cast(ob, t_conversions);
return(Cast_Helper_Inner<T>::cast(ob, t_conversions));
}
};
}

File diff suppressed because it is too large Load Diff

View File

@ -1,18 +1,21 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_BOXED_VALUE_HPP_
#define CHAISCRIPT_BOXED_VALUE_HPP_
#include <functional>
#include <map>
#include <memory>
#include <type_traits>
#include "../chaiscript_threading.hpp"
#include "../chaiscript_defines.hpp"
#include "any.hpp"
#include "type_info.hpp"
@ -36,10 +39,11 @@ namespace chaiscript
{
Data(const Type_Info &ti,
chaiscript::detail::Any to,
bool tr,
const void *t_void_ptr)
bool is_ref,
const void *t_void_ptr,
bool t_return_value)
: m_type_info(ti), m_obj(std::move(to)), m_data_ptr(ti.is_const()?nullptr:const_cast<void *>(t_void_ptr)), m_const_data_ptr(t_void_ptr),
m_is_ref(tr)
m_is_ref(is_ref), m_return_value(t_return_value)
{
}
@ -50,10 +54,11 @@ namespace chaiscript
m_is_ref = rhs.m_is_ref;
m_data_ptr = rhs.m_data_ptr;
m_const_data_ptr = rhs.m_const_data_ptr;
m_return_value = rhs.m_return_value;
if (rhs.m_attrs)
{
m_attrs = std::unique_ptr<std::map<std::string, Boxed_Value>>(new std::map<std::string, Boxed_Value>(*rhs.m_attrs));
m_attrs = std::make_unique<std::map<std::string, std::shared_ptr<Data>>>(*rhs.m_attrs);
}
return *this;
@ -61,80 +66,106 @@ namespace chaiscript
Data(const Data &) = delete;
#if !defined(__APPLE__) && (!defined(_MSC_VER) || _MSC_VER != 1800)
Data(Data &&) = default;
Data &operator=(Data &&rhs) = default;
#endif
Type_Info m_type_info;
chaiscript::detail::Any m_obj;
void *m_data_ptr;
const void *m_const_data_ptr;
std::unique_ptr<std::map<std::string, std::shared_ptr<Data>>> m_attrs;
bool m_is_ref;
std::unique_ptr<std::map<std::string, Boxed_Value>> m_attrs;
bool m_return_value;
};
struct Object_Data
{
static std::shared_ptr<Data> get(Boxed_Value::Void_Type)
static auto get(Boxed_Value::Void_Type, bool t_return_value)
{
return std::make_shared<Data>(
detail::Get_Type_Info<void>::get(),
chaiscript::detail::Any(),
false,
nullptr)
nullptr,
t_return_value)
;
}
template<typename T>
static std::shared_ptr<Data> get(const std::shared_ptr<T> *obj)
static auto get(const std::shared_ptr<T> *obj, bool t_return_value)
{
return get(*obj);
return get(*obj, t_return_value);
}
template<typename T>
static std::shared_ptr<Data> get(const std::shared_ptr<T> &obj)
static auto get(const std::shared_ptr<T> &obj, bool t_return_value)
{
return std::make_shared<Data>(
detail::Get_Type_Info<T>::get(),
chaiscript::detail::Any(obj),
false,
obj.get()
obj.get(),
t_return_value
);
}
template<typename T>
static std::shared_ptr<Data> get(std::shared_ptr<T> &&obj)
static auto get(std::shared_ptr<T> &&obj, bool t_return_value)
{
auto ptr = obj.get();
return std::make_shared<Data>(
detail::Get_Type_Info<T>::get(),
chaiscript::detail::Any(std::move(obj)),
false,
ptr
ptr,
t_return_value
);
}
template<typename T>
static std::shared_ptr<Data> get(T *t)
static auto get(T *t, bool t_return_value)
{
return get(std::ref(*t));
return get(std::ref(*t), t_return_value);
}
template<typename T>
static std::shared_ptr<Data> get(std::reference_wrapper<T> obj)
static auto get(const T *t, bool t_return_value)
{
return get(std::cref(*t), t_return_value);
}
template<typename T>
static auto get(std::reference_wrapper<T> obj, bool t_return_value)
{
auto p = &obj.get();
return std::make_shared<Data>(
detail::Get_Type_Info<T>::get(),
chaiscript::detail::Any(std::move(obj)),
true,
p
p,
t_return_value
);
}
template<typename T>
static std::shared_ptr<Data> get(T t)
static auto get(std::unique_ptr<T> &&obj, bool t_return_value)
{
auto ptr = obj.get();
return std::make_shared<Data>(
detail::Get_Type_Info<T>::get(),
chaiscript::detail::Any(std::make_shared<std::unique_ptr<T>>(std::move(obj))),
true,
ptr,
t_return_value
);
}
template<typename T>
static auto get(T t, bool t_return_value)
{
auto p = std::make_shared<T>(std::move(t));
auto ptr = p.get();
@ -142,7 +173,8 @@ namespace chaiscript
detail::Get_Type_Info<T>::get(),
chaiscript::detail::Any(std::move(p)),
false,
ptr
ptr,
t_return_value
);
}
@ -152,7 +184,8 @@ namespace chaiscript
Type_Info(),
chaiscript::detail::Any(),
false,
nullptr
nullptr,
false
);
}
@ -162,22 +195,16 @@ namespace chaiscript
/// Basic Boxed_Value constructor
template<typename T,
typename = typename std::enable_if<!std::is_same<Boxed_Value, typename std::decay<T>::type>::value>::type>
explicit Boxed_Value(T &&t)
: m_data(Object_Data::get(std::forward<T>(t)))
explicit Boxed_Value(T &&t, bool t_return_value = false)
: m_data(Object_Data::get(std::forward<T>(t), t_return_value))
{
}
/// Unknown-type constructor
Boxed_Value()
: m_data(Object_Data::get())
{
}
Boxed_Value() = default;
#if !defined(_MSC_VER) || _MSC_VER != 1800
Boxed_Value(Boxed_Value&&) = default;
Boxed_Value& operator=(Boxed_Value&&) = default;
#endif
Boxed_Value(const Boxed_Value&) = default;
Boxed_Value& operator=(const Boxed_Value&) = default;
@ -194,53 +221,99 @@ namespace chaiscript
return *this;
}
const Type_Info &get_type_info() const CHAISCRIPT_NOEXCEPT
const Type_Info &get_type_info() const noexcept
{
return m_data->m_type_info;
}
/// return true if the object is uninitialized
bool is_undef() const CHAISCRIPT_NOEXCEPT
bool is_undef() const noexcept
{
return m_data->m_type_info.is_undef();
}
bool is_const() const CHAISCRIPT_NOEXCEPT
bool is_const() const noexcept
{
return m_data->m_type_info.is_const();
}
bool is_type(const Type_Info &ti) const CHAISCRIPT_NOEXCEPT
bool is_type(const Type_Info &ti) const noexcept
{
return m_data->m_type_info.bare_equal(ti);
}
bool is_null() const CHAISCRIPT_NOEXCEPT
template<typename T>
auto pointer_sentinel(std::shared_ptr<T> &ptr) const
{
struct Sentinel {
Sentinel(std::shared_ptr<T> &t_ptr, Data &data)
: m_ptr(t_ptr), m_data(data)
{
}
~Sentinel()
{
// save new pointer data
const auto ptr_ = m_ptr.get().get();
m_data.get().m_data_ptr = ptr_;
m_data.get().m_const_data_ptr = ptr_;
}
Sentinel& operator=(Sentinel&&s) = default;
Sentinel(Sentinel &&s) = default;
operator std::shared_ptr<T>&() const
{
return m_ptr.get();
}
Sentinel &operator=(const Sentinel &) = delete;
Sentinel(Sentinel&) = delete;
std::reference_wrapper<std::shared_ptr<T>> m_ptr;
std::reference_wrapper<Data> m_data;
};
return Sentinel(ptr, *(m_data.get()));
}
bool is_null() const noexcept
{
return (m_data->m_data_ptr == nullptr && m_data->m_const_data_ptr == nullptr);
}
const chaiscript::detail::Any & get() const CHAISCRIPT_NOEXCEPT
const chaiscript::detail::Any & get() const noexcept
{
return m_data->m_obj;
}
bool is_ref() const CHAISCRIPT_NOEXCEPT
bool is_ref() const noexcept
{
return m_data->m_is_ref;
}
bool is_pointer() const CHAISCRIPT_NOEXCEPT
bool is_return_value() const noexcept
{
return m_data->m_return_value;
}
void reset_return_value() const noexcept
{
m_data->m_return_value = false;
}
bool is_pointer() const noexcept
{
return !is_ref();
}
void *get_ptr() const CHAISCRIPT_NOEXCEPT
void *get_ptr() const noexcept
{
return m_data->m_data_ptr;
}
const void *get_const_ptr() const CHAISCRIPT_NOEXCEPT
const void *get_const_ptr() const noexcept
{
return m_data->m_const_data_ptr;
}
@ -249,30 +322,51 @@ namespace chaiscript
{
if (!m_data->m_attrs)
{
m_data->m_attrs = std::unique_ptr<std::map<std::string, Boxed_Value>>(new std::map<std::string, Boxed_Value>());
m_data->m_attrs = std::make_unique<std::map<std::string, std::shared_ptr<Data>>>();
}
return (*m_data->m_attrs)[t_name];
auto &attr = (*m_data->m_attrs)[t_name];
if (attr) {
return Boxed_Value(attr, Internal_Construction());
} else {
Boxed_Value bv; //default construct a new one
attr = bv.m_data;
return bv;
}
}
Boxed_Value &copy_attrs(const Boxed_Value &t_obj)
{
if (t_obj.m_data->m_attrs)
{
m_data->m_attrs = std::unique_ptr<std::map<std::string, Boxed_Value>>(new std::map<std::string, Boxed_Value>(*t_obj.m_data->m_attrs));
m_data->m_attrs = std::make_unique<std::map<std::string, std::shared_ptr<Data>>>(*t_obj.m_data->m_attrs);
}
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
static bool type_match(const Boxed_Value &l, const Boxed_Value &r) noexcept
{
return l.get_type_info() == r.get_type_info();
}
private:
std::shared_ptr<Data> m_data;
// necessary to avoid hitting the templated && constructor of Boxed_Value
struct Internal_Construction{};
Boxed_Value(std::shared_ptr<Data> t_data, Internal_Construction)
: m_data(std::move(t_data)) {
}
std::shared_ptr<Data> m_data = Object_Data::get();
};
/// @brief Creates a Boxed_Value. If the object passed in is a value type, it is copied. If it is a pointer, std::shared_ptr, or std::reference_type
@ -290,9 +384,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 {
@ -369,7 +463,21 @@ namespace chaiscript
return detail::const_var_impl(t);
}
inline Boxed_Value void_var() {
static const auto v = Boxed_Value(Boxed_Value::Void_Type());
return v;
}
inline Boxed_Value const_var(bool b) {
static const auto t = detail::const_var_impl(true);
static const auto f = detail::const_var_impl(false);
if (b) {
return t;
} else {
return f;
}
}
}

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-2017, 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
{
explicit 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
{
explicit 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
{
explicit 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

File diff suppressed because it is too large Load Diff

View File

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

View File

@ -1,29 +1,24 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_DYNAMIC_OBJECT_HPP_
#define CHAISCRIPT_DYNAMIC_OBJECT_HPP_
#include <cassert>
#include <map>
#include <memory>
#include <string>
#include <typeinfo>
#include <utility>
#include <vector>
#include "../chaiscript_defines.hpp"
#include "boxed_cast.hpp"
#include "boxed_cast_helper.hpp"
#include "boxed_value.hpp"
#include "proxy_functions.hpp"
#include "type_info.hpp"
namespace chaiscript {
class Dynamic_Cast_Conversions;
class Type_Conversions;
namespace dispatch {
class Proxy_Function_Base;
} // namespace dispatch
@ -33,263 +28,103 @@ namespace chaiscript
{
namespace dispatch
{
struct option_explicit_set : std::runtime_error {
explicit option_explicit_set(const std::string &t_param_name)
: std::runtime_error("option explicit set and parameter '" + t_param_name + "' does not exist")
{
}
option_explicit_set(const option_explicit_set &) = default;
~option_explicit_set() noexcept override = default;
};
class Dynamic_Object
{
public:
Dynamic_Object(std::string t_type_name)
: m_type_name(std::move(t_type_name))
explicit Dynamic_Object(std::string t_type_name)
: m_type_name(std::move(t_type_name)), m_option_explicit(false)
{
}
Dynamic_Object() = default;
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;
}
Boxed_Value get_attr(const std::string &t_attr_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);
if (a != m_attrs.end()) {
return a->second;
} else {
throw std::range_error("Attr not found '" + t_attr_name + "' and cannot be added to const obj");
}
}
bool has_attr(const std::string &t_attr_name) const {
return m_attrs.find(t_attr_name) != m_attrs.end();
}
Boxed_Value &get_attr(const std::string &t_attr_name)
{
return m_attrs[t_attr_name];
}
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);
}
std::map<std::string, Boxed_Value> get_attrs() const
{
return m_attrs;
}
private:
std::string m_type_name;
const std::string m_type_name = "";
bool m_option_explicit = false;
std::map<std::string, Boxed_Value> m_attrs;
};
namespace detail
{
/**
* A Proxy_Function implementation designed for calling a function
* that is automatically guarded based on the first param based on the
* param's type name
*/
class Dynamic_Object_Function : public Proxy_Function_Base
{
public:
Dynamic_Object_Function(
std::string t_type_name,
const Proxy_Function &t_func)
: Proxy_Function_Base(t_func->get_param_types()),
m_type_name(std::move(t_type_name)), m_func(t_func), m_doti(user_type<Dynamic_Object>())
{
assert( (t_func->get_arity() > 0 || t_func->get_arity() < 0)
&& "Programming error, Dynamic_Object_Function must have at least one parameter (this)");
}
Dynamic_Object_Function(
std::string t_type_name,
const Proxy_Function &t_func,
const Type_Info &t_ti)
: Proxy_Function_Base(build_param_types(t_func->get_param_types(), t_ti)),
m_type_name(std::move(t_type_name)), m_func(t_func), m_ti(new Type_Info(t_ti)), m_doti(user_type<Dynamic_Object>())
{
assert( (t_func->get_arity() > 0 || t_func->get_arity() < 0)
&& "Programming error, Dynamic_Object_Function must have at least one parameter (this)");
}
virtual ~Dynamic_Object_Function() {}
Dynamic_Object_Function &operator=(const Dynamic_Object_Function) = delete;
virtual bool operator==(const Proxy_Function_Base &f) const CHAISCRIPT_OVERRIDE
{
const Dynamic_Object_Function *df = dynamic_cast<const Dynamic_Object_Function *>(&f);
if (df)
{
return df->m_type_name == m_type_name && (*df->m_func) == (*m_func);
} else {
return false;
}
}
virtual bool call_match(const std::vector<Boxed_Value> &vals, const Dynamic_Cast_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
{
if (dynamic_object_typename_match(vals, m_type_name, m_ti, t_conversions))
{
return m_func->call_match(vals, t_conversions);
} else {
return false;
}
}
virtual std::vector<Const_Proxy_Function> get_contained_functions() const CHAISCRIPT_OVERRIDE
{
return {m_func};
}
virtual int get_arity() const CHAISCRIPT_OVERRIDE
{
return m_func->get_arity();
}
virtual std::string annotation() const CHAISCRIPT_OVERRIDE
{
return m_func->annotation();
}
protected:
virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
{
if (dynamic_object_typename_match(params, m_type_name, m_ti, t_conversions))
{
return (*m_func)(params, t_conversions);
} else {
throw exception::guard_error();
}
}
virtual bool compare_first_type(const Boxed_Value &bv, const Dynamic_Cast_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
{
return dynamic_object_typename_match(bv, m_type_name, m_ti, t_conversions);
}
private:
static std::vector<Type_Info> build_param_types(
const std::vector<Type_Info> &t_inner_types, const Type_Info& t_objectti)
{
std::vector<Type_Info> types(t_inner_types);
assert(types.size() > 1);
assert(types[1].bare_equal(user_type<Boxed_Value>()));
types[1] = t_objectti;
return types;
}
bool dynamic_object_typename_match(const Boxed_Value &bv, const std::string &name,
const std::shared_ptr<Type_Info> &ti, const Dynamic_Cast_Conversions &t_conversions) const
{
if (bv.get_type_info().bare_equal(m_doti))
{
try {
const Dynamic_Object &d = boxed_cast<const Dynamic_Object &>(bv, &t_conversions);
return name == "Dynamic_Object" || d.get_type_name() == name;
} catch (const std::bad_cast &) {
return false;
}
} else {
if (ti)
{
return bv.get_type_info().bare_equal(*ti);
} else {
return false;
}
}
}
bool dynamic_object_typename_match(const std::vector<Boxed_Value> &bvs, const std::string &name,
const std::shared_ptr<Type_Info> &ti, const Dynamic_Cast_Conversions &t_conversions) const
{
if (bvs.size() > 0)
{
return dynamic_object_typename_match(bvs[0], name, ti, t_conversions);
} else {
return false;
}
}
std::string m_type_name;
Proxy_Function m_func;
std::shared_ptr<Type_Info> m_ti;
const Type_Info m_doti;
};
/**
* A Proxy_Function implementation designed for creating a new
* Dynamic_Object
* that is automatically guarded based on the first param based on the
* param's type name
*/
class Dynamic_Object_Constructor : public Proxy_Function_Base
{
public:
Dynamic_Object_Constructor(
std::string t_type_name,
const Proxy_Function &t_func)
: Proxy_Function_Base(build_type_list(t_func->get_param_types())),
m_type_name(std::move(t_type_name)), m_func(t_func)
{
assert( (t_func->get_arity() > 0 || t_func->get_arity() < 0)
&& "Programming error, Dynamic_Object_Function must have at least one parameter (this)");
}
static std::vector<Type_Info> build_type_list(const std::vector<Type_Info> &tl)
{
auto begin = tl.begin();
auto end = tl.end();
if (begin != end)
{
++begin;
}
return std::vector<Type_Info>(begin, end);
}
virtual ~Dynamic_Object_Constructor() {}
virtual bool operator==(const Proxy_Function_Base &f) const CHAISCRIPT_OVERRIDE
{
const Dynamic_Object_Constructor *dc = dynamic_cast<const Dynamic_Object_Constructor*>(&f);
if (dc)
{
return dc->m_type_name == m_type_name && (*dc->m_func) == (*m_func);
} else {
return false;
}
}
virtual bool call_match(const std::vector<Boxed_Value> &vals, const Dynamic_Cast_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
{
std::vector<Boxed_Value> new_vals;
new_vals.push_back(Boxed_Value(Dynamic_Object(m_type_name)));
new_vals.insert(new_vals.end(), vals.begin(), vals.end());
return m_func->call_match(new_vals, t_conversions);
}
virtual int get_arity() const CHAISCRIPT_OVERRIDE
{
// "this" is not considered part of the arity
return m_func->get_arity() - 1;
}
virtual std::string annotation() const CHAISCRIPT_OVERRIDE
{
return m_func->annotation();
}
protected:
virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
{
std::vector<Boxed_Value> new_params;
chaiscript::Boxed_Value bv = var(Dynamic_Object(m_type_name));
new_params.push_back(bv);
new_params.insert(new_params.end(), params.begin(), params.end());
(*m_func)(new_params, t_conversions);
return bv;
}
private:
std::string m_type_name;
Proxy_Function m_func;
};
}
}
}
#endif

View File

@ -0,0 +1,237 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_DYNAMIC_OBJECT_DETAIL_HPP_
#define CHAISCRIPT_DYNAMIC_OBJECT_DETAIL_HPP_
#include <cassert>
#include <map>
#include <memory>
#include <string>
#include <typeinfo>
#include <utility>
#include <vector>
#include "../chaiscript_defines.hpp"
#include "boxed_cast.hpp"
#include "boxed_cast_helper.hpp"
#include "boxed_value.hpp"
#include "proxy_functions.hpp"
#include "type_info.hpp"
#include "dynamic_object.hpp"
namespace chaiscript {
class Type_Conversions;
namespace dispatch {
class Proxy_Function_Base;
} // namespace dispatch
} // namespace chaiscript
namespace chaiscript
{
namespace dispatch
{
namespace detail
{
/// A Proxy_Function implementation designed for calling a function
/// that is automatically guarded based on the first param based on the
/// param's type name
class Dynamic_Object_Function final : public Proxy_Function_Base
{
public:
Dynamic_Object_Function(
std::string t_type_name,
const Proxy_Function &t_func,
bool t_is_attribute = false)
: Proxy_Function_Base(t_func->get_param_types(), t_func->get_arity()),
m_type_name(std::move(t_type_name)), m_func(t_func), m_doti(user_type<Dynamic_Object>()),
m_is_attribute(t_is_attribute)
{
assert( (t_func->get_arity() > 0 || t_func->get_arity() < 0)
&& "Programming error, Dynamic_Object_Function must have at least one parameter (this)");
}
Dynamic_Object_Function(
std::string t_type_name,
const Proxy_Function &t_func,
const Type_Info &t_ti,
bool t_is_attribute = false)
: Proxy_Function_Base(build_param_types(t_func->get_param_types(), t_ti), t_func->get_arity()),
m_type_name(std::move(t_type_name)), m_func(t_func), m_ti(t_ti.is_undef()?nullptr:new Type_Info(t_ti)), m_doti(user_type<Dynamic_Object>()),
m_is_attribute(t_is_attribute)
{
assert( (t_func->get_arity() > 0 || t_func->get_arity() < 0)
&& "Programming error, Dynamic_Object_Function must have at least one parameter (this)");
}
Dynamic_Object_Function &operator=(const Dynamic_Object_Function) = delete;
Dynamic_Object_Function(Dynamic_Object_Function &) = delete;
bool operator==(const Proxy_Function_Base &f) const override
{
if (const auto *df = dynamic_cast<const Dynamic_Object_Function *>(&f))
{
return df->m_type_name == m_type_name && (*df->m_func) == (*m_func);
} else {
return false;
}
}
bool is_attribute_function() const override { return m_is_attribute; }
bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const override
{
if (dynamic_object_typename_match(vals, m_type_name, m_ti, t_conversions))
{
return m_func->call_match(vals, t_conversions);
} else {
return false;
}
}
std::vector<Const_Proxy_Function> get_contained_functions() const override
{
return {m_func};
}
protected:
Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions_State &t_conversions) const override
{
if (dynamic_object_typename_match(params, m_type_name, m_ti, t_conversions))
{
return (*m_func)(params, t_conversions);
} else {
throw exception::guard_error();
}
}
bool compare_first_type(const Boxed_Value &bv, const Type_Conversions_State &t_conversions) const override
{
return dynamic_object_typename_match(bv, m_type_name, m_ti, t_conversions);
}
private:
static std::vector<Type_Info> build_param_types(
const std::vector<Type_Info> &t_inner_types, const Type_Info& t_objectti)
{
std::vector<Type_Info> types(t_inner_types);
assert(types.size() > 1);
//assert(types[1].bare_equal(user_type<Boxed_Value>()));
types[1] = t_objectti;
return types;
}
bool dynamic_object_typename_match(const Boxed_Value &bv, const std::string &name,
const std::unique_ptr<Type_Info> &ti, const Type_Conversions_State &t_conversions) const
{
if (bv.get_type_info().bare_equal(m_doti))
{
try {
const Dynamic_Object &d = boxed_cast<const Dynamic_Object &>(bv, &t_conversions);
return name == "Dynamic_Object" || d.get_type_name() == name;
} catch (const std::bad_cast &) {
return false;
}
} else {
if (ti)
{
return bv.get_type_info().bare_equal(*ti);
} else {
return false;
}
}
}
bool dynamic_object_typename_match(const std::vector<Boxed_Value> &bvs, const std::string &name,
const std::unique_ptr<Type_Info> &ti, const Type_Conversions_State &t_conversions) const
{
if (!bvs.empty())
{
return dynamic_object_typename_match(bvs[0], name, ti, t_conversions);
} else {
return false;
}
}
std::string m_type_name;
Proxy_Function m_func;
std::unique_ptr<Type_Info> m_ti;
const Type_Info m_doti;
const bool m_is_attribute;
};
/**
* A Proxy_Function implementation designed for creating a new
* Dynamic_Object
* that is automatically guarded based on the first param based on the
* param's type name
*/
class Dynamic_Object_Constructor final : public Proxy_Function_Base
{
public:
Dynamic_Object_Constructor(
std::string t_type_name,
const Proxy_Function &t_func)
: Proxy_Function_Base(build_type_list(t_func->get_param_types()), t_func->get_arity() - 1),
m_type_name(std::move(t_type_name)), m_func(t_func)
{
assert( (t_func->get_arity() > 0 || t_func->get_arity() < 0)
&& "Programming error, Dynamic_Object_Function must have at least one parameter (this)");
}
static std::vector<Type_Info> build_type_list(const std::vector<Type_Info> &tl)
{
auto begin = tl.begin();
auto end = tl.end();
if (begin != end)
{
++begin;
}
return std::vector<Type_Info>(begin, end);
}
bool operator==(const Proxy_Function_Base &f) const override
{
const Dynamic_Object_Constructor *dc = dynamic_cast<const Dynamic_Object_Constructor*>(&f);
return (dc != nullptr) && dc->m_type_name == m_type_name && (*dc->m_func) == (*m_func);
}
bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const override
{
std::vector<Boxed_Value> new_vals{Boxed_Value(Dynamic_Object(m_type_name))};
new_vals.insert(new_vals.end(), vals.begin(), vals.end());
return m_func->call_match(new_vals, t_conversions);
}
protected:
Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions_State &t_conversions) const override
{
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());
(*m_func)(new_params, t_conversions);
return bv;
}
private:
const std::string m_type_name;
const Proxy_Function m_func;
};
}
}
}
#endif

View File

@ -1,9 +1,13 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_EXCEPTION_SPECIFICATION_HPP_
#define CHAISCRIPT_EXCEPTION_SPECIFICATION_HPP_
@ -23,80 +27,26 @@ namespace chaiscript
{
namespace detail
{
/// \todo make this a variadic template
struct Exception_Handler_Base
{
virtual void handle(const Boxed_Value &bv, const Dispatch_Engine &t_engine) = 0;
virtual ~Exception_Handler_Base() {}
virtual ~Exception_Handler_Base() = default;
protected:
template<typename T>
void throw_type(const Boxed_Value &bv, const Dispatch_Engine &t_engine)
static void throw_type(const Boxed_Value &bv, const Dispatch_Engine &t_engine)
{
try { T t = t_engine.boxed_cast<T>(bv); throw t; } catch (const chaiscript::exception::bad_boxed_cast &) {}
}
};
template<typename T1>
struct Exception_Handler_Impl1 : Exception_Handler_Base
template<typename ... T>
struct Exception_Handler_Impl : Exception_Handler_Base
{
virtual ~Exception_Handler_Impl1() {}
virtual void handle(const Boxed_Value &bv, const Dispatch_Engine &t_engine) CHAISCRIPT_OVERRIDE
void handle(const Boxed_Value &bv, const Dispatch_Engine &t_engine) override
{
throw_type<T1>(bv, t_engine);
}
};
template<typename T1, typename T2>
struct Exception_Handler_Impl2 : Exception_Handler_Base
{
virtual ~Exception_Handler_Impl2() {}
virtual void handle(const Boxed_Value &bv, const Dispatch_Engine &t_engine) CHAISCRIPT_OVERRIDE
{
throw_type<T1>(bv, t_engine);
throw_type<T2>(bv, t_engine);
}
};
template<typename T1, typename T2, typename T3>
struct Exception_Handler_Impl3 : Exception_Handler_Base
{
virtual ~Exception_Handler_Impl3() {}
virtual void handle(const Boxed_Value &bv, const Dispatch_Engine &t_engine) CHAISCRIPT_OVERRIDE
{
throw_type<T1>(bv, t_engine);
throw_type<T2>(bv, t_engine);
throw_type<T3>(bv, t_engine);
}
};
template<typename T1, typename T2, typename T3, typename T4>
struct Exception_Handler_Impl4 : Exception_Handler_Base
{
virtual ~Exception_Handler_Impl4() {}
virtual void handle(const Boxed_Value &bv, const Dispatch_Engine &t_engine) CHAISCRIPT_OVERRIDE
{
throw_type<T1>(bv, t_engine);
throw_type<T2>(bv, t_engine);
throw_type<T3>(bv, t_engine);
throw_type<T4>(bv, t_engine);
}
};
template<typename T1, typename T2, typename T3, typename T4, typename T5>
struct Exception_Handler_Impl5 : Exception_Handler_Base
{
virtual ~Exception_Handler_Impl5() {}
virtual void handle(const Boxed_Value &bv, const Dispatch_Engine &t_engine) CHAISCRIPT_OVERRIDE
{
throw_type<T1>(bv, t_engine);
throw_type<T2>(bv, t_engine);
throw_type<T3>(bv, t_engine);
throw_type<T4>(bv, t_engine);
throw_type<T5>(bv, t_engine);
(void)std::initializer_list<int>{(throw_type<T>(bv, t_engine), 0)...};
}
};
}
@ -155,42 +105,10 @@ namespace chaiscript
/// \brief creates a chaiscript::Exception_Handler which handles one type of exception unboxing
/// \sa \ref exceptions
template<typename T1>
template<typename ... T>
Exception_Handler exception_specification()
{
return Exception_Handler(new detail::Exception_Handler_Impl1<T1>());
}
/// \brief creates a chaiscript::Exception_Handler which handles two types of exception unboxing
/// \sa \ref exceptions
template<typename T1, typename T2>
Exception_Handler exception_specification()
{
return Exception_Handler(new detail::Exception_Handler_Impl2<T1, T2>());
}
/// \brief creates a chaiscript::Exception_Handler which handles three types of exception unboxing
/// \sa \ref exceptions
template<typename T1, typename T2, typename T3>
Exception_Handler exception_specification()
{
return Exception_Handler(new detail::Exception_Handler_Impl3<T1, T2, T3>());
}
/// \brief creates a chaiscript::Exception_Handler which handles four types of exception unboxing
/// \sa \ref exceptions
template<typename T1, typename T2, typename T3, typename T4>
Exception_Handler exception_specification()
{
return Exception_Handler(new detail::Exception_Handler_Impl4<T1, T2, T3, T4>());
}
/// \brief creates a chaiscript::Exception_Handler which handles five types of exception unboxing
/// \sa \ref exceptions
template<typename T1, typename T2, typename T3, typename T4, typename T5>
Exception_Handler exception_specification()
{
return Exception_Handler(new detail::Exception_Handler_Impl5<T1, T2, T3, T4, T5>());
return std::make_shared<detail::Exception_Handler_Impl<T...>>();
}
}

View File

@ -1,24 +1,28 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_FUNCTION_CALL_HPP_
#define CHAISCRIPT_FUNCTION_CALL_HPP_
#include <functional>
#include <iostream>
#include <string>
#include <vector>
#include "boxed_cast.hpp"
#include "function_call_detail.hpp"
#include "proxy_functions.hpp"
#include "callable_traits.hpp"
namespace chaiscript {
class Boxed_Value;
class Dynamic_Cast_Conversions;
class Type_Conversions_State;
namespace detail {
template <typename T> struct Cast_Helper;
} // namespace detail
@ -28,66 +32,60 @@ namespace chaiscript
{
namespace dispatch
{
/**
* Build a function caller that knows how to dispatch on a set of functions
* example:
* std::function<void (int)> f =
* build_function_caller(dispatchkit.get_function("print"));
* \returns A std::function object for dispatching
* \param[in] funcs the set of functions to dispatch on.
*/
/// Build a function caller that knows how to dispatch on a set of functions
/// example:
/// std::function<void (int)> f =
/// build_function_caller(dispatchkit.get_function("print"));
/// \returns A std::function object for dispatching
/// \param[in] funcs the set of functions to dispatch on.
template<typename FunctionType>
std::function<FunctionType>
functor(const std::vector<Const_Proxy_Function> &funcs, const Dynamic_Cast_Conversions *t_conversions)
std::function<FunctionType> functor(const std::vector<Const_Proxy_Function> &funcs, const Type_Conversions_State *t_conversions)
{
const bool has_arity_match = std::any_of(funcs.begin(), funcs.end(),
[](const Const_Proxy_Function &f) {
return f->get_arity() == -1 || size_t(f->get_arity()) == chaiscript::dispatch::detail::Arity<FunctionType>::arity;
});
if (!has_arity_match) {
throw exception::bad_boxed_cast(user_type<Const_Proxy_Function>(), typeid(std::function<FunctionType>));
}
FunctionType *p=nullptr;
return detail::build_function_caller_helper(p, funcs, t_conversions);
}
/**
* Build a function caller for a particular Proxy_Function object
* useful in the case that a function is being pass out from scripting back
* into code
* example:
* void my_function(Proxy_Function f)
* {
* std::function<void (int)> local_f =
* build_function_caller(f);
* }
* \returns A std::function object for dispatching
* \param[in] func A function to execute.
*/
/// Build a function caller for a particular Proxy_Function object
/// useful in the case that a function is being pass out from scripting back
/// into code
/// example:
/// void my_function(Proxy_Function f)
/// {
/// std::function<void (int)> local_f =
/// build_function_caller(f);
/// }
/// \returns A std::function object for dispatching
/// \param[in] func A function to execute.
template<typename FunctionType>
std::function<FunctionType>
functor(Const_Proxy_Function func, const Dynamic_Cast_Conversions *t_conversions)
std::function<FunctionType> functor(Const_Proxy_Function func, const Type_Conversions_State *t_conversions)
{
std::vector<Const_Proxy_Function> funcs;
funcs.push_back(func);
return functor<FunctionType>(funcs, t_conversions);
return functor<FunctionType>(std::vector<Const_Proxy_Function>({std::move(func)}), t_conversions);
}
/**
* Helper for automatically unboxing a Boxed_Value that contains a function object
* and creating a typesafe C++ function caller from it.
*/
/// Helper for automatically unboxing a Boxed_Value that contains a function object
/// and creating a typesafe C++ function caller from it.
template<typename FunctionType>
std::function<FunctionType>
functor(const Boxed_Value &bv, const Dynamic_Cast_Conversions *t_conversions)
std::function<FunctionType> functor(const Boxed_Value &bv, const Type_Conversions_State *t_conversions)
{
return functor<FunctionType>(boxed_cast<Const_Proxy_Function >(bv, t_conversions), t_conversions);
}
}
namespace detail{
/**
* Cast helper to handle automatic casting to const std::function &
*/
/// Cast helper to handle automatic casting to const std::function &
template<typename Signature>
struct Cast_Helper<const std::function<Signature> &>
{
typedef std::function<Signature> Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *t_conversions)
static std::function<Signature> cast(const Boxed_Value &ob, const Type_Conversions_State *t_conversions)
{
if (ob.get_type_info().bare_equal(user_type<Const_Proxy_Function>()))
{
@ -98,15 +96,11 @@ namespace chaiscript
}
};
/**
* Cast helper to handle automatic casting to std::function
*/
/// Cast helper to handle automatic casting to std::function
template<typename Signature>
struct Cast_Helper<std::function<Signature> >
{
typedef std::function<Signature> Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *t_conversions)
static std::function<Signature> cast(const Boxed_Value &ob, const Type_Conversions_State *t_conversions)
{
if (ob.get_type_info().bare_equal(user_type<Const_Proxy_Function>()))
{
@ -117,15 +111,11 @@ namespace chaiscript
}
};
/**
* Cast helper to handle automatic casting to const std::function
*/
/// Cast helper to handle automatic casting to const std::function
template<typename Signature>
struct Cast_Helper<const std::function<Signature> >
{
typedef std::function<Signature> Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *t_conversions)
static std::function<Signature> cast(const Boxed_Value &ob, const Type_Conversions_State *t_conversions)
{
if (ob.get_type_info().bare_equal(user_type<Const_Proxy_Function>()))
{

View File

@ -1,13 +1,16 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_FUNCTION_CALL_DETAIL_HPP_
#define CHAISCRIPT_FUNCTION_CALL_DETAIL_HPP_
#include <algorithm>
#include <functional>
#include <memory>
#include <string>
@ -17,7 +20,7 @@
#include "boxed_cast.hpp"
#include "boxed_number.hpp"
#include "boxed_value.hpp"
#include "dynamic_cast_conversion.hpp"
#include "type_conversions.hpp"
#include "proxy_functions.hpp"
namespace chaiscript
@ -26,17 +29,21 @@ namespace chaiscript
{
namespace detail
{
/**
* Internal helper class for handling the return
* value of a build_function_caller
*/
/// Internal helper class for handling the return
/// value of a build_function_caller
template<typename Ret, bool is_arithmetic>
struct Function_Caller_Ret
{
static Ret call(const std::vector<Const_Proxy_Function> &t_funcs,
const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions)
const std::vector<Boxed_Value> &params, const Type_Conversions_State *t_conversions)
{
return boxed_cast<Ret>(dispatch::dispatch(t_funcs, params, t_conversions));
if (t_conversions != nullptr) {
return boxed_cast<Ret>(dispatch::dispatch(t_funcs, params, *t_conversions), t_conversions);
} else {
Type_Conversions conv;
Type_Conversions_State state(conv, conv.conversion_saves());
return boxed_cast<Ret>(dispatch::dispatch(t_funcs, params, state), t_conversions);
}
}
};
@ -47,9 +54,15 @@ namespace chaiscript
struct Function_Caller_Ret<Ret, true>
{
static Ret call(const std::vector<Const_Proxy_Function> &t_funcs,
const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions)
const std::vector<Boxed_Value> &params, const Type_Conversions_State *t_conversions)
{
return Boxed_Number(dispatch::dispatch(t_funcs, params, t_conversions)).get_as<Ret>();
if (t_conversions != nullptr) {
return Boxed_Number(dispatch::dispatch(t_funcs, params, *t_conversions)).get_as<Ret>();
} else {
Type_Conversions conv;
Type_Conversions_State state(conv, conv.conversion_saves());
return Boxed_Number(dispatch::dispatch(t_funcs, params, state)).get_as<Ret>();
}
}
};
@ -61,9 +74,15 @@ namespace chaiscript
struct Function_Caller_Ret<void, false>
{
static void call(const std::vector<Const_Proxy_Function> &t_funcs,
const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions)
const std::vector<Boxed_Value> &params, const Type_Conversions_State *t_conversions)
{
dispatch::dispatch(t_funcs, params, t_conversions);
if (t_conversions != nullptr) {
dispatch::dispatch(t_funcs, params, *t_conversions);
} else {
Type_Conversions conv;
Type_Conversions_State state(conv, conv.conversion_saves());
dispatch::dispatch(t_funcs, params, state);
}
}
};
@ -73,31 +92,60 @@ namespace chaiscript
template<typename Ret, typename ... Param>
struct Build_Function_Caller_Helper
{
Build_Function_Caller_Helper(std::vector<Const_Proxy_Function> t_funcs, const Dynamic_Cast_Conversions &t_conversions)
Build_Function_Caller_Helper(std::vector<Const_Proxy_Function> t_funcs, const Type_Conversions *t_conversions)
: m_funcs(std::move(t_funcs)),
m_conversions(t_conversions)
{
}
Ret operator()(Param...param)
template<typename ... P>
Ret operator()(P&& ... param)
{
return Function_Caller_Ret<Ret, std::is_arithmetic<Ret>::value && !std::is_same<Ret, bool>::value>::call(m_funcs, {
(std::is_reference<Param>::value&&!(std::is_same<chaiscript::Boxed_Value, typename std::remove_const<typename std::remove_reference<Param>::type>::type>::value))?Boxed_Value(std::ref(param)):Boxed_Value(param)...
}, m_conversions
);
if (m_conversions) {
Type_Conversions_State state(*m_conversions, m_conversions->conversion_saves());
return Function_Caller_Ret<Ret, std::is_arithmetic<Ret>::value && !std::is_same<Ret, bool>::value>::call(m_funcs, {
box<P>(std::forward<P>(param))...
}, &state
);
} else {
return Function_Caller_Ret<Ret, std::is_arithmetic<Ret>::value && !std::is_same<Ret, bool>::value>::call(m_funcs, {
box<P>(std::forward<P>(param))...
}, nullptr
);
}
}
template<typename P, typename Q>
static auto box(Q&& q) -> typename std::enable_if<std::is_reference<P>::value&&!std::is_same<chaiscript::Boxed_Value, typename std::remove_const<typename std::remove_reference<P>::type>::type>::value, Boxed_Value>::type
{
return Boxed_Value(std::ref(std::forward<Q>(q)));
}
template<typename P, typename Q>
static auto box(Q&& q) -> typename std::enable_if<!std::is_reference<P>::value&&!std::is_same<chaiscript::Boxed_Value, typename std::remove_const<typename std::remove_reference<P>::type>::type>::value, Boxed_Value>::type
{
return Boxed_Value(std::forward<Q>(q));
}
template<typename P>
static Boxed_Value box(Boxed_Value bv)
{
return bv;
}
std::vector<Const_Proxy_Function> m_funcs;
Dynamic_Cast_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 Dynamic_Cast_Conversions *t_conversions)
std::function<Ret (Params...)> build_function_caller_helper(Ret (Params...), const std::vector<Const_Proxy_Function> &funcs, const Type_Conversions_State *t_conversions)
{
/*
if (funcs.size() == 1)
{
std::shared_ptr<const Proxy_Function_Impl<Ret (Params...)>> pfi =
@ -111,8 +159,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:Dynamic_Cast_Conversions()));
return std::function<Ret (Params...)>(Build_Function_Caller_Helper<Ret, Params...>(funcs, t_conversions?t_conversions->get():nullptr));
}
}
}

View File

@ -1,21 +1,22 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_HANDLE_RETURN_HPP_
#define CHAISCRIPT_HANDLE_RETURN_HPP_
#include <functional>
#include <memory>
#include <stdexcept>
#include <string>
#include <vector>
#include <type_traits>
#include "boxed_number.hpp"
#include "boxed_value.hpp"
#include "type_info.hpp"
namespace chaiscript {
class Boxed_Number;
@ -25,17 +26,97 @@ namespace chaiscript
{
namespace dispatch
{
template<class T, class U> class Proxy_Function_Callable_Impl;
template<class T> class Assignable_Proxy_Function_Impl;
namespace detail
{
/**
* Used internally for handling a return value from a Proxy_Function call
*/
/// Used internally for handling a return value from a Proxy_Function call
template<typename Ret>
struct Handle_Return
{
static Boxed_Value handle(const Ret &r)
template<typename T,
typename = typename std::enable_if<std::is_pod<typename std::decay<T>::type>::value>::type>
static Boxed_Value handle(T r)
{
return const_var(r);
return Boxed_Value(std::move(r), true);
}
template<typename T,
typename = typename std::enable_if<!std::is_pod<typename std::decay<T>::type>::value>::type>
static Boxed_Value handle(T &&r)
{
return Boxed_Value(std::make_shared<T>(std::forward<T>(r)), true);
}
};
template<typename Ret>
struct Handle_Return<const std::function<Ret> &>
{
static Boxed_Value handle(const std::function<Ret> &f) {
return Boxed_Value(
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Ret, std::function<Ret>>>(f)
);
}
};
template<typename Ret>
struct Handle_Return<std::function<Ret>> : Handle_Return<const std::function<Ret> &>
{
};
template<typename Ret>
struct Handle_Return<const std::shared_ptr<std::function<Ret>>>
{
static Boxed_Value handle(const std::shared_ptr<std::function<Ret>> &f) {
return Boxed_Value(
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Assignable_Proxy_Function_Impl<Ret>>(std::ref(*f),f)
);
}
};
template<typename Ret>
struct Handle_Return<const std::shared_ptr<std::function<Ret>> &> : Handle_Return<const std::shared_ptr<std::function<Ret>>>
{
};
template<typename Ret>
struct Handle_Return<std::shared_ptr<std::function<Ret>>> : Handle_Return<const std::shared_ptr<std::function<Ret>>>
{
};
template<typename Ret>
struct Handle_Return<std::function<Ret> &>
{
static Boxed_Value handle(std::function<Ret> &f) {
return Boxed_Value(
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(
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Ret, std::function<Ret>>>(f)
);
}
};
template<typename Ret>
struct Handle_Return<Ret *&>
{
static Boxed_Value handle(Ret *p)
{
return Boxed_Value(p, true);
}
};
template<typename Ret>
struct Handle_Return<const Ret *&>
{
static Boxed_Value handle(const Ret *p)
{
return Boxed_Value(p, true);
}
};
@ -44,7 +125,16 @@ namespace chaiscript
{
static Boxed_Value handle(Ret *p)
{
return Boxed_Value(p);
return Boxed_Value(p, true);
}
};
template<typename Ret>
struct Handle_Return<const Ret *>
{
static Boxed_Value handle(const Ret *p)
{
return Boxed_Value(p, true);
}
};
@ -53,30 +143,43 @@ namespace chaiscript
{
static Boxed_Value handle(const std::shared_ptr<Ret> &r)
{
return Boxed_Value(r);
return Boxed_Value(r, true);
}
};
template<typename Ret>
struct Handle_Return<std::shared_ptr<Ret> >
struct Handle_Return<std::shared_ptr<Ret>> : Handle_Return<std::shared_ptr<Ret> &>
{
static Boxed_Value handle(const std::shared_ptr<Ret> &r)
{
return Boxed_Value(r);
}
};
template<typename Ret>
struct Handle_Return<const std::shared_ptr<Ret> &>
struct Handle_Return<const std::shared_ptr<Ret> &> : Handle_Return<std::shared_ptr<Ret> &>
{
static Boxed_Value handle(const std::shared_ptr<Ret> &r)
};
template<typename Ret>
struct Handle_Return<std::unique_ptr<Ret>> : Handle_Return<std::unique_ptr<Ret> &>
{
static Boxed_Value handle(std::unique_ptr<Ret> &&r)
{
return Boxed_Value(r);
return Boxed_Value(std::move(r), true);
}
};
template<typename Ret>
struct Handle_Return<const Ret &>
{
static Boxed_Value handle(const Ret &r)
{
return Boxed_Value(std::cref(r), true);
}
};
template<typename Ret>
struct Handle_Return<const Ret>
{
static Boxed_Value handle(const Ret &r)
{
@ -84,10 +187,6 @@ namespace chaiscript
}
};
/**
* Used internally for handling a return value from a Proxy_Function call
*/
template<typename Ret>
struct Handle_Return<Ret &>
{
@ -95,16 +194,8 @@ namespace chaiscript
{
return Boxed_Value(std::ref(r));
}
static Boxed_Value handle(const Ret &r)
{
return Boxed_Value(std::cref(r));
}
};
/**
* Used internally for handling a return value from a Proxy_Function call
*/
template<>
struct Handle_Return<Boxed_Value>
{
@ -114,40 +205,19 @@ namespace chaiscript
}
};
/**
* Used internally for handling a return value from a Proxy_Function call
*/
template<>
struct Handle_Return<const Boxed_Value>
struct Handle_Return<const Boxed_Value> : Handle_Return<Boxed_Value>
{
static Boxed_Value handle(const Boxed_Value &r)
{
return r;
}
};
/**
* Used internally for handling a return value from a Proxy_Function call
*/
template<>
struct Handle_Return<Boxed_Value &>
struct Handle_Return<Boxed_Value &> : Handle_Return<Boxed_Value>
{
static Boxed_Value handle(const Boxed_Value &r)
{
return r;
}
};
/**
* Used internally for handling a return value from a Proxy_Function call
*/
template<>
struct Handle_Return<const Boxed_Value &>
struct Handle_Return<const Boxed_Value &> : Handle_Return<Boxed_Value>
{
static Boxed_Value handle(const Boxed_Value &r)
{
return r;
}
};
/**
@ -162,16 +232,9 @@ namespace chaiscript
}
};
/**
* Used internally for handling a return value from a Proxy_Function call
*/
template<>
struct Handle_Return<const Boxed_Number>
struct Handle_Return<const Boxed_Number> : Handle_Return<Boxed_Number>
{
static Boxed_Value handle(const Boxed_Number &r)
{
return r.bv;
}
};
@ -183,7 +246,7 @@ namespace chaiscript
{
static Boxed_Value handle()
{
return Boxed_Value(Boxed_Value::Void_Type());
return void_var();
}
};
}

View File

@ -1,9 +1,13 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_OPERATORS_HPP_
#define CHAISCRIPT_OPERATORS_HPP_
@ -16,447 +20,202 @@ namespace chaiscript
{
namespace operators
{
namespace detail
{
/// \todo make this return a decltype once we drop gcc 4.6
template<typename L, typename R>
auto assign(L l, R r) -> L&
{
return (l = r);
}
template<typename L, typename R>
auto assign_bitwise_and(L l, R r) -> decltype((l &= r))
{
return (l &= r);
}
template<typename L, typename R>
auto assign_xor(L l, R r) -> decltype((l^=r))
{
return (l ^= r);
}
template<typename L, typename R>
auto assign_bitwise_or(L l, R r) -> decltype((l |= r))
{
return (l |= r);
}
template<typename L, typename R>
auto assign_difference(L l, R r) -> decltype(( l -= r))
{
return (l -= r);
}
template<typename L, typename R>
auto assign_left_shift(L l, R r) -> decltype(( l <<= r))
{
return (l <<= r);
}
template<typename L, typename R>
auto assign_product(L l, R r) -> decltype(( l *= r ))
{
return (l *= r);
}
template<typename L, typename R>
auto assign_quotient(L l, R r) -> decltype(( l /= r ))
{
return (l /= r);
}
template<typename L, typename R>
auto assign_remainder(L l, R r) -> decltype(( l %= r ))
{
return (l %= r);
}
template<typename L, typename R>
auto assign_right_shift(L l, R r) -> decltype(( l >>= r))
{
return (l >>= r);
}
/// \todo make this return a decltype once we drop gcc 4.6
template<typename L, typename R>
auto assign_sum(L l, R r) -> L&
{
return (l += r);
}
template<typename L>
auto prefix_decrement(L l) -> decltype(( --l ))
{
return (--l);
}
template<typename L>
auto prefix_increment(L l) -> decltype(( ++l ))
{
return (++l);
}
template<typename L, typename R>
auto equal(L l, R r) -> decltype(( l == r ))
{
return (l == r);
}
template<typename L, typename R>
auto greater_than(L l, R r) -> decltype(( l > r ))
{
return (l > r);
}
template<typename L, typename R>
auto greater_than_equal(L l, R r) -> decltype(( l >= r ))
{
return (l >= r);
}
template<typename L, typename R>
auto less_than(L l, R r) -> decltype(( l < r ))
{
return (l < r);
}
template<typename L, typename R>
auto less_than_equal(L l, R r) -> decltype(( l <= r ))
{
return (l <= r);
}
template<typename L>
auto logical_compliment(L l) -> decltype(( !l ))
{
return (!l);
}
template<typename L, typename R>
auto not_equal(L l, R r) -> decltype(( l != r ))
{
return (l != r);
}
template<typename L, typename R>
auto addition(L l, R r) -> decltype(( l + r ))
{
return (l + r);
}
template<typename L>
auto unary_plus(L l) -> decltype(( +l ))
{
return (+l);
}
template<typename L, typename R>
auto subtraction(L l, R r) -> decltype(( l - r ))
{
return (l - r);
}
template<typename L>
auto unary_minus(L l) -> decltype(( -l ))
{
#ifdef CHAISCRIPT_MSVC
#pragma warning(push)
#pragma warning(disable : 4146)
return (-l);
#pragma warning(pop)
#else
return (-l);
#endif
}
template<typename L, typename R>
auto bitwise_and(L l, R r) -> decltype(( l & r ))
{
return (l & r);
}
template<typename L>
auto bitwise_compliment(L l) -> decltype(( ~l ))
{
return (~l);
}
template<typename L, typename R>
auto bitwise_xor(L l, R r) -> decltype(( l ^ r ))
{
return (l ^ r);
}
template<typename L, typename R>
auto bitwise_or(L l, R r) -> decltype(( l | r ))
{
return (l | r);
}
template<typename L, typename R>
auto division(L l, R r) -> decltype(( l / r ))
{
return (l / r);
}
template<typename L, typename R>
auto left_shift(L l, R r) -> decltype(( l << r ))
{
return l << r;
}
template<typename L, typename R>
auto multiplication(L l, R r) -> decltype(( l * r ))
{
return l * r;
}
template<typename L, typename R>
auto remainder(L l, R r) -> decltype(( l % r ))
{
return (l % r);
}
template<typename L, typename R>
auto right_shift(L l, R r) -> decltype(( l >> r ))
{
return (l >> r);
}
}
template<typename T>
ModulePtr assign(ModulePtr m = ModulePtr(new Module()))
void assign(Module& m)
{
m->add(chaiscript::fun(&detail::assign<T &, const T&>), "=");
return m;
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs = rhs;}), "=");
}
template<typename T>
ModulePtr assign_bitwise_and(ModulePtr m = ModulePtr(new Module()))
void assign_bitwise_and(Module& m)
{
m->add(chaiscript::fun(&detail::assign_bitwise_and<T &, const T&>), "&=");
return m;
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs &= rhs;}), "&=");
}
template<typename T>
ModulePtr assign_xor(ModulePtr m = ModulePtr(new Module()))
void assign_xor(Module& m)
{
m->add(chaiscript::fun(&detail::assign_xor<T &, const T&>), "^=");
return m;
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs ^= rhs;}), "^=");
}
template<typename T>
ModulePtr assign_bitwise_or(ModulePtr m = ModulePtr(new Module()))
void assign_bitwise_or(Module& m)
{
m->add(chaiscript::fun(&detail::assign_bitwise_or<T &, const T&>), "|=");
return m;
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs |= rhs;}), "|=");
}
template<typename T>
ModulePtr assign_difference(ModulePtr m = ModulePtr(new Module()))
void assign_difference(Module& m)
{
m->add(chaiscript::fun(&detail::assign_difference<T &, const T&>), "-=");
return m;
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs -= rhs;}), "-=");
}
template<typename T>
ModulePtr assign_left_shift(ModulePtr m = ModulePtr(new Module()))
void assign_left_shift(Module& m)
{
m->add(chaiscript::fun(&detail::assign_left_shift<T &, const T&>), "<<=");
return m;
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs <<= rhs;}), "<<=");
}
template<typename T>
ModulePtr assign_product(ModulePtr m = ModulePtr(new Module()))
void assign_product(Module& m)
{
m->add(chaiscript::fun(&detail::assign_product<T &, const T&>), "*=");
return m;
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs <<= rhs;}), "*=");
}
template<typename T>
ModulePtr assign_quotient(ModulePtr m = ModulePtr(new Module()))
void assign_quotient(Module& m)
{
m->add(chaiscript::fun(&detail::assign_quotient<T &, const T&>), "/=");
return m;
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs /= rhs;}), "/=");
}
template<typename T>
ModulePtr assign_remainder(ModulePtr m = ModulePtr(new Module()))
void assign_remainder(Module& m)
{
m->add(chaiscript::fun(&detail::assign_remainder<T &, const T&>), "%=");
return m;
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs %= rhs;}), "%=");
}
template<typename T>
ModulePtr assign_right_shift(ModulePtr m = ModulePtr(new Module()))
void assign_right_shift(Module& m)
{
m->add(chaiscript::fun(&detail::assign_right_shift<T &, const T&>), ">>=");
return m;
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs >>= rhs;}), ">>=");
}
template<typename T>
ModulePtr assign_sum(ModulePtr m = ModulePtr(new Module()))
void assign_sum(Module& m)
{
m->add(chaiscript::fun(&detail::assign_sum<T &, const T&>), "+=");
return m;
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs += rhs;}), "+=");
}
template<typename T>
ModulePtr prefix_decrement(ModulePtr m = ModulePtr(new Module()))
void prefix_decrement(Module& m)
{
m->add(chaiscript::fun(&detail::prefix_decrement<T &>), "--");
return m;
m.add(chaiscript::fun([](T &lhs)->T&{return --lhs;}), "--");
}
template<typename T>
ModulePtr prefix_increment(ModulePtr m = ModulePtr(new Module()))
void prefix_increment(Module& m)
{
m->add(chaiscript::fun(&detail::prefix_increment<T &>), "++");
return m;
m.add(chaiscript::fun([](T &lhs)->T&{return ++lhs;}), "++");
}
template<typename T>
ModulePtr equal(ModulePtr m = ModulePtr(new Module()))
void equal(Module& m)
{
m->add(chaiscript::fun(&detail::equal<const T&, const T&>), "==");
return m;
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs==rhs;}), "==");
}
template<typename T>
ModulePtr greater_than(ModulePtr m = ModulePtr(new Module()))
void greater_than(Module& m)
{
m->add(chaiscript::fun(&detail::greater_than<const T&, const T&>), ">");
return m;
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs>rhs;}), ">");
}
template<typename T>
ModulePtr greater_than_equal(ModulePtr m = ModulePtr(new Module()))
void greater_than_equal(Module& m)
{
m->add(chaiscript::fun(&detail::greater_than_equal<const T&, const T&>), ">=");
return m;
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs>=rhs;}), ">=");
}
template<typename T>
ModulePtr less_than(ModulePtr m = ModulePtr(new Module()))
void less_than(Module& m)
{
m->add(chaiscript::fun(&detail::less_than<const T&, const T&>), "<");
return m;
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs<rhs;}), "<");
}
template<typename T>
ModulePtr less_than_equal(ModulePtr m = ModulePtr(new Module()))
void less_than_equal(Module& m)
{
m->add(chaiscript::fun(&detail::less_than_equal<const T&, const T&>), "<=");
return m;
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs<=rhs;}), "<=");
}
template<typename T>
ModulePtr logical_compliment(ModulePtr m = ModulePtr(new Module()))
void logical_compliment(Module& m)
{
m->add(chaiscript::fun(&detail::logical_compliment<const T &>), "!");
return m;
m.add(chaiscript::fun([](const T &lhs){return !lhs;}), "!");
}
template<typename T>
ModulePtr not_equal(ModulePtr m = ModulePtr(new Module()))
void not_equal(Module& m)
{
m->add(chaiscript::fun(&detail::not_equal<const T &, const T &>), "!=");
return m;
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs!=rhs;}), "!=");
}
template<typename T>
ModulePtr addition(ModulePtr m = ModulePtr(new Module()))
void addition(Module& m)
{
m->add(chaiscript::fun(&detail::addition<const T &, const T &>), "+");
return m;
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs+rhs;}), "+");
}
template<typename T>
ModulePtr unary_plus(ModulePtr m = ModulePtr(new Module()))
void unary_plus(Module& m)
{
m->add(chaiscript::fun(&detail::unary_plus<const T &>), "+");
return m;
m.add(chaiscript::fun([](const T &lhs){return +lhs;}), "+");
}
template<typename T>
ModulePtr subtraction(ModulePtr m = ModulePtr(new Module()))
void subtraction(Module& m)
{
m->add(chaiscript::fun(&detail::subtraction<const T &, const T &>), "-");
return m;
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs-rhs;}), "-");
}
template<typename T>
ModulePtr unary_minus(ModulePtr m = ModulePtr(new Module()))
void unary_minus(Module& m)
{
m->add(chaiscript::fun(&detail::unary_minus<const T &>), "-");
return m;
m.add(chaiscript::fun([](const T &lhs){return -lhs;}), "-");
}
template<typename T>
ModulePtr bitwise_and(ModulePtr m = ModulePtr(new Module()))
void bitwise_and(Module& m)
{
m->add(chaiscript::fun(&detail::bitwise_and<const T &, const T &>), "&");
return m;
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs&rhs;}), "&");
}
template<typename T>
ModulePtr bitwise_compliment(ModulePtr m = ModulePtr(new Module()))
void bitwise_compliment(Module& m)
{
m->add(chaiscript::fun(&detail::bitwise_compliment<const T &>), "~");
return m;
m.add(chaiscript::fun([](const T &lhs){return ~lhs;}), "~");
}
template<typename T>
ModulePtr bitwise_xor(ModulePtr m = ModulePtr(new Module()))
void bitwise_xor(Module& m)
{
m->add(chaiscript::fun(&detail::bitwise_xor<const T &, const T &>), "^");
return m;
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs^rhs;}), "^");
}
template<typename T>
ModulePtr bitwise_or(ModulePtr m = ModulePtr(new Module()))
void bitwise_or(Module& m)
{
m->add(chaiscript::fun(&detail::bitwise_or<const T &, const T &>), "|");
return m;
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs|rhs;}), "|");
}
template<typename T>
ModulePtr division(ModulePtr m = ModulePtr(new Module()))
void division(Module& m)
{
m->add(chaiscript::fun(&detail::division<const T &, const T &>), "/");
return m;
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs/rhs;}), "/");
}
template<typename T>
ModulePtr left_shift(ModulePtr m = ModulePtr(new Module()))
void left_shift(Module& m)
{
m->add(chaiscript::fun(&detail::left_shift<const T &, const T &>), "<<");
return m;
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs<<rhs;}), "<<");
}
template<typename T>
ModulePtr multiplication(ModulePtr m = ModulePtr(new Module()))
void multiplication(Module& m)
{
m->add(chaiscript::fun(&detail::multiplication<const T &, const T &>), "*");
return m;
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs*rhs;}), "*");
}
template<typename T>
ModulePtr remainder(ModulePtr m = ModulePtr(new Module()))
void remainder(Module& m)
{
m->add(chaiscript::fun(&detail::remainder<const T &, const T &>), "%");
return m;
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs%rhs;}), "%");
}
template<typename T>
ModulePtr right_shift(ModulePtr m = ModulePtr(new Module()))
void right_shift(Module& m)
{
m->add(chaiscript::fun(&detail::right_shift<const T &, const T &>), ">>");
return m;
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs>>rhs;}), ">>");
}
}
}

View File

@ -1,34 +1,32 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_PROXY_CONSTRUCTORS_HPP_
#define CHAISCRIPT_PROXY_CONSTRUCTORS_HPP_
#include "proxy_functions.hpp"
namespace chaiscript
{
namespace dispatch
{
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(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));
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,26 +1,30 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_PROXY_FUNCTIONS_DETAIL_HPP_
#define CHAISCRIPT_PROXY_FUNCTIONS_DETAIL_HPP_
#include <algorithm>
#include <functional>
#include <stdexcept>
#include <string>
#include <vector>
#include <array>
#include "../chaiscript_defines.hpp"
#include "boxed_cast.hpp"
#include "boxed_value.hpp"
#include "handle_return.hpp"
#include "type_info.hpp"
#include "callable_traits.hpp"
namespace chaiscript {
class Dynamic_Cast_Conversions;
class Type_Conversions_State;
namespace exception {
class bad_boxed_cast;
} // namespace exception
@ -42,7 +46,9 @@ namespace chaiscript
{
}
virtual ~arity_error() CHAISCRIPT_NOEXCEPT {}
arity_error(const arity_error &) = default;
~arity_error() noexcept override = default;
int got;
int expected;
@ -65,30 +71,6 @@ namespace chaiscript
}
// Forward declaration
template<typename ... Rest>
struct Try_Cast;
template<typename Param, typename ... Rest>
struct Try_Cast<Param, Rest...>
{
static void do_try(const std::vector<Boxed_Value> &params, int generation, const Dynamic_Cast_Conversions &t_conversions)
{
boxed_cast<Param>(params[generation], &t_conversions);
Try_Cast<Rest...>::do_try(params, generation+1, t_conversions);
}
};
// 0th case
template<>
struct Try_Cast<>
{
static void do_try(const std::vector<Boxed_Value> &, int, const Dynamic_Cast_Conversions &)
{
}
};
/**
* Used by Proxy_Function_Impl to determine if it is equivalent to another
* Proxy_Function_Impl object. This function is primarily used to prevent
@ -96,63 +78,56 @@ namespace chaiscript
*/
template<typename Ret, typename ... Params>
bool compare_types_cast(Ret (*)(Params...),
const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions)
{
const std::vector<Boxed_Value> &params, const Type_Conversions_State &t_conversions)
{
try {
Try_Cast<Params...>::do_try(params, 0, t_conversions);
std::vector<Boxed_Value>::size_type i = 0;
(void)i;
(void)params; (void)t_conversions;
// this is ok because the order of evaluation of initializer lists is well defined
(void)std::initializer_list<int>{(boxed_cast<Params>(params[i++], &t_conversions), 0)...};
return true;
} catch (const exception::bad_boxed_cast &) {
return false;
}
return true;
}
template<typename Ret, int count, typename ... Params>
struct Call_Func
{
template<typename ... InnerParams>
static Ret do_call(const std::function<Ret (Params...)> &f,
const std::vector<Boxed_Value> &params, const Dynamic_Cast_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]);
}
};
template<typename Ret, typename ... Params>
struct Call_Func<Ret, 0, Params...>
template<typename Callable, typename Ret, typename ... Params, size_t ... I>
Ret call_func(const chaiscript::dispatch::detail::Function_Signature<Ret (Params...)> &,
std::index_sequence<I...>, const Callable &f,
const std::vector<Boxed_Value> &params, const Type_Conversions_State &t_conversions)
{
(void)params; (void)t_conversions;
return f(boxed_cast<Params>(params[I], &t_conversions)...);
}
/// Used by Proxy_Function_Impl to perform typesafe execution of a function.
/// The function attempts to unbox each parameter to the expected type.
/// if any unboxing fails the execution of the function fails and
/// the bad_boxed_cast is passed up to the caller.
template<typename Callable, typename Ret, typename ... Params>
Boxed_Value call_func(const chaiscript::dispatch::detail::Function_Signature<Ret (Params...)> &sig, const Callable &f,
const std::vector<Boxed_Value> &params, const Type_Conversions_State &t_conversions)
{
return Handle_Return<Ret>::handle(call_func(sig, std::index_sequence_for<Params...>{}, f, params, t_conversions));
}
template<typename Callable, typename ... Params>
Boxed_Value call_func(const chaiscript::dispatch::detail::Function_Signature<void (Params...)> &sig, const Callable &f,
const std::vector<Boxed_Value> &params, const Type_Conversions_State &t_conversions)
{
call_func(sig, std::index_sequence_for<Params...>{}, f, params, t_conversions);
#ifdef CHAISCRIPT_MSVC
#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
#pragma warning(disable : 4702)
#endif
template<typename ... InnerParams>
static Ret do_call(const std::function<Ret (Params...)> &f,
const std::vector<Boxed_Value> &, const Dynamic_Cast_Conversions &t_conversions, InnerParams &&... innerparams)
{
return f(boxed_cast<Params>(std::forward<InnerParams>(innerparams), &t_conversions)...);
}
// MSVC is reporting that this is unreachable code - and it's wrong.
return Handle_Return<void>::handle();
#ifdef CHAISCRIPT_MSVC
#pragma warning(pop)
#endif
};
/**
* 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 Ret, typename ... Params>
Ret call_func(const std::function<Ret (Params...)> &f,
const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions)
{
if (params.size() == sizeof...(Params))
{
return Call_Func<Ret, sizeof...(Params), Params...>::do_call(f, params, t_conversions);
}
throw exception::arity_error(static_cast<int>(params.size()), sizeof...(Params));
}
}
@ -161,34 +136,4 @@ namespace chaiscript
}
namespace chaiscript
{
namespace dispatch
{
namespace detail
{
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 Dynamic_Cast_Conversions &t_conversions)
{
return Handle_Return<Ret>::handle(call_func(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 Dynamic_Cast_Conversions &t_conversions)
{
call_func(fun, params, t_conversions);
return Handle_Return<void>::handle();
}
};
}
}
}
#endif

View File

@ -1,81 +1,23 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_REGISTER_FUNCTION_HPP_
#define CHAISCRIPT_REGISTER_FUNCTION_HPP_
#include <functional>
#include <type_traits>
#include "bind_first.hpp"
#include "dispatchkit.hpp"
#include "proxy_functions.hpp"
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...))
{
/// \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));
}
template<typename Ret, typename Class, typename ... Args>
std::function<Ret (const Class &, Args...) > to_function(Ret (Class::*func)(Args...) const)
{
/// \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...)>(std::mem_fn(func));
}
template<bool Object>
struct Fun_Helper
{
template<typename T>
static Proxy_Function go(T t)
{
/// \todo is it possible to reduce the number of templates generated here?
return Proxy_Function(
new Proxy_Function_Impl<typename FunctionSignature<decltype(to_function(t)) >::Signature>(to_function(t)));
}
};
template<>
struct Fun_Helper<true>
{
template<typename T, typename Class>
static Proxy_Function go(T Class::* m)
{
return Proxy_Function(new Attribute_Access<T, Class>(m));
}
};
}
}
/// \brief Creates a new Proxy_Function object from a free function, member function or data member
/// \param[in] t Function / member to expose
@ -98,29 +40,52 @@ namespace chaiscript
///
/// \sa \ref adding_functions
template<typename T>
Proxy_Function fun(T t)
Proxy_Function fun(const T &t)
{
return dispatch::detail::Fun_Helper<std::is_member_object_pointer<T>::value>::go(t);
typedef typename dispatch::detail::Callable_Traits<T>::Signature Signature;
return Proxy_Function(
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::*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_Callable_Impl<Ret (const Class &, Param...), decltype(call)>>(call));
}
template<typename Ret, typename Class, typename ... 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_Callable_Impl<Ret (Class &, Param...), decltype(call)>>(call));
}
/// \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)
template<typename T, typename Class /*, typename = typename std::enable_if<std::is_member_object_pointer<T>::value>::type*/>
Proxy_Function fun(T Class::* m /*, typename std::enable_if<std::is_member_object_pointer<T>::value>::type* = 0*/ )
{
return Proxy_Function(new dispatch::Proxy_Function_Impl<T>(f));
return Proxy_Function(chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Attribute_Access<T, Class>>(m));
}
/// \brief Creates a new Proxy_Function object from a free function, member function or data member and binds the first parameter of it
/// \param[in] t Function / member to expose
@ -141,37 +106,12 @@ namespace chaiscript
///
/// \sa \ref adding_functions
template<typename T, typename Q>
Proxy_Function fun(T t, const Q &q)
Proxy_Function fun(T &&t, const Q &q)
{
return fun(detail::bind_first(t, q));
return fun(detail::bind_first(std::forward<T>(t), q));
}
/// \brief Creates a new Proxy_Function object from a free function or member function and binds the first and second parameters of it
/// \param[in] t Function / member to expose
/// \param[in] q Value to bind to first parameter
/// \param[in] r Value to bind to second parameter
///
/// \b Example:
/// \code
/// struct MyClass
/// {
/// void memberfunction(int);
/// };
///
/// MyClass obj;
/// chaiscript::ChaiScript chai;
/// // Add function taking only no arguments, and permanently bound to "obj" and "1"
/// // memberfunction() will be equivalent to obj.memberfunction(1)
/// chai.add(fun(&MyClass::memberfunction, std::ref(obj), 1), "memberfunction");
/// \endcode
///
/// \sa \ref adding_functions
template<typename T, typename Q, typename R>
Proxy_Function fun(T t, const Q &q, const R &r)
{
return fun(detail::bind_first(detail::bind_first(t, q), r));
}
}

View File

@ -0,0 +1,159 @@
#ifndef SHORT_ALLOC_H
#define SHORT_ALLOC_H
// The MIT License (MIT)
//
// Copyright (c) 2015 Howard Hinnant
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#include <cstddef>
#include <cassert>
template <std::size_t N, std::size_t alignment = alignof(std::max_align_t)>
class arena
{
alignas(alignment) char buf_[N];
char* ptr_;
public:
~arena() {ptr_ = nullptr;}
arena() noexcept : ptr_(buf_) {}
arena(const arena&) = delete;
arena& operator=(const arena&) = delete;
template <std::size_t ReqAlign> char* allocate(std::size_t n);
void deallocate(char* p, std::size_t n) noexcept;
static constexpr std::size_t size() noexcept {return N;}
std::size_t used() const noexcept {return static_cast<std::size_t>(ptr_ - buf_);}
void reset() noexcept {ptr_ = buf_;}
private:
static
std::size_t
align_up(std::size_t n) noexcept
{return (n + (alignment-1)) & ~(alignment-1);}
bool
pointer_in_buffer(char* p) noexcept
{return buf_ <= p && p <= buf_ + N;}
};
template <std::size_t N, std::size_t alignment>
template <std::size_t ReqAlign>
char*
arena<N, alignment>::allocate(std::size_t n)
{
static_assert(ReqAlign <= alignment, "alignment is too small for this arena");
assert(pointer_in_buffer(ptr_) && "short_alloc has outlived arena");
auto const aligned_n = align_up(n);
if (static_cast<decltype(aligned_n)>(buf_ + N - ptr_) >= aligned_n)
{
char* r = ptr_;
ptr_ += aligned_n;
return r;
}
static_assert(alignment <= alignof(std::max_align_t), "you've chosen an "
"alignment that is larger than alignof(std::max_align_t), and "
"cannot be guaranteed by normal operator new");
return static_cast<char*>(::operator new(n));
}
template <std::size_t N, std::size_t alignment>
void
arena<N, alignment>::deallocate(char* p, std::size_t n) noexcept
{
assert(pointer_in_buffer(ptr_) && "short_alloc has outlived arena");
if (pointer_in_buffer(p))
{
n = align_up(n);
if (p + n == ptr_) {
ptr_ = p;
}
}
else {
::operator delete(p);
}
}
template <class T, std::size_t N, std::size_t Align = alignof(std::max_align_t)>
class short_alloc
{
public:
using value_type = T;
static auto constexpr alignment = Align;
static auto constexpr size = N;
using arena_type = arena<size, alignment>;
private:
arena_type& a_;
public:
short_alloc(const short_alloc&) = default;
short_alloc& operator=(const short_alloc&) = delete;
explicit short_alloc(arena_type& a) noexcept : a_(a)
{
static_assert(size % alignment == 0,
"size N needs to be a multiple of alignment Align");
}
template <class U>
explicit short_alloc(const short_alloc<U, N, alignment>& a) noexcept
: a_(a.a_) {}
template <class _Up> struct rebind {using other = short_alloc<_Up, N, alignment>;};
T* allocate(std::size_t n)
{
return reinterpret_cast<T*>(a_.template allocate<alignof(T)>(n*sizeof(T)));
}
void deallocate(T* p, std::size_t n) noexcept
{
a_.deallocate(reinterpret_cast<char*>(p), n*sizeof(T));
}
template <class T1, std::size_t N1, std::size_t A1,
class U, std::size_t M, std::size_t A2>
friend
bool
operator==(const short_alloc<T1, N1, A1>& x, const short_alloc<U, M, A2>& y) noexcept;
template <class U, std::size_t M, std::size_t A> friend class short_alloc;
};
template <class T, std::size_t N, std::size_t A1, class U, std::size_t M, std::size_t A2>
inline
bool
operator==(const short_alloc<T, N, A1>& x, const short_alloc<U, M, A2>& y) noexcept
{
return N == M && A1 == A2 && &x.a_ == &y.a_;
}
template <class T, std::size_t N, std::size_t A1, class U, std::size_t M, std::size_t A2>
inline
bool
operator!=(const short_alloc<T, N, A1>& x, const short_alloc<U, M, A2>& y) noexcept
{
return !(x == y);
}
#endif // SHORT_ALLOC_HPP

View File

@ -0,0 +1,649 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_DYNAMIC_CAST_CONVERSION_HPP_
#define CHAISCRIPT_DYNAMIC_CAST_CONVERSION_HPP_
#include <atomic>
#include <memory>
#include <set>
#include <stdexcept>
#include <string>
#include <type_traits>
#include <typeinfo>
#include "../chaiscript_threading.hpp"
#include "bad_boxed_cast.hpp"
#include "boxed_cast_helper.hpp"
#include "boxed_value.hpp"
#include "type_info.hpp"
namespace chaiscript
{
namespace exception
{
class bad_boxed_dynamic_cast : public bad_boxed_cast
{
public:
bad_boxed_dynamic_cast(const Type_Info &t_from, const std::type_info &t_to,
const std::string &t_what) noexcept
: bad_boxed_cast(t_from, t_to, t_what)
{
}
bad_boxed_dynamic_cast(const Type_Info &t_from, const std::type_info &t_to) noexcept
: bad_boxed_cast(t_from, t_to)
{
}
explicit bad_boxed_dynamic_cast(const std::string &w) noexcept
: bad_boxed_cast(w)
{
}
bad_boxed_dynamic_cast(const bad_boxed_dynamic_cast &) = default;
~bad_boxed_dynamic_cast() noexcept override = default;
};
class bad_boxed_type_cast : public bad_boxed_cast
{
public:
bad_boxed_type_cast(const Type_Info &t_from, const std::type_info &t_to,
const std::string &t_what) noexcept
: bad_boxed_cast(t_from, t_to, t_what)
{
}
bad_boxed_type_cast(const Type_Info &t_from, const std::type_info &t_to) noexcept
: bad_boxed_cast(t_from, t_to)
{
}
explicit bad_boxed_type_cast(const std::string &w) noexcept
: bad_boxed_cast(w)
{
}
bad_boxed_type_cast(const bad_boxed_type_cast &) = default;
~bad_boxed_type_cast() noexcept override = default;
};
}
namespace detail
{
class Type_Conversion_Base
{
public:
virtual Boxed_Value convert(const Boxed_Value &from) const = 0;
virtual Boxed_Value convert_down(const Boxed_Value &to) const = 0;
const Type_Info &to() const
{
return m_to;
}
const Type_Info &from() const
{
return m_from;
}
virtual bool bidir() const
{
return true;
}
virtual ~Type_Conversion_Base() = default;
protected:
Type_Conversion_Base(Type_Info t_to, Type_Info t_from)
: m_to(std::move(t_to)), m_from(std::move(t_from))
{
}
private:
const Type_Info m_to;
const Type_Info m_from;
};
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(
[&](){
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(
[&](){
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
{
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(
[&](){
if (auto data = std::dynamic_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(
[&](){
if (auto data = std::dynamic_pointer_cast<To>(detail::Cast_Helper<std::shared_ptr<From> >::cast(t_from, nullptr)))
{
return data;
} else {
#ifdef CHAISCRIPT_LIBCPP
/// \todo fix this someday after libc++ is fixed.
if (std::string(typeid(To).name()).find("Assignable_Proxy_Function") != std::string::npos) {
auto from = detail::Cast_Helper<std::shared_ptr<From> >::cast(t_from, nullptr);
if (std::string(typeid(*from).name()).find("Assignable_Proxy_Function_Impl") != std::string::npos) {
return std::static_pointer_cast<To>(from);
}
}
#endif
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 = dynamic_cast<const To &>(d);
return Boxed_Value(std::cref(data));
} else {
From &d = detail::Cast_Helper<From &>::cast(t_from, nullptr);
To &data = dynamic_cast<To &>(d);
return Boxed_Value(std::ref(data));
}
}
} else {
throw chaiscript::exception::bad_boxed_dynamic_cast(t_from.get_type_info(), typeid(To), "Unknown dynamic_cast_conversion");
}
}
};
template<typename Base, typename Derived>
class Dynamic_Conversion_Impl : public Type_Conversion_Base
{
public:
Dynamic_Conversion_Impl()
: Type_Conversion_Base(chaiscript::user_type<Base>(), chaiscript::user_type<Derived>())
{
}
Boxed_Value convert_down(const Boxed_Value &t_base) const override
{
return Dynamic_Caster<Base, Derived>::cast(t_base);
}
Boxed_Value convert(const Boxed_Value &t_derived) const override
{
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>())
{
}
Boxed_Value convert_down(const Boxed_Value &t_base) const 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");
}
bool bidir() const override
{
return false;
}
Boxed_Value convert(const Boxed_Value &t_derived) const override
{
return Static_Caster<Derived, Base>::cast(t_derived);
}
};
template<typename Callable>
class Type_Conversion_Impl : public Type_Conversion_Base
{
public:
Type_Conversion_Impl(Type_Info t_from, Type_Info t_to, Callable t_func)
: Type_Conversion_Base(t_to, t_from),
m_func(std::move(t_func))
{
}
Boxed_Value convert_down(const Boxed_Value &) const override
{
throw chaiscript::exception::bad_boxed_type_cast("No conversion exists");
}
Boxed_Value convert(const Boxed_Value &t_from) const override
{
/// \todo better handling of errors from the conversion function
return m_func(t_from);
}
bool bidir() const override
{
return false;
}
private:
Callable m_func;
};
}
class Type_Conversions
{
public:
struct Conversion_Saves
{
bool enabled = false;
std::vector<Boxed_Value> saves;
};
struct Less_Than
{
bool operator()(const std::type_info *t_lhs, const std::type_info *t_rhs) const
{
return *t_lhs != *t_rhs && t_lhs->before(*t_rhs);
}
};
Type_Conversions()
: m_mutex(),
m_conversions(),
m_convertableTypes(),
m_num_types(0)
{
}
Type_Conversions(const Type_Conversions &t_other) = delete;
Type_Conversions(Type_Conversions &&) = default;
Type_Conversions &operator=(const Type_Conversions &) = delete;
Type_Conversions &operator=(Type_Conversions &&) = default;
const std::set<const std::type_info *, Less_Than> &thread_cache() const
{
auto &cache = *m_thread_cache;
if (cache.size() != m_num_types)
{
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
cache = m_convertableTypes;
}
return cache;
}
void add_conversion(const std::shared_ptr<detail::Type_Conversion_Base> &conversion)
{
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
/// \todo error if a conversion already exists
m_conversions.insert(conversion);
m_convertableTypes.insert({conversion->to().bare_type_info(), conversion->from().bare_type_info()});
m_num_types = m_convertableTypes.size();
}
template<typename T>
bool convertable_type() const
{
return thread_cache().count(user_type<T>().bare_type_info()) != 0;
}
template<typename To, typename From>
bool converts() const
{
return converts(user_type<To>(), user_type<From>());
}
bool converts(const Type_Info &to, const Type_Info &from) const
{
const auto &types = thread_cache();
if (types.count(to.bare_type_info()) != 0 && types.count(from.bare_type_info()) != 0)
{
return has_conversion(to, from);
} else {
return false;
}
}
template<typename To>
Boxed_Value boxed_type_conversion(Conversion_Saves &t_saves, const Boxed_Value &from) const
{
return boxed_type_conversion(user_type<To>(), t_saves, from);
}
template<typename From>
Boxed_Value boxed_type_down_conversion(Conversion_Saves &t_saves, const Boxed_Value &to) const
{
return boxed_type_down_conversion(user_type<From>(), t_saves, to);
}
Boxed_Value boxed_type_conversion(const Type_Info &to, Conversion_Saves &t_saves, const Boxed_Value &from) const
{
try {
Boxed_Value ret = get_conversion(to, from.get_type_info())->convert(from);
if (t_saves.enabled) { t_saves.saves.push_back(ret); }
return ret;
} catch (const std::out_of_range &) {
throw exception::bad_boxed_dynamic_cast(from.get_type_info(), *to.bare_type_info(), "No known conversion");
} catch (const std::bad_cast &) {
throw exception::bad_boxed_dynamic_cast(from.get_type_info(), *to.bare_type_info(), "Unable to perform dynamic_cast operation");
}
}
Boxed_Value boxed_type_down_conversion(const Type_Info &from, Conversion_Saves &t_saves, const Boxed_Value &to) const
{
try {
Boxed_Value ret = get_conversion(to.get_type_info(), from)->convert_down(to);
if (t_saves.enabled) { t_saves.saves.push_back(ret); }
return ret;
} catch (const std::out_of_range &) {
throw exception::bad_boxed_dynamic_cast(to.get_type_info(), *from.bare_type_info(), "No known conversion");
} catch (const std::bad_cast &) {
throw exception::bad_boxed_dynamic_cast(to.get_type_info(), *from.bare_type_info(), "Unable to perform dynamic_cast operation");
}
}
static void enable_conversion_saves(Conversion_Saves &t_saves, bool t_val)
{
t_saves.enabled = t_val;
}
std::vector<Boxed_Value> take_saves(Conversion_Saves &t_saves)
{
std::vector<Boxed_Value> ret;
std::swap(ret, t_saves.saves);
return ret;
}
bool has_conversion(const Type_Info &to, const Type_Info &from) const
{
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
return find_bidir(to, from) != m_conversions.end();
}
std::shared_ptr<detail::Type_Conversion_Base> get_conversion(const Type_Info &to, const Type_Info &from) const
{
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
const auto itr = find(to, from);
if (itr != m_conversions.end())
{
return *itr;
} else {
throw std::out_of_range("No such conversion exists from " + from.bare_name() + " to " + to.bare_name());
}
}
Conversion_Saves &conversion_saves() const {
return *m_conversion_saves;
}
private:
std::set<std::shared_ptr<detail::Type_Conversion_Base> >::const_iterator find_bidir(
const Type_Info &to, const Type_Info &from) const
{
return std::find_if(m_conversions.begin(), m_conversions.end(),
[&to, &from](const std::shared_ptr<detail::Type_Conversion_Base> &conversion) -> bool
{
return (conversion->to().bare_equal(to) && conversion->from().bare_equal(from))
|| (conversion->bidir() && conversion->from().bare_equal(to) && conversion->to().bare_equal(from));
}
);
}
std::set<std::shared_ptr<detail::Type_Conversion_Base> >::const_iterator find(
const Type_Info &to, const Type_Info &from) const
{
return std::find_if(m_conversions.begin(), m_conversions.end(),
[&to, &from](const std::shared_ptr<detail::Type_Conversion_Base> &conversion)
{
return conversion->to().bare_equal(to) && conversion->from().bare_equal(from);
}
);
}
std::set<std::shared_ptr<detail::Type_Conversion_Base>> get_conversions() const
{
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
return m_conversions;
}
mutable chaiscript::detail::threading::shared_mutex m_mutex;
std::set<std::shared_ptr<detail::Type_Conversion_Base>> m_conversions;
std::set<const std::type_info *, Less_Than> m_convertableTypes;
std::atomic_size_t m_num_types;
mutable chaiscript::detail::threading::Thread_Storage<std::set<const std::type_info *, Less_Than>> m_thread_cache;
mutable chaiscript::detail::threading::Thread_Storage<Conversion_Saves> m_conversion_saves;
};
class Type_Conversions_State
{
public:
Type_Conversions_State(const Type_Conversions &t_conversions,
Type_Conversions::Conversion_Saves &t_saves)
: m_conversions(t_conversions),
m_saves(t_saves)
{
}
const Type_Conversions *operator->() const {
return &m_conversions.get();
}
const Type_Conversions *get() const {
return &m_conversions.get();
}
Type_Conversions::Conversion_Saves &saves() const {
return m_saves;
}
private:
std::reference_wrapper<const Type_Conversions> m_conversions;
std::reference_wrapper<Type_Conversions::Conversion_Saves> m_saves;
};
typedef std::shared_ptr<chaiscript::detail::Type_Conversion_Base> Type_Conversion;
/// \brief Used to register a to / parent class relationship with ChaiScript. Necessary if you
/// want automatic conversions up your inheritance hierarchy.
///
/// Create a new to class registration for applying to a module or to the ChaiScript engine
/// Currently, due to limitations in module loading on Windows, and for the sake of portability,
/// if you have a type that is introduced in a loadable module and is used by multiple modules
/// (through a tertiary dll that is shared between the modules, static linking the new type
/// into both loadable modules would not be portable), you need to register the type
/// relationship in all modules that use the newly added type in a polymorphic way.
///
/// Example:
/// \code
/// class Base
/// {};
/// class Derived : public Base
/// {};
///
/// chaiscript::ChaiScript chai;
/// chai.add(chaiscript::to_class<Base, Derived>());
/// \endcode
///
template<typename Base, typename Derived>
Type_Conversion base_class(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::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)
{
return chaiscript::make_shared<detail::Type_Conversion_Base, detail::Type_Conversion_Impl<Callable>>(t_from, t_to, t_func);
}
template<typename From, typename To, typename Callable>
Type_Conversion type_conversion(const Callable &t_function)
{
auto func = [t_function](const Boxed_Value &t_bv) -> Boxed_Value {
// not even attempting to call boxed_cast so that we don't get caught in some call recursion
return chaiscript::Boxed_Value(t_function(detail::Cast_Helper<const From &>::cast(t_bv, nullptr)));
};
return chaiscript::make_shared<detail::Type_Conversion_Base, detail::Type_Conversion_Impl<decltype(func)>>(user_type<From>(), user_type<To>(), func);
}
template<typename From, typename To>
Type_Conversion type_conversion()
{
static_assert(std::is_convertible<From, To>::value, "Types are not automatically convertible");
auto func = [](const Boxed_Value &t_bv) -> Boxed_Value {
// not even attempting to call boxed_cast so that we don't get caught in some call recursion
return chaiscript::Boxed_Value(To(detail::Cast_Helper<From>::cast(t_bv, nullptr)));
};
return chaiscript::make_shared<detail::Type_Conversion_Base, detail::Type_Conversion_Impl<decltype(func)>>(user_type<From>(), user_type<To>(), func);
}
template<typename To>
Type_Conversion vector_conversion()
{
auto func = [](const Boxed_Value &t_bv) -> Boxed_Value {
const std::vector<Boxed_Value> &from_vec = detail::Cast_Helper<const std::vector<Boxed_Value> &>::cast(t_bv, nullptr);
To vec;
vec.reserve(from_vec.size());
for (const Boxed_Value &bv : from_vec) {
vec.push_back(detail::Cast_Helper<typename To::value_type>::cast(bv, nullptr));
}
return Boxed_Value(std::move(vec));
};
return chaiscript::make_shared<detail::Type_Conversion_Base, detail::Type_Conversion_Impl<decltype(func)>>(user_type<std::vector<Boxed_Value>>(), user_type<To>(), func);
}
template<typename To>
Type_Conversion map_conversion()
{
auto func = [](const Boxed_Value &t_bv) -> Boxed_Value {
const std::map<std::string, Boxed_Value> &from_map = detail::Cast_Helper<const std::map<std::string, Boxed_Value> &>::cast(t_bv, nullptr);
To map;
for (const std::pair<std::string, Boxed_Value> &p : from_map) {
map.insert(std::make_pair(p.first, detail::Cast_Helper<typename To::mapped_type>::cast(p.second, nullptr)));
}
return Boxed_Value(std::move(map));
};
return chaiscript::make_shared<detail::Type_Conversion_Base, detail::Type_Conversion_Impl<decltype(func)>>(user_type<std::map<std::string, Boxed_Value>>(), user_type<To>(), func);
}
}
#endif

View File

@ -1,17 +1,20 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_TYPE_INFO_HPP_
#define CHAISCRIPT_TYPE_INFO_HPP_
#include <functional>
#include <memory>
#include <string>
#include <type_traits>
#include <typeinfo>
#include <string>
namespace chaiscript
{
@ -30,70 +33,66 @@ namespace chaiscript
class Type_Info
{
public:
CHAISCRIPT_CONSTEXPR Type_Info(bool t_is_const, bool t_is_reference, bool t_is_pointer, bool t_is_void,
bool t_is_arithmetic, const std::type_info *t_ti, const std::type_info *t_bareti)
: m_type_info(t_ti), m_bare_type_info(t_bareti),
m_is_const(t_is_const), m_is_reference(t_is_reference), m_is_pointer(t_is_pointer),
m_is_void(t_is_void), m_is_arithmetic(t_is_arithmetic),
m_is_undef(false)
constexpr Type_Info(const bool t_is_const, const bool t_is_reference, const bool t_is_pointer, const bool t_is_void,
const bool t_is_arithmetic, const std::type_info *t_ti, const std::type_info *t_bare_ti)
: m_type_info(t_ti), m_bare_type_info(t_bare_ti),
m_flags((static_cast<unsigned int>(t_is_const) << is_const_flag)
+ (static_cast<unsigned int>(t_is_reference) << is_reference_flag)
+ (static_cast<unsigned int>(t_is_pointer) << is_pointer_flag)
+ (static_cast<unsigned int>(t_is_void) << is_void_flag)
+ (static_cast<unsigned int>(t_is_arithmetic) << is_arithmetic_flag))
{
}
CHAISCRIPT_CONSTEXPR Type_Info()
: m_type_info(nullptr), m_bare_type_info(nullptr),
m_is_const(false), m_is_reference(false), m_is_pointer(false),
m_is_void(false), m_is_arithmetic(false),
m_is_undef(true)
{
}
constexpr Type_Info() = default;
#if !defined(_MSC_VER) || _MSC_VER != 1800
Type_Info(Type_Info&&) = default;
Type_Info& operator=(Type_Info&&) = default;
#endif
Type_Info(const Type_Info&) = default;
Type_Info& operator=(const Type_Info&) = default;
CHAISCRIPT_CONSTEXPR bool operator<(const Type_Info &ti) const CHAISCRIPT_NOEXCEPT
constexpr bool operator<(const Type_Info &ti) const noexcept
{
return m_type_info < ti.m_type_info;
}
CHAISCRIPT_CONSTEXPR bool operator==(const Type_Info &ti) const CHAISCRIPT_NOEXCEPT
constexpr bool operator!=(const Type_Info &ti) const noexcept
{
return ti.m_type_info == m_type_info
|| (ti.m_type_info && m_type_info && *ti.m_type_info == *m_type_info);
return !(operator==(ti));
}
CHAISCRIPT_CONSTEXPR bool operator==(const std::type_info &ti) const CHAISCRIPT_NOEXCEPT
constexpr bool operator!=(const std::type_info &ti) const noexcept
{
return m_type_info != nullptr && (*m_type_info) == ti;
return !(operator==(ti));
}
CHAISCRIPT_CONSTEXPR bool bare_equal(const Type_Info &ti) const CHAISCRIPT_NOEXCEPT
constexpr bool operator==(const Type_Info &ti) const noexcept
{
return ti.m_bare_type_info == m_bare_type_info
|| (ti.m_bare_type_info && m_bare_type_info && *ti.m_bare_type_info == *m_bare_type_info);
return ti.m_type_info == m_type_info
|| *ti.m_type_info == *m_type_info;
}
CHAISCRIPT_CONSTEXPR bool bare_equal_type_info(const std::type_info &ti) const CHAISCRIPT_NOEXCEPT
constexpr bool operator==(const std::type_info &ti) const noexcept
{
return m_bare_type_info != nullptr
&& (*m_bare_type_info) == ti;
return !is_undef() && (*m_type_info) == ti;
}
CHAISCRIPT_CONSTEXPR bool is_const() const CHAISCRIPT_NOEXCEPT { return m_is_const; }
CHAISCRIPT_CONSTEXPR bool is_reference() const CHAISCRIPT_NOEXCEPT { return m_is_reference; }
CHAISCRIPT_CONSTEXPR bool is_void() const CHAISCRIPT_NOEXCEPT { return m_is_void; }
CHAISCRIPT_CONSTEXPR bool is_arithmetic() const CHAISCRIPT_NOEXCEPT { return m_is_arithmetic; }
CHAISCRIPT_CONSTEXPR bool is_undef() const CHAISCRIPT_NOEXCEPT { return m_is_undef || m_bare_type_info == nullptr; }
CHAISCRIPT_CONSTEXPR bool is_pointer() const CHAISCRIPT_NOEXCEPT { return m_is_pointer; }
constexpr bool bare_equal(const Type_Info &ti) const noexcept
{
return ti.m_bare_type_info == m_bare_type_info
|| *ti.m_bare_type_info == *m_bare_type_info;
}
constexpr bool bare_equal_type_info(const std::type_info &ti) const noexcept
{
return !is_undef() && (*m_bare_type_info) == ti;
}
constexpr bool is_const() const noexcept { return (m_flags & (1 << is_const_flag)) != 0; }
constexpr bool is_reference() const noexcept { return (m_flags & (1 << is_reference_flag)) != 0; }
constexpr bool is_void() const noexcept { return (m_flags & (1 << is_void_flag)) != 0; }
constexpr bool is_arithmetic() const noexcept { return (m_flags & (1 << is_arithmetic_flag)) != 0; }
constexpr bool is_undef() const noexcept { return (m_flags & (1 << is_undef_flag)) != 0; }
constexpr bool is_pointer() const noexcept { return (m_flags & (1 << is_pointer_flag)) != 0; }
std::string name() const
{
if (m_type_info)
if (!is_undef())
{
return m_type_info->name();
} else {
@ -101,9 +100,9 @@ namespace chaiscript
}
}
std::string bare_name() const
std::string bare_name() const
{
if (m_bare_type_info)
if (!is_undef())
{
return m_bare_type_info->name();
} else {
@ -111,33 +110,39 @@ namespace chaiscript
}
}
constexpr const std::type_info *bare_type_info() const
{
return m_bare_type_info;
}
private:
const std::type_info *m_type_info;
const std::type_info *m_bare_type_info;
bool m_is_const;
bool m_is_reference;
bool m_is_pointer;
bool m_is_void;
bool m_is_arithmetic;
bool m_is_undef;
struct Unknown_Type {};
const std::type_info *m_type_info = &typeid(Unknown_Type);
const std::type_info *m_bare_type_info = &typeid(Unknown_Type);
static const int is_const_flag = 0;
static const int is_reference_flag = 1;
static const int is_pointer_flag = 2;
static const int is_void_flag = 3;
static const int is_arithmetic_flag = 4;
static const int is_undef_flag = 5;
unsigned int m_flags = (1 << is_undef_flag);
};
namespace detail
{
/**
* Helper used to create a Type_Info object
*/
/// Helper used to create a Type_Info object
template<typename T>
struct Get_Type_Info
{
typedef T type;
CHAISCRIPT_CONSTEXPR static Type_Info get()
static constexpr 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));
}
};
@ -145,28 +150,31 @@ namespace chaiscript
template<typename T>
struct Get_Type_Info<std::shared_ptr<T> >
{
typedef T type;
// typedef T type;
CHAISCRIPT_CONSTEXPR static Type_Info get()
static constexpr Type_Info get()
{
return Type_Info(std::is_const<T>::value, std::is_reference<T>::value, std::is_pointer<T>::value,
std::is_void<T>::value,
std::is_arithmetic<T>::value && !std::is_same<typename std::remove_const<T>::type, bool>::value,
std::is_arithmetic<T>::value && !std::is_same<typename std::remove_const<typename std::remove_reference<T>::type>::type, bool>::value,
&typeid(std::shared_ptr<T> ),
&typeid(typename Bare_Type<T>::type));
}
};
template<typename T>
struct Get_Type_Info<std::shared_ptr<T> &> : Get_Type_Info<std::shared_ptr<T>>
{
};
template<typename T>
struct Get_Type_Info<const std::shared_ptr<T> &>
{
typedef T type;
CHAISCRIPT_CONSTEXPR static Type_Info get()
static constexpr 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));
}
@ -175,13 +183,11 @@ namespace chaiscript
template<typename T>
struct Get_Type_Info<std::reference_wrapper<T> >
{
typedef T type;
CHAISCRIPT_CONSTEXPR static Type_Info get()
static constexpr 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));
}
@ -190,13 +196,11 @@ namespace chaiscript
template<typename T>
struct Get_Type_Info<const std::reference_wrapper<T> &>
{
typedef T type;
CHAISCRIPT_CONSTEXPR static Type_Info get()
static constexpr 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));
}
@ -214,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*/)
constexpr Type_Info user_type(const T &/*t*/)
{
return detail::Get_Type_Info<T>::get();
}
@ -229,7 +233,7 @@ namespace chaiscript
/// chaiscript::Type_Info ti = chaiscript::user_type<int>();
/// \endcode
template<typename T>
CHAISCRIPT_CONSTEXPR Type_Info user_type()
constexpr Type_Info user_type()
{
return detail::Get_Type_Info<T>::get();
}

View File

@ -1,21 +1,25 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_ALGEBRAIC_HPP_
#define CHAISCRIPT_ALGEBRAIC_HPP_
#include <string>
#include "../utility/fnv1a.hpp"
#include "../dispatchkit/dispatchkit.hpp"
#include <string>
namespace chaiscript
{
struct Operators {
enum Opers
enum class Opers
{
boolean_flag,
equals, less_than, greater_than, less_than_equal, greater_than_equal, not_equal,
@ -33,7 +37,7 @@ namespace chaiscript
};
static const char *to_string(Opers t_oper) {
const char *opers[] = {
static const char *opers[] = {
"",
"==", "<", ">", "<=", ">=", "!=",
"",
@ -48,81 +52,53 @@ namespace chaiscript
"+", "/", "*", "-", "+", "-",
""
};
return opers[t_oper];
return opers[static_cast<int>(t_oper)];
}
static Opers to_operator(const std::string &t_str, bool t_is_unary = false)
{
if (t_str == "==")
{
return equals;
} else if (t_str == "<") {
return less_than;
} else if (t_str == ">") {
return greater_than;
} else if (t_str == "<=") {
return less_than_equal;
} else if (t_str == ">=") {
return greater_than_equal;
} else if (t_str == "!=") {
return not_equal;
} else if (t_str == "=") {
return assign;
} else if (t_str == "++") {
return pre_increment;
} else if (t_str == "--") {
return pre_decrement;
} else if (t_str == "*=") {
return assign_product;
} else if (t_str == "+=") {
return assign_sum;
} else if (t_str == "-=") {
return assign_difference;
} else if (t_str == "&=") {
return assign_bitwise_and;
} else if (t_str == "|=") {
return assign_bitwise_or;
} else if (t_str == "<<=") {
return assign_shift_left;
} else if (t_str == ">>=") {
return assign_shift_right;
} else if (t_str == "%=") {
return assign_remainder;
} else if (t_str == "^=") {
return assign_bitwise_xor;
} else if (t_str == "<<") {
return shift_left;
} else if (t_str == ">>") {
return shift_right;
} else if (t_str == "%") {
return remainder;
} else if (t_str == "&") {
return bitwise_and;
} else if (t_str == "|") {
return bitwise_or;
} else if (t_str == "^") {
return bitwise_xor;
} else if (t_str == "~") {
return bitwise_complement;
} else if (t_str == "+") {
if (t_is_unary) {
return unary_plus;
} else {
return sum;
}
} else if (t_str == "-") {
if (t_is_unary) {
return unary_minus;
} else {
return difference;
}
} else if (t_str == "/") {
return quotient;
} else if (t_str == "*") {
return product;
} else {
return invalid;
}
#ifdef CHAISCRIPT_MSVC
#pragma warning(push)
#pragma warning(disable : 4307)
#endif
const auto op_hash = utility::fnv1a_32(t_str.c_str());
switch (op_hash) {
case utility::fnv1a_32("=="): { return Opers::equals; }
case utility::fnv1a_32("<"): { return Opers::less_than; }
case utility::fnv1a_32(">"): { return Opers::greater_than; }
case utility::fnv1a_32("<="): { return Opers::less_than_equal; }
case utility::fnv1a_32(">="): { return Opers::greater_than_equal; }
case utility::fnv1a_32("!="): { return Opers::not_equal; }
case utility::fnv1a_32("="): { return Opers::assign; }
case utility::fnv1a_32("++"): { return Opers::pre_increment; }
case utility::fnv1a_32("--"): { return Opers::pre_decrement; }
case utility::fnv1a_32("*="): { return Opers::assign_product; }
case utility::fnv1a_32("+="): { return Opers::assign_sum; }
case utility::fnv1a_32("-="): { return Opers::assign_difference; }
case utility::fnv1a_32("&="): { return Opers::assign_bitwise_and; }
case utility::fnv1a_32("|="): { return Opers::assign_bitwise_or; }
case utility::fnv1a_32("<<="): { return Opers::assign_shift_left; }
case utility::fnv1a_32(">>="): { return Opers::assign_shift_right; }
case utility::fnv1a_32("%="): { return Opers::assign_remainder; }
case utility::fnv1a_32("^="): { return Opers::assign_bitwise_xor; }
case utility::fnv1a_32("<<"): { return Opers::shift_left; }
case utility::fnv1a_32(">>"): { return Opers::shift_right; }
case utility::fnv1a_32("%"): { return Opers::remainder; }
case utility::fnv1a_32("&"): { return Opers::bitwise_and; }
case utility::fnv1a_32("|"): { return Opers::bitwise_or; }
case utility::fnv1a_32("^"): { return Opers::bitwise_xor; }
case utility::fnv1a_32("~"): { return Opers::bitwise_complement; }
case utility::fnv1a_32("+"): { return t_is_unary ? Opers::unary_plus : Opers::sum; }
case utility::fnv1a_32("-"): { return t_is_unary ? Opers::unary_minus : Opers::difference; }
case utility::fnv1a_32("/"): { return Opers::quotient; }
case utility::fnv1a_32("*"): { return Opers::product; }
default: { return Opers::invalid; }
}
#ifdef CHAISCRIPT_MSVC
#pragma warning(pop)
#endif
}
};

View File

@ -1,9 +1,13 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_COMMON_HPP_
#define CHAISCRIPT_COMMON_HPP_
@ -26,33 +30,60 @@ struct AST_Node;
namespace chaiscript
{
struct Name_Validator {
static bool is_reserved_word(const std::string &name)
{
static const std::set<std::string> m_reserved_words
= {"def", "fun", "while", "for", "if", "else", "&&", "||", ",", "auto",
"return", "break", "true", "false", "class", "attr", "var", "global", "GLOBAL", "_",
"__LINE__", "__FILE__", "__FUNC__", "__CLASS__"};
return m_reserved_words.count(name) > 0;
}
static bool valid_object_name(const std::string &name)
{
return name.find("::") == std::string::npos && !is_reserved_word(name);
}
static void validate_object_name(const std::string &name)
{
if (is_reserved_word(name)) {
throw exception::reserved_word_error(name);
}
if (name.find("::") != std::string::npos) {
throw exception::illegal_name_error(name);
}
}
};
/// Signature of module entry point that all binary loadable modules must implement.
typedef ModulePtr (*Create_Module_Func)();
/// 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,
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,
Logical_And, Logical_Or, Reference, Switch, Case, Default, Ternary_Cond, Noop, Class
};
enum class AST_Node_Type { Id, Fun_Call, Unused_Return_Fun_Call, Arg_List, Equation, Var_Decl,
Array_Call, Dot_Access,
Lambda, Block, Scopeless_Block, Def, While, If, For, Ranged_For, Inline_Array, Inline_Map, Return, File, Prefix, Break, Continue, Map_Pair, Value_Range,
Inline_Range, Try, Catch, Finally, Method, Attr_Decl,
Logical_And, Logical_Or, Reference, Switch, Case, Default, Noop, Class, Binary, Arg, Global_Decl, Constant, Compiled
};
enum class Operator_Precidence { Ternary_Cond, Logical_Or,
Logical_And, Bitwise_Or, Bitwise_Xor, Bitwise_And,
Equality, Comparison, Shift, Addition, Multiplication, Prefix };
namespace
{
/// 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",
"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",
"Logical_And", "Logical_Or", "Reference", "Switch", "Case", "Default", "Ternary Condition", "Noop"};
inline const char *ast_node_type_to_string(AST_Node_Type ast_node_type) {
static const char * const ast_node_types[] = { "Id", "Fun_Call", "Unused_Return_Fun_Call", "Arg_List", "Equation", "Var_Decl",
"Array_Call", "Dot_Access",
"Lambda", "Block", "Scopeless_Block", "Def", "While", "If", "For", "Ranged_For", "Inline_Array", "Inline_Map", "Return", "File", "Prefix", "Break", "Continue", "Map_Pair", "Value_Range",
"Inline_Range", "Try", "Catch", "Finally", "Method", "Attr_Decl",
"Logical_And", "Logical_Or", "Reference", "Switch", "Case", "Default", "Noop", "Class", "Binary", "Arg", "Global_Decl", "Constant", "Compiled"};
return ast_node_types[ast_node_type];
return ast_node_types[static_cast<int>(ast_node_type)];
}
}
@ -67,6 +98,31 @@ namespace chaiscript
File_Position() : line(0), column(0) { }
};
struct Parse_Location {
Parse_Location(std::string t_fname="", const int t_start_line=0, const int t_start_col=0,
const int t_end_line=0, const int t_end_col=0)
: start(t_start_line, t_start_col),
end(t_end_line, t_end_col),
filename(std::make_shared<std::string>(std::move(t_fname)))
{
}
Parse_Location(std::shared_ptr<std::string> t_fname, const int t_start_line=0, const int t_start_col=0,
const int t_end_line=0, const int t_end_col=0)
: start(t_start_line, t_start_col),
end(t_end_line, t_end_col),
filename(std::move(t_fname))
{
}
File_Position start;
File_Position end;
std::shared_ptr<std::string> filename;
};
/// \brief Typedef for pointers to AST_Node objects. Used in building of the AST_Node tree
typedef std::shared_ptr<AST_Node> AST_NodePtr;
typedef std::shared_ptr<const AST_Node> AST_NodePtr_Const;
@ -75,12 +131,41 @@ namespace chaiscript
/// \brief Classes which may be thrown during error cases when ChaiScript is executing.
namespace exception
{
/// \brief Thrown if an error occurs while attempting to load a binary module
struct load_module_error : std::runtime_error
{
explicit load_module_error(const std::string &t_reason) noexcept
: std::runtime_error(t_reason)
{
}
load_module_error(const std::string &t_name, const std::vector<load_module_error> &t_errors)
: std::runtime_error(format_error(t_name, t_errors))
{
}
load_module_error(const load_module_error &) = default;
~load_module_error() noexcept override = default;
static std::string format_error(const std::string &t_name, const std::vector<load_module_error> &t_errors)
{
std::stringstream ss;
ss << "Error loading module '" << t_name << "'\n"
<< " The following locations were searched:\n";
for (const auto &err : t_errors) {
ss << " " << err.what() << "\n";
}
return ss.str();
}
};
/// Errors generated during parsing or evaluation
struct eval_error : public std::runtime_error {
struct eval_error : std::runtime_error {
std::string reason;
File_Position start_position;
File_Position end_position;
std::string filename;
std::string detail;
std::vector<AST_NodePtr_Const> call_stack;
@ -88,58 +173,60 @@ namespace chaiscript
eval_error(const std::string &t_why, const File_Position &t_where, const std::string &t_fname,
const std::vector<Boxed_Value> &t_parameters, const std::vector<chaiscript::Const_Proxy_Function> &t_functions,
bool t_dot_notation,
const chaiscript::detail::Dispatch_Engine &t_ss) CHAISCRIPT_NOEXCEPT :
const chaiscript::detail::Dispatch_Engine &t_ss) noexcept :
std::runtime_error(format(t_why, t_where, t_fname, t_parameters, t_dot_notation, t_ss)),
reason(t_why), start_position(t_where), end_position(t_where), filename(t_fname), detail(format_detail(t_functions, t_dot_notation, t_ss))
reason(t_why), start_position(t_where), filename(t_fname), detail(format_detail(t_functions, t_dot_notation, t_ss))
{}
eval_error(const std::string &t_why,
const std::vector<Boxed_Value> &t_parameters, const std::vector<chaiscript::Const_Proxy_Function> &t_functions,
bool t_dot_notation,
const chaiscript::detail::Dispatch_Engine &t_ss) CHAISCRIPT_NOEXCEPT :
const chaiscript::detail::Dispatch_Engine &t_ss) noexcept :
std::runtime_error(format(t_why, t_parameters, t_dot_notation, t_ss)),
reason(t_why), detail(format_detail(t_functions, t_dot_notation, t_ss))
{}
eval_error(const std::string &t_why, const File_Position &t_where, const std::string &t_fname) CHAISCRIPT_NOEXCEPT :
eval_error(const std::string &t_why, const File_Position &t_where, const std::string &t_fname) noexcept :
std::runtime_error(format(t_why, t_where, t_fname)),
reason(t_why), start_position(t_where), end_position(t_where), filename(t_fname)
reason(t_why), start_position(t_where), filename(t_fname)
{}
eval_error(const std::string &t_why) CHAISCRIPT_NOEXCEPT
explicit eval_error(const std::string &t_why) noexcept
: std::runtime_error("Error: \"" + t_why + "\" "),
reason(t_why)
{}
eval_error(const eval_error &) = default;
std::string pretty_print() const
{
std::ostringstream ss;
ss << what();
if (call_stack.size() > 0) {
ss << "during evaluation at (" << fname(call_stack[0]) << " " << startpos(call_stack[0]) << ")" << std::endl;
ss << std::endl << detail << std::endl;
if (!call_stack.empty()) {
ss << "during evaluation at (" << fname(call_stack[0]) << " " << startpos(call_stack[0]) << ")\n";
ss << '\n' << detail << '\n';
ss << " " << fname(call_stack[0]) << " (" << startpos(call_stack[0]) << ") '" << pretty(call_stack[0]) << "'";
for (size_t j = 1; j < call_stack.size(); ++j) {
if (id(call_stack[j]) != chaiscript::AST_Node_Type::Block
&& id(call_stack[j]) != chaiscript::AST_Node_Type::File)
{
ss << std::endl;
ss << '\n';
ss << " from " << fname(call_stack[j]) << " (" << startpos(call_stack[j]) << ") '" << pretty(call_stack[j]) << "'";
}
}
}
ss << std::endl;
ss << '\n';
return ss.str();
}
virtual ~eval_error() CHAISCRIPT_NOEXCEPT {}
~eval_error() noexcept override = default;
private:
template<typename T>
static int id(const T& t)
static AST_Node_Type id(const T& t)
{
return t->identifier;
}
@ -151,16 +238,16 @@ namespace chaiscript
}
template<typename T>
static std::string fname(const T& t)
static const std::string &fname(const T& t)
{
return *t->filename;
return t->filename();
}
template<typename T>
static std::string startpos(const T& t)
{
std::ostringstream oss;
oss << t->start.line << ", " << t->start.column;
oss << t->start().line << ", " << t->start().column;
return oss.str();
}
@ -227,8 +314,7 @@ namespace chaiscript
if (f)
{
std::shared_ptr<const dispatch::Dynamic_Proxy_Function> dynfunguard
= std::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(f);
auto dynfunguard = std::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(f);
if (dynfunguard)
{
retval += " : " + format_guard(dynfunguard->get_parse_tree());
@ -250,10 +336,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)";
}
}
@ -264,13 +353,13 @@ namespace chaiscript
std::stringstream ss;
if (t_functions.size() == 1)
{
ss << " Expected: " << format_types(t_functions[0], t_dot_notation, t_ss) << std::endl;
ss << " Expected: " << format_types(t_functions[0], t_dot_notation, t_ss) << '\n';
} else {
ss << " " << t_functions.size() << " overloads available:" << std::endl;
ss << " " << t_functions.size() << " overloads available:\n";
for (const auto & t_function : t_functions)
{
ss << " " << format_types((t_function), t_dot_notation, t_ss) << std::endl;
ss << " " << format_types((t_function), t_dot_notation, t_ss) << '\n';
}
}
@ -390,12 +479,13 @@ namespace chaiscript
/// Errors generated when loading a file
struct file_not_found_error : public std::runtime_error {
file_not_found_error(const std::string &t_filename) CHAISCRIPT_NOEXCEPT
struct file_not_found_error : std::runtime_error {
explicit file_not_found_error(const std::string &t_filename) noexcept
: std::runtime_error("File Not Found: " + t_filename)
{ }
virtual ~file_not_found_error() CHAISCRIPT_NOEXCEPT {}
file_not_found_error(const file_not_found_error &) = default;
~file_not_found_error() noexcept override = default;
};
}
@ -404,178 +494,209 @@ namespace chaiscript
/// \brief Struct that doubles as both a parser ast_node and an AST node.
struct AST_Node : std::enable_shared_from_this<AST_Node> {
public:
const AST_Node_Type identifier;
const std::string text;
const int identifier; //< \todo shouldn't this be a strongly typed enum value?
std::shared_ptr<const std::string> filename;
File_Position start, end;
std::vector<AST_NodePtr> children;
AST_NodePtr annotation;
Parse_Location location;
virtual std::string pretty_print() const
const std::string &filename() const {
return *location.filename;
}
const File_Position &start() const {
return location.start;
}
const File_Position &end() const {
return location.end;
}
std::string pretty_print() const
{
std::ostringstream oss;
oss << text;
for (auto & elem : this->children) {
oss << elem->pretty_print();
for (auto & elem : this->get_children()) {
oss << elem->pretty_print() << ' ';
}
return oss.str();
}
virtual std::vector<AST_NodePtr> get_children() const = 0;
virtual Boxed_Value eval(const chaiscript::detail::Dispatch_State &t_e) const = 0;
/// Prints the contents of an AST node, including its children, recursively
std::string to_string(const std::string &t_prepend = "") const {
std::ostringstream oss;
oss << t_prepend << "(" << ast_node_type_to_string(this->identifier) << ") "
<< this->text << " : " << this->start.line << ", " << this->start.column << std::endl;
<< 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->get_children()) {
oss << elem->to_string(t_prepend + " ");
}
return oss.str();
}
Boxed_Value eval(chaiscript::detail::Dispatch_Engine &t_e) const
{
static bool get_bool_condition(const Boxed_Value &t_bv, const chaiscript::detail::Dispatch_State &t_ss) {
try {
return eval_internal(t_e);
} catch (exception::eval_error &ee) {
ee.call_stack.push_back(shared_from_this());
throw;
return t_ss->boxed_cast<bool>(t_bv);
}
catch (const exception::bad_boxed_cast &) {
throw exception::eval_error("Condition not boolean");
}
}
void replace_child(const AST_NodePtr &t_child, const AST_NodePtr &t_new_child)
{
std::replace(children.begin(), children.end(), t_child, t_new_child);
}
virtual ~AST_Node() = default;
AST_Node(AST_Node &&) = default;
AST_Node &operator=(AST_Node &&) = default;
AST_Node(const AST_Node &) = delete;
AST_Node& operator=(const AST_Node &) = delete;
protected:
AST_Node(std::string t_ast_node_text, int t_id, const std::shared_ptr<std::string> &t_fname,
int t_start_line, int t_start_col, int t_end_line, int t_end_col) :
text(std::move(t_ast_node_text)), identifier(t_id), filename(t_fname),
start(t_start_line, t_start_col), end(t_end_line, t_end_col)
AST_Node(std::string t_ast_node_text, AST_Node_Type t_id, Parse_Location t_loc)
: identifier(t_id), text(std::move(t_ast_node_text)),
location(std::move(t_loc))
{
}
AST_Node(std::string t_ast_node_text, int t_id, const std::shared_ptr<std::string> &t_fname) :
text(std::move(t_ast_node_text)), identifier(t_id), filename(t_fname) {}
virtual ~AST_Node() {}
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &) const
{
throw std::runtime_error("Undispatched ast_node (internal error)");
}
private:
// Copy and assignment explicitly unimplemented
AST_Node(const AST_Node &);
AST_Node& operator=(const AST_Node &);
};
namespace parser {
class ChaiScript_Parser_Base
{
public:
virtual AST_NodePtr parse(const std::string &t_input, const std::string &t_fname) = 0;
virtual void debug_print(AST_NodePtr t, std::string prepend = "") const = 0;
virtual void *get_tracer_ptr() = 0;
virtual ~ChaiScript_Parser_Base() = default;
ChaiScript_Parser_Base() = default;
ChaiScript_Parser_Base(ChaiScript_Parser_Base &&) = default;
ChaiScript_Parser_Base &operator=(ChaiScript_Parser_Base &&) = delete;
ChaiScript_Parser_Base &operator=(const ChaiScript_Parser_Base &&) = delete;
template<typename T>
T &get_tracer()
{
// to do type check this somehow?
return *static_cast<T*>(get_tracer_ptr());
}
protected:
ChaiScript_Parser_Base(const ChaiScript_Parser_Base &) = default;
};
}
namespace eval
{
namespace detail
{
/// Special type for returned values
struct Return_Value {
Boxed_Value retval;
Return_Value(const Boxed_Value &t_return_value) : retval(t_return_value) { }
explicit Return_Value(Boxed_Value t_return_value) : retval(std::move(t_return_value)) { }
};
/// Special type indicating a call to 'break'
struct Break_Loop {
Break_Loop() { }
Break_Loop() = default;
};
/// Special type indicating a call to 'continue'
struct Continue_Loop {
Continue_Loop() { }
Continue_Loop() = default;
};
/// Creates a new scope then pops it on destruction
struct Scope_Push_Pop
{
Scope_Push_Pop(Scope_Push_Pop &&) = default;
Scope_Push_Pop& operator=(Scope_Push_Pop &&) = default;
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)
explicit Scope_Push_Pop(const chaiscript::detail::Dispatch_State &t_ds)
: m_ds(t_ds)
{
m_de.new_scope();
m_ds->new_scope(m_ds.stack_holder());
}
~Scope_Push_Pop()
{
m_de.pop_scope();
m_ds->pop_scope(m_ds.stack_holder());
}
private:
chaiscript::detail::Dispatch_Engine &m_de;
const chaiscript::detail::Dispatch_State &m_ds;
};
/// Creates a new function call and pops it on destruction
struct Function_Push_Pop
{
Function_Push_Pop(Function_Push_Pop &&) = default;
Function_Push_Pop& operator=(Function_Push_Pop &&) = default;
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)
explicit Function_Push_Pop(const chaiscript::detail::Dispatch_State &t_ds)
: m_ds(t_ds)
{
m_de.new_function_call();
m_ds->new_function_call(m_ds.stack_holder(), m_ds.conversion_saves());
}
~Function_Push_Pop()
{
m_de.pop_function_call();
m_ds->pop_function_call(m_ds.stack_holder(), m_ds.conversion_saves());
}
void save_params(const std::vector<Boxed_Value> &t_params)
{
m_de.save_function_params(t_params);
m_ds->save_function_params(t_params);
}
void save_params(std::initializer_list<Boxed_Value> t_params)
{
m_ds->save_function_params(t_params);
}
private:
chaiscript::detail::Dispatch_Engine &m_de;
const chaiscript::detail::Dispatch_State &m_ds;
};
/// Creates a new scope then pops it on destruction
struct Stack_Push_Pop
{
Stack_Push_Pop(Stack_Push_Pop &&) = default;
Stack_Push_Pop& operator=(Stack_Push_Pop &&) = default;
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)
explicit Stack_Push_Pop(const chaiscript::detail::Dispatch_State &t_ds)
: m_ds(t_ds)
{
m_de.new_stack();
m_ds->new_stack(m_ds.stack_holder());
}
~Stack_Push_Pop()
{
m_de.pop_stack();
m_ds->pop_stack(m_ds.stack_holder());
}
private:
chaiscript::detail::Dispatch_Engine &m_de;
const chaiscript::detail::Dispatch_State &m_ds;
};
}
}

View File

@ -1,15 +1,17 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_ENGINE_HPP_
#define CHAISCRIPT_ENGINE_HPP_
#include <cassert>
#include <cstring>
#include <algorithm>
#include <exception>
#include <fstream>
#include <functional>
@ -18,15 +20,15 @@
#include <mutex>
#include <set>
#include <stdexcept>
#include <string>
#include <vector>
#include <cstring>
#include "../chaiscript_defines.hpp"
#include "../chaiscript_threading.hpp"
#include "../dispatchkit/boxed_cast_helper.hpp"
#include "../dispatchkit/boxed_value.hpp"
#include "../dispatchkit/dispatchkit.hpp"
#include "../dispatchkit/dynamic_cast_conversion.hpp"
#include "../dispatchkit/type_conversions.hpp"
#include "../dispatchkit/proxy_functions.hpp"
#include "chaiscript_common.hpp"
@ -34,229 +36,34 @@
#include <unistd.h>
#endif
#if defined(_POSIX_VERSION) && !defined(__CYGWIN__)
#if !defined(CHAISCRIPT_NO_DYNLOAD) && defined(_POSIX_VERSION) && !defined(__CYGWIN__)
#include <dlfcn.h>
#else
#ifdef CHAISCRIPT_WINDOWS
#define VC_EXTRA_LEAN
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#endif
#if defined(CHAISCRIPT_NO_DYNLOAD)
#include "chaiscript_unknown.hpp"
#elif defined(CHAISCRIPT_WINDOWS)
#include "chaiscript_windows.hpp"
#elif _POSIX_VERSION
#include "chaiscript_posix.hpp"
#else
#include "chaiscript_unknown.hpp"
#endif
#include "../dispatchkit/exception_specification.hpp"
#include "chaiscript_parser.hpp"
#include "chaiscript_prelude.chai"
namespace chaiscript
{
namespace exception
{
/// \brief Thrown if an error occurs while attempting to load a binary module
struct load_module_error : std::runtime_error
{
load_module_error(const std::string &t_reason) CHAISCRIPT_NOEXCEPT
: std::runtime_error(t_reason)
{
}
virtual ~load_module_error() CHAISCRIPT_NOEXCEPT
{
}
};
}
namespace detail
{
#if defined(_POSIX_VERSION) && !defined(__CYGWIN__)
struct Loadable_Module
{
struct DLModule
{
DLModule(const std::string &t_filename)
: m_data(dlopen(t_filename.c_str(), RTLD_NOW))
{
if (!m_data)
{
throw chaiscript::exception::load_module_error(dlerror());
}
}
DLModule(const DLModule &); // Explicitly unimplemented copy constructor
DLModule &operator=(const DLModule &); // Explicitly unimplemented assignment operator
~DLModule()
{
dlclose(m_data);
}
void *m_data;
};
template<typename T>
struct DLSym
{
DLSym(DLModule &t_mod, const std::string &t_symbol)
: m_symbol(cast_symbol(dlsym(t_mod.m_data, t_symbol.c_str())))
{
if (!m_symbol)
{
throw chaiscript::exception::load_module_error(dlerror());
}
}
static T cast_symbol(void *p)
{
union cast_union
{
T func_ptr;
void *in_ptr;
};
cast_union c;
c.in_ptr = p;
return c.func_ptr;
}
T m_symbol;
};
Loadable_Module(const std::string &t_module_name, const std::string &t_filename)
: m_dlmodule(t_filename), m_func(m_dlmodule, "create_chaiscript_module_" + t_module_name),
m_moduleptr(m_func.m_symbol())
{
}
DLModule m_dlmodule;
DLSym<Create_Module_Func> m_func;
ModulePtr m_moduleptr;
};
#else
#ifdef WIN32
struct Loadable_Module
{
template<typename T>
static std::wstring to_wstring(const T &t_str)
{
return std::wstring(t_str.begin(), t_str.end());
}
template<typename T>
static std::string to_string(const T &t_str)
{
return std::string(t_str.begin(), t_str.end());
}
#ifdef _UNICODE
template<typename T>
static std::wstring to_proper_string(const T &t_str)
{
return to_wstring(t_str);
}
#else
template<typename T>
static std::string to_proper_string(const T &t_str)
{
return to_string(t_str);
}
#endif
static std::string get_error_message(DWORD t_err)
{
#ifdef _UNICODE
typedef LPWSTR StringType;
std::wstring retval = L"Unknown Error";
#else
typedef LPSTR StringType;
std::string retval = "Unknown Error";
#endif
StringType lpMsgBuf = nullptr;
if (FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
t_err,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(StringType)&lpMsgBuf,
0, NULL ) != 0 && lpMsgBuf)
{
retval = lpMsgBuf;
LocalFree(lpMsgBuf);
}
return to_string(retval);
}
struct DLModule
{
DLModule(const std::string &t_filename)
: m_data(LoadLibrary(to_proper_string(t_filename).c_str()))
{
if (!m_data)
{
throw chaiscript::exception::load_module_error(get_error_message(GetLastError()));
}
}
~DLModule()
{
FreeLibrary(m_data);
}
HMODULE m_data;
};
template<typename T>
struct DLSym
{
DLSym(DLModule &t_mod, const std::string &t_symbol)
: m_symbol(reinterpret_cast<T>(GetProcAddress(t_mod.m_data, t_symbol.c_str())))
{
if (!m_symbol)
{
throw chaiscript::exception::load_module_error(get_error_message(GetLastError()));
}
}
T m_symbol;
};
Loadable_Module(const std::string &t_module_name, const std::string &t_filename)
: m_dlmodule(t_filename), m_func(m_dlmodule, "create_chaiscript_module_" + t_module_name),
m_moduleptr(m_func.m_symbol())
{
}
DLModule m_dlmodule;
DLSym<Create_Module_Func> m_func;
ModulePtr m_moduleptr;
};
#else
struct Loadable_Module
{
Loadable_Module(const std::string &, const std::string &)
{
throw chaiscript::exception::load_module_error("Loadable module support not available for your platform");
}
ModulePtr m_moduleptr;
};
#endif
#endif
typedef std::shared_ptr<Loadable_Module> Loadable_Module_Ptr;
}
/// \brief The main object that the ChaiScript user will use.
class ChaiScript {
class ChaiScript_Basic {
mutable chaiscript::detail::threading::shared_mutex m_mutex;
mutable chaiscript::detail::threading::recursive_mutex m_use_mutex;
@ -265,8 +72,10 @@ namespace chaiscript
std::map<std::string, detail::Loadable_Module_Ptr> m_loaded_modules;
std::set<std::string> m_active_loaded_modules;
std::vector<std::string> m_modulepaths;
std::vector<std::string> m_usepaths;
std::vector<std::string> m_module_paths;
std::vector<std::string> m_use_paths;
std::unique_ptr<parser::ChaiScript_Parser_Base> m_parser;
chaiscript::detail::Dispatch_Engine m_engine;
@ -274,13 +83,8 @@ namespace chaiscript
Boxed_Value do_eval(const std::string &t_input, const std::string &t_filename = "__EVAL__", bool /* t_internal*/ = false)
{
try {
parser::ChaiScript_Parser parser;
if (parser.parse(t_input, t_filename)) {
//parser.show_match_stack();
return parser.ast()->eval(m_engine);
} else {
return Boxed_Value();
}
const auto p = m_parser->parse(t_input, t_filename);
return p->eval(chaiscript::detail::Dispatch_State(m_engine));
}
catch (chaiscript::eval::detail::Return_Value &rv) {
return rv.retval;
@ -289,13 +93,23 @@ 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) {
for (const auto &path : m_use_paths)
{
try {
const auto appendedpath = path + t_filename;
return do_eval(load_file(appendedpath), appendedpath, true);
} catch (const exception::file_not_found_error &) {
// failed to load, try the next path
} catch (const exception::eval_error &t_ee) {
throw Boxed_Value(t_ee);
}
}
// failed to load by any name
throw exception::file_not_found_error(t_filename);
}
@ -315,64 +129,72 @@ namespace chaiscript
}
/// Builds all the requirements for ChaiScript, including its evaluator and a run of its prelude.
void build_eval_system(const ModulePtr &t_lib) {
m_engine.add_reserved_word("def");
m_engine.add_reserved_word("fun");
m_engine.add_reserved_word("while");
m_engine.add_reserved_word("for");
m_engine.add_reserved_word("if");
m_engine.add_reserved_word("else");
m_engine.add_reserved_word("&&");
m_engine.add_reserved_word("||");
m_engine.add_reserved_word(",");
m_engine.add_reserved_word("auto");
m_engine.add_reserved_word("return");
m_engine.add_reserved_word("break");
m_engine.add_reserved_word("true");
m_engine.add_reserved_word("false");
m_engine.add_reserved_word("class");
m_engine.add_reserved_word("_");
void build_eval_system(const ModulePtr &t_lib, const std::vector<Options> &t_opts) {
if (t_lib)
{
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(Proxy_Function(new 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");
m_engine.add(fun<Boxed_Value (const dispatch::Proxy_Function_Base *, const std::vector<Boxed_Value> &)>(std::bind(&chaiscript::dispatch::Proxy_Function_Base::operator(), std::placeholders::_1, std::placeholders::_2, std::ref(m_engine.conversions()))), "call");
m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::get_type_name, std::ref(m_engine)), "name");
})
, "call_exists");
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(
[=](const dispatch::Proxy_Function_Base &t_fun, const std::vector<Boxed_Value> &t_params) -> Boxed_Value {
Type_Conversions_State s(this->m_engine.conversions(), this->m_engine.conversions().conversion_saves());
return t_fun(t_params, s);
}), "call");
m_engine.add(fun(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(&ChaiScript::use, this), "use");
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 Type_Info &t_ti){ return m_engine.get_type_name(t_ti); }), "name");
m_engine.add(fun(&ChaiScript::version_major, this), "version_major");
m_engine.add(fun(&ChaiScript::version_minor, this), "version_minor");
m_engine.add(fun(&ChaiScript::version_patch, this), "version_patch");
m_engine.add(fun(&ChaiScript::version, this), "version");
m_engine.add(fun([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(&ChaiScript::add_global_const, this), "add_global_const");
m_engine.add(fun(&ChaiScript::add_global, this), "add_global");
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");
do_eval(ChaiScript_Prelude::chaiscript_prelude(), "standard prelude");
if (std::find(t_opts.begin(), t_opts.end(), Options::No_Load_Modules) == t_opts.end()
&& std::find(t_opts.begin(), t_opts.end(), Options::Load_Modules) != t_opts.end())
{
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");
}
if (std::find(t_opts.begin(), t_opts.end(), Options::No_External_Scripts) == t_opts.end()
&& std::find(t_opts.begin(), t_opts.end(), Options::External_Scripts) != t_opts.end())
{
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([this](const std::string &t_str, const bool t_dump){ return parse(t_str, t_dump); }), "parse");
m_engine.add(fun([this](const std::string &t_str){ return parse(t_str); }), "parse");
m_engine.add(fun([this](const Boxed_Value &t_bv, const std::string &t_name){ add_global_const(t_bv, t_name); }), "add_global_const");
m_engine.add(fun([this](const Boxed_Value &t_bv, const std::string &t_name){ add_global(t_bv, t_name); }), "add_global");
m_engine.add(fun([this](const Boxed_Value &t_bv, const std::string &t_name){ set_global(t_bv, t_name); }), "set_global");
}
@ -399,65 +221,43 @@ namespace chaiscript
}
}
std::vector<std::string> ensure_minimum_path_vec(std::vector<std::string> paths)
{
if (paths.empty()) { return {""}; }
else { return paths; }
}
public:
/// \brief Constructor for ChaiScript
/// \param[in] t_lib Standard library to apply to this ChaiScript instance
/// \param[in] t_modulepaths Vector of paths to search when attempting to load a binary module
/// \param[in] t_usepaths Vector of paths to search when attempting to "use" an included ChaiScript file
ChaiScript(const ModulePtr &t_lib,
std::vector<std::string> t_modulepaths = std::vector<std::string>(),
std::vector<std::string> t_usepaths = std::vector<std::string>())
: m_modulepaths(std::move(t_modulepaths)), m_usepaths(std::move(t_usepaths))
ChaiScript_Basic(const ModulePtr &t_lib,
std::unique_ptr<parser::ChaiScript_Parser_Base> &&parser,
std::vector<std::string> t_module_paths = {},
std::vector<std::string> t_use_paths = {},
const std::vector<chaiscript::Options> &t_opts = chaiscript::default_options())
: m_module_paths(ensure_minimum_path_vec(std::move(t_module_paths))),
m_use_paths(ensure_minimum_path_vec(std::move(t_use_paths))),
m_parser(std::move(parser)),
m_engine(*m_parser)
{
if (m_modulepaths.empty())
{
m_modulepaths.push_back("");
}
if (m_usepaths.empty())
{
m_usepaths.push_back("");
}
build_eval_system(t_lib);
}
/// \brief Constructor for ChaiScript.
///
/// This version of the ChaiScript constructor attempts to find the stdlib module to load
/// at runtime generates an error if it cannot be found.
///
/// \param[in] t_modulepaths Vector of paths to search when attempting to load a binary module
/// \param[in] t_usepaths Vector of paths to search when attempting to "use" an included ChaiScript file
ChaiScript( std::vector<std::string> t_modulepaths = std::vector<std::string>(),
std::vector<std::string> t_usepaths = std::vector<std::string>())
: m_modulepaths(std::move(t_modulepaths)), m_usepaths(std::move(t_usepaths))
{
if (m_modulepaths.empty())
{
m_modulepaths.push_back("");
}
if (m_usepaths.empty())
{
m_usepaths.push_back("");
}
#if defined(_POSIX_VERSION) && !defined(__CYGWIN__)
#if !defined(CHAISCRIPT_NO_DYNLOAD) && defined(_POSIX_VERSION) && !defined(__CYGWIN__)
// If on Unix, add the path of the current executable to the module search path
// as windows would do
union cast_union
{
void (ChaiScript::*in_ptr)(const std::string&);
Boxed_Value (ChaiScript_Basic::*in_ptr)(const std::string&);
void *out_ptr;
};
Dl_info rInfo;
memset( &rInfo, 0, sizeof(rInfo) );
cast_union u;
u.in_ptr = &ChaiScript::use;
if ( dladdr((void*)(u.out_ptr), &rInfo) && rInfo.dli_fname ) {
u.in_ptr = &ChaiScript_Basic::use;
if ( (dladdr(static_cast<void*>(u.out_ptr), &rInfo) != 0) && (rInfo.dli_fname != nullptr) ) {
std::string dllpath(rInfo.dli_fname);
const size_t lastslash = dllpath.rfind('/');
if (lastslash != std::string::npos)
@ -467,44 +267,78 @@ namespace chaiscript
// Let's see if this is a link that we should expand
std::vector<char> buf(2048);
const size_t pathlen = readlink(dllpath.c_str(), &buf.front(), buf.size());
if (pathlen > 0 && pathlen < buf.size())
const auto pathlen = readlink(dllpath.c_str(), &buf.front(), buf.size());
if (pathlen > 0 && static_cast<size_t>(pathlen) < buf.size())
{
dllpath = std::string(&buf.front(), pathlen);
dllpath = std::string(&buf.front(), static_cast<size_t>(pathlen));
}
m_modulepaths.insert(m_modulepaths.begin(), dllpath+"/");
m_module_paths.insert(m_module_paths.begin(), dllpath+"/");
}
#endif
// attempt to load the stdlib
load_module("chaiscript_stdlib-" + version());
build_eval_system(ModulePtr());
build_eval_system(t_lib, t_opts);
}
int version_major() const
#ifndef CHAISCRIPT_NO_DYNLOAD
/// \brief Constructor for ChaiScript.
///
/// This version of the ChaiScript constructor attempts to find the stdlib module to load
/// at runtime generates an error if it cannot be found.
///
/// \param[in] t_modulepaths Vector of paths to search when attempting to load a binary module
/// \param[in] t_usepaths Vector of paths to search when attempting to "use" an included ChaiScript file
explicit ChaiScript_Basic(std::unique_ptr<parser::ChaiScript_Parser_Base> &&parser,
std::vector<std::string> t_module_paths = {},
std::vector<std::string> t_use_paths = {},
const std::vector<chaiscript::Options> &t_opts = chaiscript::default_options())
: ChaiScript_Basic({}, std::move(parser), t_module_paths, t_use_paths, t_opts)
{
return chaiscript::version_major;
try {
// attempt to load the stdlib
load_module("chaiscript_stdlib-" + Build_Info::version());
} catch (const exception::load_module_error &t_err) {
std::cout << "An error occured while trying to load the chaiscript standard library.\n"
<< "\n"
<< "You must either provide a standard library, or compile it in.\n"
<< "For an example of compiling the standard library in,\n"
<< "see: https://gist.github.com/lefticus/9456197\n"
<< "Compiling the stdlib in is the recommended and MOST SUPPORTED method.\n"
<< "\n"
<< "\n"
<< t_err.what();
throw;
}
}
#else // CHAISCRIPT_NO_DYNLOAD
explicit ChaiScript_Basic(std::unique_ptr<parser::ChaiScript_Parser_Base> &&parser,
std::vector<std::string> t_module_paths = {},
std::vector<std::string> t_use_paths = {},
const std::vector<chaiscript::Options> &t_opts = chaiscript::default_options()) = delete;
#endif
parser::ChaiScript_Parser_Base &get_parser()
{
return *m_parser;
}
int version_minor() const
const Boxed_Value eval(const AST_NodePtr &t_ast)
{
return chaiscript::version_minor;
try {
return t_ast->eval(chaiscript::detail::Dispatch_State(m_engine));
} catch (const exception::eval_error &t_ee) {
throw Boxed_Value(t_ee);
}
}
int version_patch() const
AST_NodePtr parse(const std::string &t_input, const bool t_debug_print = false)
{
return chaiscript::version_patch;
const auto ast = m_parser->parse(t_input, "PARSE");
if (t_debug_print) {
m_parser->debug_print(ast);
}
return ast;
}
std::string version() const
{
std::stringstream ss;
ss << version_major() << "." << version_minor() << "." << version_patch();
return ss.str();
}
std::string get_type_name(const Type_Info &ti) const
{
@ -523,9 +357,9 @@ namespace chaiscript
/// requested file.
///
/// \param[in] t_filename Filename to load and evaluate
void use(const std::string &t_filename)
Boxed_Value use(const std::string &t_filename)
{
for (const auto &path : m_usepaths)
for (const auto &path : m_use_paths)
{
try {
const auto appendedpath = path + t_filename;
@ -533,15 +367,17 @@ namespace chaiscript
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::recursive_mutex> l(m_use_mutex);
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l2(m_mutex);
Boxed_Value retval;
if (m_used_files.count(appendedpath) == 0)
{
l2.unlock();
eval_file(appendedpath);
retval = eval_file(appendedpath);
l2.lock();
m_used_files.insert(appendedpath);
}
}
return; // return, we loaded it, or it was already loaded
return retval; // return, we loaded it, or it was already loaded
} catch (const exception::file_not_found_error &) {
// failed to load, try the next path
}
@ -556,8 +392,9 @@ namespace chaiscript
/// \param[in] t_name Name of the value to add
/// \throw chaiscript::exception::global_non_const If t_bv is not a constant object
/// \sa Boxed_Value::is_const
ChaiScript &add_global_const(const Boxed_Value &t_bv, const std::string &t_name)
ChaiScript_Basic &add_global_const(const Boxed_Value &t_bv, const std::string &t_name)
{
Name_Validator::validate_object_name(t_name);
m_engine.add_global_const(t_bv, t_name);
return *this;
}
@ -567,13 +404,23 @@ namespace chaiscript
/// \param[in] t_name Name of the value to add
/// \warning The user is responsible for making sure the object is thread-safe if necessary
/// ChaiScript is thread-safe but provides no threading locking mechanism to the script
ChaiScript &add_global(const Boxed_Value &t_bv, const std::string &t_name)
ChaiScript_Basic &add_global(const Boxed_Value &t_bv, const std::string &t_name)
{
Name_Validator::validate_object_name(t_name);
m_engine.add_global(t_bv, t_name);
return *this;
}
ChaiScript_Basic &set_global(const Boxed_Value &t_bv, const std::string &t_name)
{
Name_Validator::validate_object_name(t_name);
m_engine.set_global(t_bv, t_name);
return *this;
}
/// \brief Represents the current state of the ChaiScript system. State and be saved and restored
/// \warning State object does not contain the user defined type conversions of the engine. They
/// are left out due to performance considerations involved in tracking the state
/// \sa ChaiScript::get_state
/// \sa ChaiScript::set_state
struct State
@ -596,7 +443,7 @@ namespace chaiscript
/// chaiscript::ChaiScript chai;
/// chaiscript::ChaiScript::State s = chai.get_state(); // represents bootstrapped initial state
/// \endcode
State get_state()
State get_state() const
{
chaiscript::detail::threading::lock_guard<chaiscript::detail::threading::recursive_mutex> l(m_use_mutex);
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l2(m_mutex);
@ -664,8 +511,9 @@ namespace chaiscript
///
/// \sa \ref adding_items
template<typename T>
ChaiScript &add(const T &t_t, const std::string &t_name)
ChaiScript_Basic &add(const T &t_t, const std::string &t_name)
{
Name_Validator::validate_object_name(t_name);
m_engine.add(t_t, t_name);
return *this;
}
@ -679,7 +527,7 @@ namespace chaiscript
/// chaiscript::ChaiScript chai;
/// chai.add(chaiscript::base_class<std::runtime_error, chaiscript::dispatch_error>());
/// \endcode
ChaiScript &add(const Dynamic_Cast_Conversion &d)
ChaiScript_Basic &add(const Type_Conversion &d)
{
m_engine.add(d);
return *this;
@ -688,7 +536,7 @@ namespace chaiscript
/// \brief Adds all elements of a module to ChaiScript runtime
/// \param[in] t_p The module to add.
/// \sa chaiscript::Module
ChaiScript &add(const ModulePtr &t_p)
ChaiScript_Basic &add(const ModulePtr &t_p)
{
t_p->apply(*this, this->get_eval_engine());
return *this;
@ -699,7 +547,7 @@ namespace chaiscript
/// \param[in] t_module_name Name of the module to load
///
/// The module is searched for in the registered module path folders (chaiscript::ChaiScript::ChaiScript)
/// and with standard prefixes and postfixes: ("lib"|"")\<t_module_name\>(".dll"|".so"|"").
/// and with standard prefixes and postfixes: ("lib"|"")\<t_module_name\>(".dll"|".so"|".bundle"|"").
///
/// Once the file is located, the system looks for the symbol "create_chaiscript_module_\<t_module_name\>".
/// If no file can be found matching the search criteria and containing the appropriate entry point
@ -708,9 +556,13 @@ namespace chaiscript
/// \throw chaiscript::exception::load_module_error In the event that no matching module can be found.
std::string load_module(const std::string &t_module_name)
{
#ifdef CHAISCRIPT_NO_DYNLOAD
(void)t_module_name; // -Wunused-parameter
throw chaiscript::exception::load_module_error("Loadable module support was disabled (CHAISCRIPT_NO_DYNLOAD)");
#else
std::vector<exception::load_module_error> errors;
std::string version_stripped_name = t_module_name;
size_t version_pos = version_stripped_name.find("-"+version());
size_t version_pos = version_stripped_name.find("-" + Build_Info::version());
if (version_pos != std::string::npos)
{
version_stripped_name.erase(version_pos);
@ -718,9 +570,9 @@ namespace chaiscript
std::vector<std::string> prefixes{"lib", "cyg", ""};
std::vector<std::string> postfixes{".dll", ".so", ""};
std::vector<std::string> postfixes{".dll", ".so", ".bundle", ""};
for (auto & elem : m_modulepaths)
for (auto & elem : m_module_paths)
{
for (auto & prefix : prefixes)
{
@ -728,11 +580,11 @@ namespace chaiscript
{
try {
const auto name = elem + prefix + t_module_name + postfix;
// std::cerr << "trying location: " << name << std::endl;
// std::cerr << "trying location: " << name << '\n';
load_module(version_stripped_name, name);
return name;
} catch (const chaiscript::exception::load_module_error &e) {
// std::cerr << "error: " << e.what() << std::endl;
// std::cerr << "error: " << e.what() << '\n';
errors.push_back(e);
// Try next set
}
@ -740,21 +592,8 @@ namespace chaiscript
}
}
std::string errstring;
for (std::vector<exception::load_module_error>::const_iterator itr = errors.begin();
itr != errors.end();
++itr)
{
if (!errstring.empty())
{
errstring += "; ";
}
errstring += itr->what();
}
throw chaiscript::exception::load_module_error("Unable to find module: " + t_module_name + " Errors: " + errstring);
throw chaiscript::exception::load_module_error(t_module_name, errors);
#endif
}
/// \brief Load a binary module from a dynamic library. Works on platforms that support
@ -791,14 +630,7 @@ namespace chaiscript
/// \throw chaiscript::exception::eval_error In the case that evaluation fails.
Boxed_Value operator()(const std::string &t_script, const Exception_Handler &t_handler = Exception_Handler())
{
try {
return do_eval(t_script);
} catch (Boxed_Value &bv) {
if (t_handler) {
t_handler->handle(bv, m_engine);
}
throw;
}
return eval(t_script, t_handler);
}
/// \brief Evaluates a string and returns a typesafe result.
@ -817,21 +649,14 @@ namespace chaiscript
template<typename T>
T eval(const std::string &t_input, const Exception_Handler &t_handler = Exception_Handler(), const std::string &t_filename="__EVAL__")
{
try {
return m_engine.boxed_cast<T>(do_eval(t_input, t_filename));
} catch (Boxed_Value &bv) {
if (t_handler) {
t_handler->handle(bv, m_engine);
}
throw;
}
return m_engine.boxed_cast<T>(eval(t_input, t_handler, t_filename));
}
/// \brief casts an object while applying any Dynamic_Conversion available
template<typename Type>
typename detail::Cast_Helper<Type>::Result_Type boxed_cast(const Boxed_Value &bv) const
decltype(auto) boxed_cast(const Boxed_Value &bv) const
{
return m_engine.boxed_cast<Type>(bv);
return(m_engine.boxed_cast<Type>(bv));
}
@ -863,14 +688,7 @@ namespace chaiscript
/// \return result of the script execution
/// \throw chaiscript::exception::eval_error In the case that evaluation fails.
Boxed_Value eval_file(const std::string &t_filename, const Exception_Handler &t_handler = Exception_Handler()) {
try {
return do_eval(load_file(t_filename), t_filename);
} catch (Boxed_Value &bv) {
if (t_handler) {
t_handler->handle(bv, m_engine);
}
throw;
}
return eval(load_file(t_filename), t_handler, t_filename);
}
/// \brief Loads the file specified by filename, evaluates it, and returns the type safe result.
@ -883,14 +701,7 @@ namespace chaiscript
/// to the requested type.
template<typename T>
T eval_file(const std::string &t_filename, const Exception_Handler &t_handler = Exception_Handler()) {
try {
return m_engine.boxed_cast<T>(do_eval(load_file(t_filename), t_filename));
} catch (Boxed_Value &bv) {
if (t_handler) {
t_handler->handle(bv, m_engine);
}
throw;
}
return m_engine.boxed_cast<T>(eval_file(t_filename, t_handler));
}
};

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,427 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_OPTIMIZER_HPP_
#define CHAISCRIPT_OPTIMIZER_HPP_
#include "chaiscript_eval.hpp"
namespace chaiscript {
namespace optimizer {
template<typename ... T>
struct Optimizer : T...
{
Optimizer() = default;
explicit Optimizer(T ... t)
: T(std::move(t))...
{
}
template<typename Tracer>
auto optimize(eval::AST_Node_Impl_Ptr<Tracer> p) {
(void)std::initializer_list<int>{ (p = static_cast<T&>(*this).optimize(p), 0)... };
return p;
}
};
template<typename T>
auto child_at(const eval::AST_Node_Impl_Ptr<T> &node, const size_t offset) {
if (node->children[offset]->identifier == AST_Node_Type::Compiled) {
return dynamic_cast<const eval::Compiled_AST_Node<T>&>(*node->children[offset]).m_original_node;
} else {
return node->children[offset];
}
/*
if (node->identifier == AST_Node_Type::Compiled) {
return dynamic_cast<const eval::Compiled_AST_Node<T>&>(*node).m_original_node->children[offset];
} else {
return node->children[offset];
}
*/
}
template<typename T>
auto child_count(const eval::AST_Node_Impl_Ptr<T> &node) {
if (node->identifier == AST_Node_Type::Compiled) {
return dynamic_cast<const eval::Compiled_AST_Node<T>&>(*node).m_original_node->children.size();
} else {
return node->children.size();
}
}
template<typename T, typename Callable>
auto make_compiled_node(const eval::AST_Node_Impl_Ptr<T> &original_node, std::vector<eval::AST_Node_Impl_Ptr<T>> children, Callable callable)
{
return chaiscript::make_shared<eval::AST_Node_Impl<T>, eval::Compiled_AST_Node<T>>(original_node, std::move(children), std::move(callable));
}
struct Return {
template<typename T>
auto optimize(const eval::AST_Node_Impl_Ptr<T> &p)
{
if ( (p->identifier == AST_Node_Type::Def || p->identifier == AST_Node_Type::Lambda)
&& !p->children.empty())
{
auto &last_child = p->children.back();
if (last_child->identifier == AST_Node_Type::Block) {
auto &block_last_child = last_child->children.back();
if (block_last_child->identifier == AST_Node_Type::Return) {
if (block_last_child->children.size() == 1) {
last_child->children.back() = block_last_child->children[0];
}
}
}
}
return p;
}
};
template<typename T>
bool contains_var_decl_in_scope(const T &node)
{
if (node->identifier == AST_Node_Type::Var_Decl) {
return true;
}
const auto num = child_count(node);
for (size_t i = 0; i < num; ++i) {
const auto &child = child_at(node, i);
if (child->identifier != AST_Node_Type::Block
&& child->identifier != AST_Node_Type::For
&& contains_var_decl_in_scope(child)) {
return true;
}
}
return false;
}
struct Block {
template<typename T>
auto optimize(const eval::AST_Node_Impl_Ptr<T> &node) {
if (node->identifier == AST_Node_Type::Block)
{
if (!contains_var_decl_in_scope(node))
{
if (node->children.size() == 1) {
return node->children[0];
} else {
return chaiscript::make_shared<eval::AST_Node_Impl<T>, eval::Scopeless_Block_AST_Node<T>>(node->text, node->location, node->children);
}
}
}
return node;
}
};
struct Dead_Code {
template<typename T>
auto optimize(const eval::AST_Node_Impl_Ptr<T> &node) {
if (node->identifier == AST_Node_Type::Block)
{
std::vector<size_t> keepers;
const auto num_children = node->children.size();
keepers.reserve(num_children);
for (size_t i = 0; i < num_children; ++i) {
auto child = node->children[i];
if ( (child->identifier != AST_Node_Type::Id
&& child->identifier != AST_Node_Type::Constant
&& child->identifier != AST_Node_Type::Noop)
|| i == num_children - 1) {
keepers.push_back(i);
}
}
if (keepers.size() == num_children) {
return node;
} else {
std::vector<eval::AST_Node_Impl_Ptr<T>> new_children;
for (const auto x : keepers)
{
new_children.push_back(node->children[x]);
}
return chaiscript::make_shared<eval::AST_Node_Impl<T>, eval::Block_AST_Node<T>>(node->text, node->location, new_children);
}
} else {
return node;
}
}
};
struct Unused_Return {
template<typename T>
auto optimize(const eval::AST_Node_Impl_Ptr<T> &node) {
if ((node->identifier == AST_Node_Type::Block
|| node->identifier == AST_Node_Type::Scopeless_Block)
&& !node->children.empty())
{
for (size_t i = 0; i < node->children.size()-1; ++i) {
auto child = node->children[i];
if (child->identifier == AST_Node_Type::Fun_Call) {
node->children[i] = chaiscript::make_shared<eval::AST_Node_Impl<T>, eval::Unused_Return_Fun_Call_AST_Node<T>>(child->text, child->location, std::move(child->children));
}
}
} else if ((node->identifier == AST_Node_Type::For
|| node->identifier == AST_Node_Type::While)
&& child_count(node) > 0) {
auto child = child_at(node, child_count(node) - 1);
if (child->identifier == AST_Node_Type::Block
|| child->identifier == AST_Node_Type::Scopeless_Block)
{
auto num_sub_children = child_count(child);
for (size_t i = 0; i < num_sub_children; ++i) {
auto sub_child = child_at(child, i);
if (sub_child->identifier == AST_Node_Type::Fun_Call) {
child->children[i] = chaiscript::make_shared<eval::AST_Node_Impl<T>, eval::Unused_Return_Fun_Call_AST_Node<T>>(sub_child->text, sub_child->location, std::move(sub_child->children));
}
}
}
}
return node;
}
};
struct If {
template<typename T>
auto optimize(const eval::AST_Node_Impl_Ptr<T> &node) {
if ((node->identifier == AST_Node_Type::If)
&& node->children.size() >= 2
&& node->children[0]->identifier == AST_Node_Type::Constant)
{
const auto condition = std::dynamic_pointer_cast<eval::Constant_AST_Node<T>>(node->children[0])->m_value;
if (condition.get_type_info().bare_equal_type_info(typeid(bool))) {
if (boxed_cast<bool>(condition)) {
return node->children[1];
} else if (node->children.size() == 3) {
return node->children[2];
}
}
}
return node;
}
};
struct Partial_Fold {
template<typename T>
auto optimize(const eval::AST_Node_Impl_Ptr<T> &node) {
// Fold right side
if (node->identifier == AST_Node_Type::Binary
&& node->children.size() == 2
&& node->children[0]->identifier != AST_Node_Type::Constant
&& node->children[1]->identifier == AST_Node_Type::Constant)
{
try {
const auto &oper = node->text;
const auto parsed = Operators::to_operator(oper);
if (parsed != Operators::Opers::invalid) {
const auto rhs = std::dynamic_pointer_cast<eval::Constant_AST_Node<T>>(node->children[1])->m_value;
if (rhs.get_type_info().is_arithmetic()) {
return chaiscript::make_shared<eval::AST_Node_Impl<T>, eval::Fold_Right_Binary_Operator_AST_Node<T>>(node->text, node->location, node->children, rhs);
}
}
} catch (const std::exception &) {
//failure to fold, that's OK
}
}
return node;
}
};
struct Constant_Fold {
template<typename T>
auto optimize(const eval::AST_Node_Impl_Ptr<T> &node) {
if (node->identifier == AST_Node_Type::Prefix
&& node->children.size() == 1
&& node->children[0]->identifier == AST_Node_Type::Constant)
{
try {
const auto &oper = node->text;
const auto parsed = Operators::to_operator(oper, true);
const auto lhs = std::dynamic_pointer_cast<eval::Constant_AST_Node<T>>(node->children[0])->m_value;
const auto match = oper + node->children[0]->text;
if (parsed != Operators::Opers::invalid && parsed != Operators::Opers::bitwise_and && lhs.get_type_info().is_arithmetic()) {
const auto val = Boxed_Number::do_oper(parsed, lhs);
return chaiscript::make_shared<eval::AST_Node_Impl<T>, eval::Constant_AST_Node<T>>(std::move(match), node->location, std::move(val));
} else if (lhs.get_type_info().bare_equal_type_info(typeid(bool)) && oper == "!") {
return chaiscript::make_shared<eval::AST_Node_Impl<T>, eval::Constant_AST_Node<T>>(std::move(match), node->location, Boxed_Value(!boxed_cast<bool>(lhs)));
}
} catch (const std::exception &) {
//failure to fold, that's OK
}
} else if ((node->identifier == AST_Node_Type::Logical_And || node->identifier == AST_Node_Type::Logical_Or)
&& node->children.size() == 2
&& node->children[0]->identifier == AST_Node_Type::Constant
&& node->children[1]->identifier == AST_Node_Type::Constant)
{
try {
const auto lhs = std::dynamic_pointer_cast<eval::Constant_AST_Node<T>>(node->children[0])->m_value;
const auto rhs = std::dynamic_pointer_cast<eval::Constant_AST_Node<T>>(node->children[1])->m_value;
if (lhs.get_type_info().bare_equal_type_info(typeid(bool)) && rhs.get_type_info().bare_equal_type_info(typeid(bool))) {
const auto match = node->children[0]->text + " " + node->text + " " + node->children[1]->text;
const auto val = [lhs_val = boxed_cast<bool>(lhs), rhs_val = boxed_cast<bool>(rhs), id = node->identifier] {
if (id == AST_Node_Type::Logical_And) { return Boxed_Value(lhs_val && rhs_val); }
else { return Boxed_Value(lhs_val || rhs_val); }
}();
return chaiscript::make_shared<eval::AST_Node_Impl<T>, eval::Constant_AST_Node<T>>(std::move(match), node->location, std::move(val));
}
} catch (const std::exception &) {
//failure to fold, that's OK
}
} else if (node->identifier == AST_Node_Type::Binary
&& node->children.size() == 2
&& node->children[0]->identifier == AST_Node_Type::Constant
&& node->children[1]->identifier == AST_Node_Type::Constant)
{
try {
const auto &oper = node->text;
const auto parsed = Operators::to_operator(oper);
if (parsed != Operators::Opers::invalid) {
const auto lhs = std::dynamic_pointer_cast<eval::Constant_AST_Node<T>>(node->children[0])->m_value;
const auto rhs = std::dynamic_pointer_cast<eval::Constant_AST_Node<T>>(node->children[1])->m_value;
if (lhs.get_type_info().is_arithmetic() && rhs.get_type_info().is_arithmetic()) {
const auto val = Boxed_Number::do_oper(parsed, lhs, rhs);
const auto match = node->children[0]->text + " " + oper + " " + node->children[1]->text;
return chaiscript::make_shared<eval::AST_Node_Impl<T>, eval::Constant_AST_Node<T>>(std::move(match), node->location, std::move(val));
}
}
} catch (const std::exception &) {
//failure to fold, that's OK
}
} else if (node->identifier == AST_Node_Type::Fun_Call
&& node->children.size() == 2
&& node->children[0]->identifier == AST_Node_Type::Id
&& node->children[1]->identifier == AST_Node_Type::Arg_List
&& node->children[1]->children.size() == 1
&& node->children[1]->children[0]->identifier == AST_Node_Type::Constant) {
const auto arg = std::dynamic_pointer_cast<eval::Constant_AST_Node<T>>(node->children[1]->children[0])->m_value;
if (arg.get_type_info().is_arithmetic()) {
const auto &fun_name = node->children[0]->text;
const auto make_constant = [&node, &fun_name](auto val){
const auto match = fun_name + "(" + node->children[1]->children[0]->text + ")";
return chaiscript::make_shared<eval::AST_Node_Impl<T>, eval::Constant_AST_Node<T>>(std::move(match), node->location, Boxed_Value(val));
};
if (fun_name == "double") {
return make_constant(Boxed_Number(arg).get_as<double>());
} else if (fun_name == "int") {
return make_constant(Boxed_Number(arg).get_as<int>());
} else if (fun_name == "float") {
return make_constant(Boxed_Number(arg).get_as<float>());
} else if (fun_name == "long") {
return make_constant(Boxed_Number(arg).get_as<long>());
} else if (fun_name == "size_t") {
return make_constant(Boxed_Number(arg).get_as<size_t>());
}
}
}
return node;
}
};
struct For_Loop {
template<typename T>
auto optimize(const eval::AST_Node_Impl_Ptr<T> &for_node) {
if (for_node->identifier != AST_Node_Type::For) {
return for_node;
}
const auto eq_node = child_at(for_node, 0);
const auto binary_node = child_at(for_node, 1);
const auto prefix_node = child_at(for_node, 2);
if (eq_node->identifier == AST_Node_Type::Equation
&& child_count(eq_node) == 2
&& child_at(eq_node, 0)->identifier == AST_Node_Type::Var_Decl
&& child_at(eq_node, 1)->identifier == AST_Node_Type::Constant
&& binary_node->identifier == AST_Node_Type::Binary
&& binary_node->text == "<"
&& child_count(binary_node) == 2
&& child_at(binary_node, 0)->identifier == AST_Node_Type::Id
&& child_at(binary_node, 0)->text == child_at(child_at(eq_node,0), 0)->text
&& child_at(binary_node, 1)->identifier == AST_Node_Type::Constant
&& prefix_node->identifier == AST_Node_Type::Prefix
&& prefix_node->text == "++"
&& child_count(prefix_node) == 1
&& child_at(prefix_node, 0)->identifier == AST_Node_Type::Id
&& child_at(prefix_node, 0)->text == child_at(child_at(eq_node,0), 0)->text)
{
const Boxed_Value &begin = std::dynamic_pointer_cast<const eval::Constant_AST_Node<T>>(child_at(eq_node, 1))->m_value;
const Boxed_Value &end = std::dynamic_pointer_cast<const eval::Constant_AST_Node<T>>(child_at(binary_node, 1))->m_value;
const std::string &id = child_at(prefix_node, 0)->text;
if (begin.get_type_info().bare_equal(user_type<int>())
&& end.get_type_info().bare_equal(user_type<int>())) {
const auto start_int = boxed_cast<int>(begin);
const auto end_int = boxed_cast<int>(end);
const auto body = child_at(for_node, 3);
return make_compiled_node(for_node, {body},
[id, start_int, end_int](const std::vector<eval::AST_Node_Impl_Ptr<T>> &children, const chaiscript::detail::Dispatch_State &t_ss) {
assert(children.size() == 1);
chaiscript::eval::detail::Scope_Push_Pop spp(t_ss);
int i = start_int;
t_ss.add_object(id, var(&i));
try {
for (; i < end_int; ++i) {
try {
// Body of Loop
children[0]->eval(t_ss);
} catch (eval::detail::Continue_Loop &) {
// we got a continue exception, which means all of the remaining
// loop implementation is skipped and we just need to continue to
// the next iteration step
}
}
} catch (eval::detail::Break_Loop &) {
// loop broken
}
return void_var();
}
);
} else {
return for_node;
}
} else {
return for_node;
}
}
};
typedef Optimizer<optimizer::Partial_Fold, optimizer::Unused_Return, optimizer::Constant_Fold,
optimizer::If, optimizer::Return, optimizer::Dead_Code, optimizer::Block, optimizer::For_Loop> Optimizer_Default;
}
}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,81 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_POSIX_HPP_
#define CHAISCRIPT_POSIX_HPP_
namespace chaiscript
{
namespace detail
{
struct Loadable_Module
{
struct DLModule
{
explicit DLModule(const std::string &t_filename)
: m_data(dlopen(t_filename.c_str(), RTLD_NOW))
{
if (m_data == nullptr)
{
throw chaiscript::exception::load_module_error(dlerror());
}
}
DLModule(DLModule &&) = default;
DLModule &operator=(DLModule &&) = default;
DLModule(const DLModule &) = delete;
DLModule &operator=(const DLModule &) = delete;
~DLModule()
{
dlclose(m_data);
}
void *m_data;
};
template<typename T>
struct DLSym
{
DLSym(DLModule &t_mod, const std::string &t_symbol)
: m_symbol(cast_symbol(dlsym(t_mod.m_data, t_symbol.c_str())))
{
if (!m_symbol)
{
throw chaiscript::exception::load_module_error(dlerror());
}
}
static T cast_symbol(void *p)
{
union cast_union
{
T func_ptr;
void *in_ptr;
};
cast_union c;
c.in_ptr = p;
return c.func_ptr;
}
T m_symbol;
};
Loadable_Module(const std::string &t_module_name, const std::string &t_filename)
: m_dlmodule(t_filename), m_func(m_dlmodule, "create_chaiscript_module_" + t_module_name),
m_moduleptr(m_func.m_symbol())
{
}
DLModule m_dlmodule;
DLSym<Create_Module_Func> m_func;
ModulePtr m_moduleptr;
};
}
}
#endif

View File

@ -1,7 +1,7 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// and Jason Turner (jason@emptycrate.com)
// and 2009-2017, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_PRELUDE_HPP_
@ -9,7 +9,7 @@
namespace chaiscript {
struct ChaiScript_Prelude {
static std::string chaiscript_prelude() { return R""(
static std::string chaiscript_prelude() { return R"chaiscript(
def lt(l, r) {
if (call_exists(`<`, l, r)) {
@ -38,11 +38,28 @@ def eq(l, r) {
def new(x) {
eval(type_name(x))();
}
}
def clone(double x) {
double(x).clone_var_attrs(x)
}
def clone(string x) {
string(x).clone_var_attrs(x)
}
def clone(vector x) {
vector(x).clone_var_attrs(x)
}
def clone(int 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);
}
@ -110,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)
@ -140,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)
{
@ -153,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;
@ -208,6 +215,29 @@ def for_each(container, func) : call_exists(range, container) {
}
}
def any_of(container, func) : call_exists(range, container) {
var t_range := range(container);
while (!t_range.empty()) {
if (func(t_range.front())) {
return true;
}
t_range.pop_front();
}
false;
}
def all_of(container, func) : call_exists(range, container) {
var t_range := range(container);
while (!t_range.empty()) {
if (!func(t_range.front())) {
return false;
}
t_range.pop_front();
}
true;
}
def back_inserter(container) {
bind(push_back, container, _);
}
@ -455,37 +485,37 @@ def zip(x, y) {
# Returns the position of the second value string in the first value string
def string::find(substr) : is_type(substr, "string") {
def string::find(string substr) {
find(this, substr, size_t(0));
}
# Returns the position of last match of the second value string in the first value string
def string::rfind(substr) : is_type(substr, "string") {
def string::rfind(string substr) {
rfind(this, substr, size_t(-1));
}
# Returns the position of the first match of elements in the second value string in the first value string
def string::find_first_of(list) : is_type(list, "string") {
def string::find_first_of(string list) {
find_first_of(this, list, size_t(0));
}
# Returns the position of the last match of elements in the second value string in the first value string
def string::find_last_of(list) : is_type(list, "string") {
def string::find_last_of(string list) {
find_last_of(this, list, size_t(-1));
}
# Returns the position of the first non-matching element in the second value string in the first value string
def string::find_first_not_of(list) : is_type(list, "string") {
def string::find_first_not_of(string list) {
find_first_not_of(this, list, size_t(0));
}
# Returns the position of the last non-matching element in the second value string in the first value string
def string::find_last_not_of(list) : is_type(list, "string") {
def string::find_last_not_of(string list) {
find_last_not_of(this, list, size_t(-1));
}
@ -505,7 +535,7 @@ def string::trim() {
}
def find(container, value, compare_func) : call_exists(range, container) && is_type(compare_func, "Function") {
def find(container, value, Function compare_func) : call_exists(range, container) {
auto range := range(container);
while (!range.empty()) {
if (compare_func(range.front(), value)) {
@ -523,7 +553,7 @@ def find(container, value) {
}
)"";
)chaiscript";
}
};

View File

@ -309,7 +309,7 @@ class Range
/// \brief Moves the front pointer forward one
///
/// \post front() returne the element at front() + 1;
/// \post front() returns the element at front() + 1;
void pop_front();
};
@ -340,7 +340,7 @@ class Const_Range
/// \brief Moves the front pointer forward one
///
/// \post front() returne the element at front() + 1;
/// \post front() returns the element at front() + 1;
void pop_front();
};
@ -505,7 +505,7 @@ class Function
/// \endcode
Vector get_contained_functions() const;
/// \brief Returns a vector of the contained functions
/// \brief Returns a function guard as function
///
/// Example:
/// \code
@ -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,46 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_TRACER_HPP_
#define CHAISCRIPT_TRACER_HPP_
namespace chaiscript {
namespace eval {
struct Noop_Tracer_Detail
{
template<typename T>
void trace(const chaiscript::detail::Dispatch_State &, const AST_Node_Impl<T> *)
{
}
};
template<typename ... T>
struct Tracer : T...
{
Tracer() = default;
explicit Tracer(T ... t)
: T(std::move(t))...
{
}
void do_trace(const chaiscript::detail::Dispatch_State &ds, const AST_Node_Impl<Tracer<T...>> *node) {
(void)std::initializer_list<int>{ (static_cast<T&>(*this).trace(ds, node), 0)... };
}
static void trace(const chaiscript::detail::Dispatch_State &ds, const AST_Node_Impl<Tracer<T...>> *node) {
ds->get_parser().get_tracer<Tracer<T...>>().do_trace(ds, node);
}
};
typedef Tracer<Noop_Tracer_Detail> Noop_Tracer;
}
}
#endif

View File

@ -0,0 +1,31 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_UNKNOWN_HPP_
#define CHAISCRIPT_UNKNOWN_HPP_
namespace chaiscript
{
namespace detail
{
struct Loadable_Module
{
Loadable_Module(const std::string &, const std::string &)
{
#ifdef CHAISCRIPT_NO_DYNLOAD
throw chaiscript::exception::load_module_error("Loadable module support was disabled (CHAISCRIPT_NO_DYNLOAD)");
#else
throw chaiscript::exception::load_module_error("Loadable module support not available for your platform");
#endif
}
ModulePtr m_moduleptr;
};
}
}
#endif

View File

@ -0,0 +1,133 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_WINDOWS_HPP_
#define CHAISCRIPT_WINDOWS_HPP_
#include <string>
#ifdef CHAISCRIPT_WINDOWS
#define VC_EXTRA_LEAN
#if !defined(WIN32_LEAN_AND_MEAN)
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
#endif
namespace chaiscript
{
namespace detail
{
struct Loadable_Module
{
template<typename T>
static std::wstring to_wstring(const T &t_str)
{
return std::wstring(t_str.begin(), t_str.end());
}
template<typename T>
static std::string to_string(const T &t_str)
{
return std::string(t_str.begin(), t_str.end());
}
#if defined(_UNICODE) || defined(UNICODE)
template<typename T>
static std::wstring to_proper_string(const T &t_str)
{
return to_wstring(t_str);
}
#else
template<typename T>
static std::string to_proper_string(const T &t_str)
{
return to_string(t_str);
}
#endif
static std::string get_error_message(DWORD t_err)
{
typedef LPTSTR StringType;
#if defined(_UNICODE) || defined(UNICODE)
std::wstring retval = L"Unknown Error";
#else
std::string retval = "Unknown Error";
#endif
StringType lpMsgBuf = nullptr;
if (FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
nullptr,
t_err,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
reinterpret_cast<StringType>(&lpMsgBuf),
0, nullptr ) != 0 && lpMsgBuf)
{
retval = lpMsgBuf;
LocalFree(lpMsgBuf);
}
return to_string(retval);
}
struct DLModule
{
explicit DLModule(const std::string &t_filename)
: m_data(LoadLibrary(to_proper_string(t_filename).c_str()))
{
if (!m_data)
{
throw chaiscript::exception::load_module_error(get_error_message(GetLastError()));
}
}
DLModule(DLModule &&) = default;
DLModule &operator=(DLModule &&) = default;
DLModule(const DLModule &) = delete;
DLModule &operator=(const DLModule &) = delete;
~DLModule()
{
FreeLibrary(m_data);
}
HMODULE m_data;
};
template<typename T>
struct DLSym
{
DLSym(DLModule &t_mod, const std::string &t_symbol)
: m_symbol(reinterpret_cast<T>(GetProcAddress(t_mod.m_data, t_symbol.c_str())))
{
if (!m_symbol)
{
throw chaiscript::exception::load_module_error(get_error_message(GetLastError()));
}
}
T m_symbol;
};
Loadable_Module(const std::string &t_module_name, const std::string &t_filename)
: m_dlmodule(t_filename), m_func(m_dlmodule, "create_chaiscript_module_" + t_module_name),
m_moduleptr(m_func.m_symbol())
{
}
DLModule m_dlmodule;
DLSym<Create_Module_Func> m_func;
ModulePtr m_moduleptr;
};
}
}
#endif

View File

@ -0,0 +1,50 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_UTILITY_FNV1A_HPP_
#define CHAISCRIPT_UTILITY_FNV1A_HPP_
#include <cstdint>
#include "../chaiscript_defines.hpp"
namespace chaiscript
{
namespace utility
{
static constexpr std::uint32_t fnv1a_32(const char *s, std::uint32_t h = 0x811c9dc5) {
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wsign-conversion"
#endif
#ifdef CHAISCRIPT_MSVC
#pragma warning(push)
#pragma warning(disable : 4307)
#endif
return (*s == 0) ? h : fnv1a_32(s+1, ((h ^ (*s)) * 0x01000193));
#ifdef CHAISCRIPT_MSVC
#pragma warning(pop)
#endif
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
}
}
}
#endif

View File

@ -0,0 +1,674 @@
// 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 <vector>
#include <map>
#include <type_traits>
#include <initializer_list>
#include <ostream>
#include <iostream>
#include "../chaiscript_defines.hpp"
namespace json {
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;
class JSON
{
public:
enum class Class {
Null,
Object,
Array,
String,
Floating,
Integral,
Boolean
};
private:
struct QuickFlatMap
{
auto find(const std::string &s) {
return std::find_if(std::begin(data), std::end(data), [&s](const auto &d) { return d.first == s; });
}
auto find(const std::string &s) const {
return std::find_if(std::begin(data), std::end(data), [&s](const auto &d) { return d.first == s; });
}
auto size() const {
return data.size();
}
auto begin() const {
return data.begin();
}
auto end() const {
return data.end();
}
auto begin() {
return data.begin();
}
auto end() {
return data.end();
}
JSON &operator[](const std::string &s) {
const auto itr = find(s);
if (itr != data.end()) {
return itr->second;
} else {
data.emplace_back(s, JSON());
return data.back().second;
}
}
JSON &at(const std::string &s) {
const auto itr = find(s);
if (itr != data.end()) {
return itr->second;
} else {
throw std::out_of_range("Unknown key: " + s);
}
}
const JSON &at(const std::string &s) const {
const auto itr = find(s);
if (itr != data.end()) {
return itr->second;
} else {
throw std::out_of_range("Unknown key: " + s);
}
}
size_t count(const std::string &s) const {
return (find(s) != data.end())?1:0;
}
std::vector<std::pair<std::string, JSON>> data;
using iterator = decltype(data)::iterator;
using const_iterator = decltype(data)::const_iterator;
};
struct Internal {
template<typename T>
auto clone(const std::unique_ptr<T> &ptr) {
if (ptr != nullptr) {
return std::make_unique<T>(*ptr);
} else {
return std::unique_ptr<T>(nullptr);
}
}
Internal( double d ) : Float( d ), Type(Class::Floating) {}
Internal( long l ) : Int( l ), Type(Class::Integral) {}
Internal( bool b ) : Bool( b ), Type(Class::Boolean) {}
Internal( std::string s ) : String(std::make_unique<std::string>(std::move(s))), Type(Class::String) {}
Internal() : Type(Class::Null) {}
Internal(Class t_type) {
set_type(t_type);
}
Internal(const Internal &other)
: List(clone(other.List)),
Map(clone(other.Map)),
String(clone(other.String)),
Float(other.Float),
Int(other.Int),
Bool(other.Bool),
Type(other.Type)
{
}
Internal &operator=(const Internal &other)
{
List = clone(other.List);
Map = clone(other.Map);
String = clone(other.String);
Float = other.Float;
Int = other.Int;
Bool = other.Bool;
Type = other.Type;
return *this;
}
void set_type( Class type ) {
if( type == Type ) {
return;
}
Map.reset();
List.reset();
String.reset();
switch( type ) {
case Class::Object: Map = std::make_unique<QuickFlatMap>(); break;
case Class::Array: List = std::make_unique<std::vector<JSON>>(); break;
case Class::String: String = std::make_unique<std::string>(); break;
case Class::Floating: Float = 0.0; break;
case Class::Integral: Int = 0; break;
case Class::Boolean: Bool = false; break;
case Class::Null: break;
}
Type = type;
}
Internal(Internal &&) = default;
Internal &operator=(Internal &&) = default;
std::unique_ptr<std::vector<JSON>> List;
std::unique_ptr<QuickFlatMap> Map;
std::unique_ptr<std::string> String;
double Float = 0;
long Int = 0;
bool Bool = false;
Class Type = Class::Null;
};
Internal internal;
public:
template <typename Container>
class JSONWrapper {
Container *object = nullptr;
public:
JSONWrapper( Container *val ) : object( val ) {}
JSONWrapper( std::nullptr_t ) {}
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 = nullptr;
public:
JSONConstWrapper( const Container *val ) : object( val ) {}
JSONConstWrapper( std::nullptr_t ) {}
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() = default;
JSON( std::nullptr_t ) {}
explicit JSON(Class type)
: internal(type)
{
}
JSON( initializer_list<JSON> list )
: internal(Class::Object)
{
for( auto i = list.begin(), e = list.end(); i != e; ++i, ++i ) {
operator[]( i->to_string() ) = *std::next( i );
}
}
template <typename T>
explicit JSON( T b, typename enable_if<is_same<T,bool>::value>::type* = nullptr ) : internal( static_cast<bool>(b) ) {}
template <typename T>
explicit JSON( T i, typename enable_if<is_integral<T>::value && !is_same<T,bool>::value>::type* = nullptr ) : internal( static_cast<long>(i) ) {}
template <typename T>
explicit JSON( T f, typename enable_if<is_floating_point<T>::value>::type* = nullptr ) : internal( static_cast<double>(f) ) {}
template <typename T>
explicit JSON( T s, typename enable_if<is_convertible<T,std::string>::value>::type* = nullptr ) : internal( static_cast<std::string>(s) ) {}
static JSON Load( const std::string & );
JSON& operator[]( const std::string &key ) {
internal.set_type( Class::Object );
return internal.Map->operator[]( key );
}
JSON& operator[]( const size_t index ) {
internal.set_type( Class::Array );
if( index >= internal.List->size() ) {
internal.List->resize( index + 1 );
}
return internal.List->operator[]( index );
}
JSON &at( const std::string &key ) {
return operator[]( key );
}
const JSON &at( const std::string &key ) const {
return internal.Map->at( key );
}
JSON &at( size_t index ) {
return operator[]( index );
}
const JSON &at( size_t index ) const {
return internal.List->at( index );
}
long length() const {
if( internal.Type == Class::Array ) {
return static_cast<long>(internal.List->size());
} else {
return -1;
}
}
bool has_key( const std::string &key ) const {
if( internal.Type == Class::Object ) {
return internal.Map->count(key) != 0;
}
return false;
}
int size() const {
if( internal.Type == Class::Object ) {
return static_cast<int>(internal.Map->size());
} else if( internal.Type == Class::Array ) {
return static_cast<int>(internal.List->size());
} else {
return -1;
}
}
Class JSONType() const { return internal.Type; }
/// Functions for getting primitives from the JSON object.
bool is_null() const { return internal.Type == Class::Null; }
std::string to_string() const { bool b; return to_string( b ); }
std::string to_string( bool &ok ) const {
ok = (internal.Type == Class::String);
return ok ? *internal.String : std::string("");
}
double to_float() const { bool b; return to_float( b ); }
double to_float( bool &ok ) const {
ok = (internal.Type == Class::Floating);
return ok ? internal.Float : 0.0;
}
long to_int() const { bool b; return to_int( b ); }
long to_int( bool &ok ) const {
ok = (internal.Type == Class::Integral);
return ok ? internal.Int : 0;
}
bool to_bool() const { bool b; return to_bool( b ); }
bool to_bool( bool &ok ) const {
ok = (internal.Type == Class::Boolean);
return ok ? internal.Bool : false;
}
JSONWrapper<QuickFlatMap> object_range() {
if( internal.Type == Class::Object ) {
return JSONWrapper<QuickFlatMap>( internal.Map.get() );
} else {
return JSONWrapper<QuickFlatMap>( nullptr );
}
}
JSONWrapper<std::vector<JSON>> array_range() {
if( internal.Type == Class::Array ) {
return JSONWrapper<std::vector<JSON>>( internal.List.get() );
} else {
return JSONWrapper<std::vector<JSON>>( nullptr );
}
}
JSONConstWrapper<QuickFlatMap> object_range() const {
if( internal.Type == Class::Object ) {
return JSONConstWrapper<QuickFlatMap>( internal.Map.get() );
} else {
return JSONConstWrapper<QuickFlatMap>( nullptr );
}
}
JSONConstWrapper<std::vector<JSON>> array_range() const {
if( internal.Type == Class::Array ) {
return JSONConstWrapper<std::vector<JSON>>( internal.List.get() );
} else {
return JSONConstWrapper<std::vector<JSON>>( nullptr );
}
}
std::string dump( long depth = 1, std::string tab = " ") const {
switch( internal.Type ) {
case Class::Null:
return "null";
case Class::Object: {
std::string pad = "";
for( long i = 0; i < depth; ++i, pad += tab ) { }
std::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: {
std::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");
}
private:
static std::string json_escape( const std::string &str ) {
std::string output;
for(char i : str) {
switch( 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 += i; break;
}
}
return output;
}
private:
};
struct JSONParser {
static bool isspace(const char c)
{
#ifdef CHAISCRIPT_MSVC
// MSVC warns on these line in some circumstances
#pragma warning(push)
#pragma warning(disable : 6330)
#endif
return ::isspace(c) != 0;
#ifdef CHAISCRIPT_MSVC
#pragma warning(pop)
#endif
}
static void consume_ws( const std::string &str, size_t &offset ) {
while( isspace( str[offset] ) && offset <= str.size() ) { ++offset; }
}
static JSON parse_object( const std::string &str, size_t &offset ) {
JSON Object( 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.to_string()] = 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;
}
static JSON parse_array( const std::string &str, size_t &offset ) {
JSON Array( JSON::Class::Array );
size_t 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;
}
static JSON parse_string( const std::string &str, size_t &offset ) {
std::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( size_t 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);
}
static JSON parse_number( const std::string &str, size_t &offset ) {
std::string val, exp_str;
char c = '\0';
bool isDouble = false;
bool isNegative = false;
long exp = 0;
if( offset < str.size() && str[offset] == '-' ) {
isNegative = true;
++offset;
}
for (; offset < str.size() ;) {
c = str[offset++];
if( c >= '0' && c <= '9' ) {
val += c;
} else if( c == '.' && !isDouble ) {
val += c;
isDouble = true;
} else {
break;
}
}
if( offset < str.size() && (c == 'E' || c == 'e' )) {
c = str[ offset++ ];
if( c == '-' ) {
exp_str += '-';
} else if( c == '+' ) {
// do nothing
} 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 = chaiscript::parse_num<long>( 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 ) {
return JSON((isNegative?-1:1) * chaiscript::parse_num<double>( val ) * std::pow( 10, exp ));
} else {
if( !exp_str.empty() ) {
return JSON((isNegative?-1:1) * static_cast<double>(chaiscript::parse_num<long>( val )) * std::pow( 10, exp ));
} else {
return JSON((isNegative?-1:1) * chaiscript::parse_num<long>( val ));
}
}
}
static JSON parse_bool( const std::string &str, size_t &offset ) {
if( str.substr( offset, 4 ) == "true" ) {
offset += 4;
return JSON(true);
} else if( str.substr( offset, 5 ) == "false" ) {
offset += 5;
return JSON(false);
} else {
throw std::runtime_error(std::string("JSON ERROR: Bool: Expected 'true' or 'false', found '") + str.substr( offset, 5 ) + "'");
}
}
static JSON parse_null( const std::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();
}
static JSON parse_next( const std::string &str, size_t &offset ) {
char value;
consume_ws( str, offset );
value = str[offset];
switch( value ) {
case '[' : return parse_array( str, offset );
case '{' : return parse_object( str, offset );
case '\"': return parse_string( str, offset );
case 't' :
case 'f' : return parse_bool( str, offset );
case 'n' : return parse_null( str, offset );
default : if( ( value <= '9' && value >= '0' ) || value == '-' ) {
return parse_number( str, offset );
}
}
throw std::runtime_error(std::string("JSON ERROR: Parse: Unexpected starting character '") + value + "'");
}
};
inline JSON JSON::Load( const std::string &str ) {
size_t offset = 0;
return JSONParser::parse_next( str, offset );
}
} // End Namespace json
#endif

View File

@ -0,0 +1,150 @@
#ifndef CHAISCRIPT_SIMPLEJSON_WRAP_HPP
#define CHAISCRIPT_SIMPLEJSON_WRAP_HPP
#include "json.hpp"
namespace chaiscript
{
class json_wrap
{
public:
static Module& library(Module& m)
{
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.object_range())
{
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.array_range())
{
vec.emplace_back(from_json(p));
}
return Boxed_Value(vec);
}
case json::JSON::Class::String:
return Boxed_Value(t_json.to_string());
case json::JSON::Class::Floating:
return Boxed_Value(t_json.to_float());
case json::JSON::Class::Integral:
return Boxed_Value(t_json.to_int());
case json::JSON::Class::Boolean:
return Boxed_Value(t_json.to_bool());
}
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);
if (Boxed_Number::is_floating_point(t_bv))
{
return json::JSON(bn.get_as<double>());
} else {
return json::JSON(bn.get_as<long>());
}
} catch (const chaiscript::detail::exception::bad_any_cast &) {
// not a number
}
try {
return json::JSON(boxed_cast<bool>(t_bv));
} catch (const chaiscript::exception::bad_boxed_cast &) {
// not a bool
}
try {
return json::JSON(boxed_cast<std::string>(t_bv));
} 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

@ -0,0 +1,37 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_UTILITY_STATIC_STRING_HPP_
#define CHAISCRIPT_UTILITY_STATIC_STRING_HPP_
namespace chaiscript
{
namespace utility
{
struct Static_String
{
template<size_t N>
constexpr Static_String(const char (&str)[N])
: m_size(N-1), data(&str[0])
{
}
constexpr size_t size() const {
return m_size;
}
constexpr const char *c_str() const {
return data;
}
const size_t m_size;
const char *data = nullptr;
};
}
}
#endif

View File

@ -1,19 +1,24 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_UTILITY_UTILITY_HPP_
#define CHAISCRIPT_UTILITY_UTILITY_HPP_
#include <string>
#include <type_traits>
#include <utility>
#include <vector>
#include "../chaiscript.hpp"
#include "../dispatchkit/proxy_functions.hpp"
#include "../dispatchkit/type_info.hpp"
#include "../language/chaiscript_common.hpp"
#include "../dispatchkit/register_function.hpp"
#include "../dispatchkit/operators.hpp"
namespace chaiscript
@ -38,8 +43,8 @@ namespace chaiscript
/// { {fun(&test::function), "function"},
/// {fun(&test::function2), "function2"},
/// {fun(&test::function3), "function3"},
/// {fun(static_cast<std::string(test::*)(double)>(&test::functionoverload)), "functionoverload" },
/// {fun(static_cast<std::string(test::*)(int)>(&test::functionoverload)), "functionoverload" },
/// {fun(static_cast<std::string(test::*)(double)>(&test::function_overload)), "function_overload" },
/// {fun(static_cast<std::string(test::*)(int)>(&test::function_overload)), "function_overload" },
/// {fun(static_cast<test & (test::*)(const test &)>(&test::operator=)), "=" }
/// }
/// );
@ -62,6 +67,55 @@ namespace chaiscript
t_module.add(fun.first, fun.second);
}
}
template<typename Enum, typename ModuleType>
typename std::enable_if<std::is_enum<Enum>::value, void>::type
add_class(ModuleType &t_module,
const std::string &t_class_name,
const std::vector<std::pair<typename std::underlying_type<Enum>::type, std::string>> &t_constants
)
{
t_module.add(chaiscript::user_type<Enum>(), t_class_name);
t_module.add(chaiscript::constructor<Enum ()>(), t_class_name);
t_module.add(chaiscript::constructor<Enum (const Enum &)>(), t_class_name);
using namespace chaiscript::bootstrap::operators;
equal<Enum>(t_module);
not_equal<Enum>(t_module);
assign<Enum>(t_module);
t_module.add(chaiscript::fun([](const Enum &e, const int &i) { return e == i; }), "==");
t_module.add(chaiscript::fun([](const int &i, const Enum &e) { return i == e; }), "==");
for (const auto &constant : t_constants)
{
t_module.add_global_const(chaiscript::const_var(Enum(constant.first)), constant.second);
}
}
template<typename EnumClass, typename ModuleType>
typename std::enable_if<std::is_enum<EnumClass>::value, void>::type
add_class(ModuleType &t_module,
const std::string &t_class_name,
const std::vector<std::pair<EnumClass, std::string>> &t_constants
)
{
t_module.add(chaiscript::user_type<EnumClass>(), t_class_name);
t_module.add(chaiscript::constructor<EnumClass()>(), t_class_name);
t_module.add(chaiscript::constructor<EnumClass(const EnumClass &)>(), t_class_name);
using namespace chaiscript::bootstrap::operators;
equal<EnumClass>(t_module);
not_equal<EnumClass>(t_module);
assign<EnumClass>(t_module);
for (const auto &constant : t_constants)
{
t_module.add_global_const(chaiscript::const_var(EnumClass(constant.first)), constant.second);
}
}
}
}

View File

@ -1,4 +1,4 @@
Copyright 2009-2014 Jason Turner
Copyright 2009-2016 Jason Turner
Copyright 2009-2012 Jonathan Turner.
All Rights Reserved.

View File

@ -0,0 +1,19 @@
def go()
{
var my_array=["1", 4, 6.6l, 10ul, "1000", 100, 10.9f ];
var q = 0;
for (var j = 0; j < 10000; ++j)
{
for (var i = 0; i < 6; ++i)
{
to_string(my_array[i]);
}
q += j;
}
}
go();

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

@ -0,0 +1,20 @@
#include <chaiscript/chaiscript.hpp>
#include <chaiscript/chaiscript_stdlib.hpp>
double f(const std::string &, double, bool) noexcept {
return .0;
}
int main()
{
chaiscript::ChaiScript chai(chaiscript::Std_Lib::library());
chai.add(chaiscript::fun(&f), "f");
chai.eval(R"(
for (var i = 0; i < 100000; ++i) {
f("str", 1.2, false);
}
)");
}

View File

@ -0,0 +1,20 @@
#include <chaiscript/chaiscript.hpp>
#include <chaiscript/chaiscript_stdlib.hpp>
double f(const std::string &, double, bool) noexcept {
return .0;
}
int main()
{
chaiscript::ChaiScript chai(chaiscript::Std_Lib::library());
chai.add(chaiscript::fun(&f), "f");
const auto f = chai.eval<std::function<void ()>>(R"(fun(){ f("str", 1.2, false); })");
for (int i = 0; i < 100000; ++i) {
f();
}
}

View File

@ -0,0 +1,22 @@
load_module("test_module")
auto t := TestBaseType();
// This uses the TestBaseType to Type2 user type
// conversion which was added in the module and then calls
// "get_val()" which exists on the Type2 type
//assert_equal(t.get_val(), 10);
//print("Made it past test 1");
var t2 := Type2(t);
//dump_system();
for (var i = 0; i < 50000; ++i) {
var str = string(get_str(t2));
size(get_str(t2));
t2.get_str().size();
t.get_str().size();
}

View File

@ -1,14 +1,23 @@
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)
<a href="https://www.patreon.com/bePatron?u=2977989&redirect_uri=https%3A%2F%2Fwww.patreon.com%2Flefticus">
<img height="40" width="204" src="https://s3-us-west-1.amazonaws.com/widget-images/become-patron-widget-medium%402x.png">
</a>
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)
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: [![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
http://www.chaiscript.com
(c) 2009-2012 Jonathan Turner
(c) 2009-2014 Jason Turner
(c) 2009-2017 Jason Turner
Release under the BSD license, see "license.txt" for details.
@ -16,6 +25,8 @@ Release under the BSD license, see "license.txt" for details.
Introduction
============
[![Gitter](https://badges.gitter.im/Join Chat.svg)](https://gitter.im/ChaiScript/ChaiScript?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
ChaiScript is one of the only embedded scripting language designed from the
ground up to directly target C++ and take advantage of modern C++ development
techniques, working with the developer like he expects it to work. Being a
@ -32,10 +43,10 @@ languages:
Requirements
============
ChaiScript requires a C++11 compiler to build with support for variadic
templates. It has been tested with gcc 4.7 and clang 3.1 (with libcxx). MacOS
10.8 (Mountain Lion) is also known to support the C++11 build with Apple's
clang 4.0.
ChaiScript requires a C++14 compiler to build with support for variadic
templates. It has been tested with gcc 4.9 and clang 3.6 (with libcxx).
For more information see the build
[dashboard](http://chaiscript.com/ChaiScript-BuildResults/index.html).
Usage
=====
@ -68,7 +79,7 @@ directory, and for more in-depth look at the language, the unit tests in the
"unittests" directory cover the most ground.
For examples of how to register parts of your C++ application, see
"example.cpp" in the "src" directory. Example.cpp is verbose and shows every
"example.cpp" in the "samples" directory. Example.cpp is verbose and shows every
possible way of working with the library. For further documentation generate
the doxygen documentation in the build folder or see the website
http://www.chaiscript.com.
@ -76,44 +87,21 @@ http://www.chaiscript.com.
The shortest complete example possible follows:
/// main.cpp
```C++
/// main.cpp
#include <chaiscript/chaiscript.hpp>
#include <chaiscript/chaiscript.hpp>
double function(int i, double j)
{
return i * j;
}
int main()
{
chaiscript::ChaiScript chai;
chai.add(chaiscript::fun(&function), "function");
double d = chai.eval<double>("function(3, 4.75);");
}
Or, if you want to compile the std lib into your code, which reduces
runtime requirements.
/// main.cpp
#include <chaiscript/chaiscript.hpp>
#include <chaiscript/chaiscript_stdlib.hpp>
double function(int i, double j)
{
return i * j;
}
int main()
{
chaiscript::ChaiScript chai(chaiscript::Std_Lib::library());
chai.add(chaiscript::fun(&function), "function");
double d = chai.eval<double>("function(3, 4.75);");
}
double function(int i, double j)
{
return i * j;
}
int main()
{
chaiscript::ChaiScript chai;
chai.add(chaiscript::fun(&function), "function");
double d = chai.eval<double>("function(3, 4.75);");
}
```

View File

@ -1,6 +1,188 @@
Notes:
=======
Current Version: 5.4.0
Current Version: 6.0.0
### Changes since 5.8.6
*6.0.0 is a massive rework compared to 5.x. It now requires a C++14 enabled compiler*
#### Compiler Requirements
* MSVC 2015 or greater
* g++ 4.9 or greater
* clang 3.6 or greater
#### Breaking Changes
* Instantiating a ChaiScript object now, by default, builds the stdlib in
* This was done to address the most common support issues of loading stdlib dynamically at runtime
* If you want the old behavior, use include/chaiscript/chaiscript_basic.hpp
* Headers have been reorganized to fully separate stdlib/parser/engine from each other (some faster builds)
* Bootstrap functions no longer return a reference to the module added to (compile time savings)
* It's now no longer possible modify AST_Nodes (compile time, runtime efficiency)
* Function annotations no longer exist (simplifies code, reduces compile time, compile size)
#### New Features Added
* Modular optimization system; this can be accessed via the ChaiScript_Basic interface
* Execution tracing capability; also accessed via ChaiScript_Basic interface
* range-based for loops `for( id : container ) { }` (much better performance than other loop types)
* If-init expressions (ala C++17)
* Support for passing r-value references to functions
* Support for containing unique_ptr
* Add helpers for exposing enum classes to ChaiScript
* Allow typed ChaiScript defined functions to perform conversions on call #303
#### Improvements
* Compile time improvements
* Compile size improvements
* Significant runtime improvements (see "Modular optimization system")
* Significant parser improvements, both with parse-time and parser initialization time (Thanks @niXman)
* Fix type conversion to bool in conditionals
#### Improvements Still Need To Be Made
* File location tracking has been rewritten; this currently means error location reporting is not as good as it was
* Tracing capability needs to be tested and vetted
### Changes since 5.8.5
* Optimize away `return` statements in lambdas also
* Allow conversions to bool in conditionals
* Don't allow `class` statements inside of scopes
* Properly error when a dynamic object non-function member is called
### Changes since 5.8.4
* Fix order of operations for prefix operators
* Make sure atomics are initialized properly
* Remove parsing of unused prefix `&` operator
### Changes since 5.8.3
* Fix case with some numeric conversions mixed with numerics that do not need conversion
### Changes since 5.8.2
* Add support for reference of pointer return types
### Changes since 5.8.1
* Allow casting to non-const & std::shared_ptr<T>
### Changes since 5.8.0
* Fix parsing of floats to be locale independent #250
* Various warning fixes on various platforms
### Changes since 5.7.1
* Make all parser iterator operations range checked
* Parse in-string eval statements once, not once for each execution
* Fix parsing of operators (ie 1<-1 now parses)
* Fix variable scoping for functors
* Exception reduction
* Various object lifetime fixes
* Add JSON support for load / save #207
* Numeric overload resolution fixes #209
* Fix long long #208
* Add octal escapes in strings #211
* Fixed sizing of binary literals #213
* Added support for != with bool values #217
* Various value assignment vector fixes
* Fixed broken hex escape sequences from @ChristianKaeser
* Multiply defined symbols fixes #232 @RaptorFactor
* Add add_class<Enum> helper #233 @vrennert
* Cheatsheet fixes #235 @mlamby
* Fix parsing of strings inside of in-string eval statements
* Allow lower-case global keyword
* Enable thread-local on MSVC (should be significant performance boost)
### Changes since 5.7.0
* Build time reduction
* Build size reduction
* Performance increases
* Fixed ~20 crash-bugs found with fuzzy testing #194
* Let unhandled exceptions propogate to user
* Report eval_error when break statement is not in loop
* Fix handling of 0 length scripts closes #193
* Don't crash on arity mismatch - Specifically affects the case where no overloads exist for a given function
* Fix error printing for `bind` calls
* Handle unexpected continue statement
* Check arity during bind
* Don't allow arith conversion on variadic function
* Correct `bind` parameter match count
* Add in expected Boxed_Value exception cases
* Check access to AST, don't allow `;` in func def
* Don't attempt arithmetic unary & call
* Don't crash on 0 param call to `bind`
* Catch errors during member function dispatch
* Properly handle type of const bool &
* Automatic deduction of lambda type signatures
* Work with non-polymorphic parent/child conversions
* Move to codecov for coverage reporting
* Add `.at` method for Map objects
* Various corrections for support of move-only objects
### Changes since 5.6.0
* Significant code cleanups and reduction
* Smaller builds
* Faster compiles
* Less runtime memory usage
* ~2x faster runtimes
* biicode support
* method_missing feature added #164 @arBmind
* Generic objects with dynamic properties support
* Add ability to call functions contained in properties
* Add lambda captures
* Create [cheatsheet.md](cheatsheet.md) for all-in-one reference of features
* Fix support for libc++
* Eliminate clone of return value stored locally
* Eliminate 'return' statements when last line of function
* Reduce number of runtime exceptions occuring
* Reduce copies / moves of return values.
* make `use` statement return value of last statement in file
* Add ability to access fixed array sizes
* Add support for scientific notation floating point literals #174 @totalgee
### Changes since 5.5.1
* Throw exception on integer divide by 0
* Add optional type specification to function declarations
```
def func(int i, j, double k) {
// i must be an int.
// j can be anything
// k must be a double
// normal conversion rules still apply
}
```
* Many minor fixes for compiler warnings
* Add support for `std::future` and `std::async`
```
var f := async(someFunction);
var f2 := async(someFunction2);
// someFunction and someFunction2 are running in parallel now
f.get();
f2.get();
```
* Fully support r-value returns, supporting move-only objects and reducing object copies
### Changes since 5.5.0
* 30% performance increase
* Fix handling of object stack, resulting in greatly reduced memory usage
* Code cleanups
### Changes since 5.4.0
* 2x performance increase
* Significant code cleanups
* Throw exception if user attempts to call function on null object
* Allow user defined type conversions
* Fix object lifetime for nested function calls made at the global scope
* Fix returning of boolean values from function calls
### Changes since 5.3.1
* Decreased compile time and build size

View File

@ -13,12 +13,12 @@
void log(const std::string &msg)
{
std::cout << "[" << time(nullptr) << "] " << msg << std::endl;
std::cout << "[" << time(nullptr) << "] " << msg << '\n';
}
void log(const std::string &module, const std::string &msg)
{
std::cout << "[" << time(nullptr) << "] <" << module << "> " << msg << std::endl;
std::cout << "[" << time(nullptr) << "] <" << module << "> " << msg << '\n';
}
void bound_log(const std::string &msg)
@ -28,12 +28,12 @@ void bound_log(const std::string &msg)
void hello_world(const chaiscript::Boxed_Value & /*o*/)
{
std::cout << "Hello World" << std::endl;
std::cout << "Hello World\n";
}
void hello_constructor(const chaiscript::Boxed_Value & /*o*/)
{
std::cout << "Hello Constructor" << std::endl;
std::cout << "Hello Constructor\n";
}
@ -62,20 +62,21 @@ struct System
void take_shared_ptr(const std::shared_ptr<const std::string> &p)
{
std::cout << *p << std::endl;
std::cout << *p << '\n';
}
int main(int /*argc*/, char * /*argv*/[]) {
using namespace chaiscript;
ChaiScript chai;
//Create a new system object and share it with the chaiscript engine
System system;
chai.add(var(&system), "system");
chai.add_global(var(&system), "system");
//Add a bound callback method
chai.add(fun(&System::add_callback, system), "add_callback_bound");
chai.add(fun(&System::add_callback, std::ref(system)), "add_callback_bound");
//Register the two methods of the System structure.
chai.add(fun(&System::add_callback), "add_callback");
@ -107,9 +108,9 @@ int main(int /*argc*/, char * /*argv*/[]) {
// A shortcut to using eval is just to use the chai operator()
chai("log(\"Test Module\", \"Test Message\");");
//Finally, it is possible to register any std::function as a system function, in this
//Finally, it is possible to register a lambda as a system function, in this
//way, we can, for instance add a bound member function to the system
chai.add(fun(&System::do_callbacks, std::ref(system), std::string("Bound Test")), "do_callbacks");
chai.add(fun([&system](){ return system.do_callbacks("Bound Test"); }), "do_callbacks");
//Call bound version of do_callbacks
chai("do_callbacks()");
@ -122,7 +123,7 @@ int main(int /*argc*/, char * /*argv*/[]) {
//the templated version of eval:
int i = chai.eval<int>("5+5");
std::cout << "5+5: " << i << std::endl;
std::cout << "5+5: " << i << '\n';
//Add a new variable
chai("var scripti = 15");
@ -130,9 +131,9 @@ int main(int /*argc*/, char * /*argv*/[]) {
//We can even get a handle to the variables in the system
int &scripti = chai.eval<int &>("scripti");
std::cout << "scripti: " << scripti << std::endl;
std::cout << "scripti: " << scripti << '\n';
scripti *= 2;
std::cout << "scripti (updated): " << scripti << std::endl;
std::cout << "scripti (updated): " << scripti << '\n';
chai("print(\"Scripti from chai: \" + to_string(scripti))");
//To do: Add examples of handling Boxed_Values directly when needed

102
samples/factory.cpp Normal file
View File

@ -0,0 +1,102 @@
#include <chaiscript/chaiscript.hpp>
class Entity
{
public:
int width;
int height;
int x;
int y;
std::string name;
std::function<void (Entity &)> updater;
Entity(const int t_width, const int t_height, const int t_x, const int t_y, std::string t_name)
: width(t_width), height(t_height), x(t_x), y(t_y), name(std::move(t_name))
{
}
};
class Factory
{
public:
// we may as well pass the parameters for the entity to the factory method, this does the initialization
// in one step.
Entity *make_entity(const int width, const int height, const int x, const int y, const std::string &name)
{
auto entity = entities.insert({name, Entity{width, height, x, y, name}});
return &(entity.first->second);
}
Entity *get_entity(const std::string &name)
{
return &entities.at(name);
}
// loop over all entities and all their updater function (if it exists)
void update_entities()
{
for (auto &entity : entities)
{
if (entity.second.updater) {
entity.second.updater(entity.second);
}
}
}
private:
// we cannot store the entities in a std::vector if we want to return a pointer to them,
// because a vector automatically resizing itself can invalidate the pointer that was returned.
// using a map guarantees that the memory assigned to the entity will never change, plus
// lets us easily look up an entity by name
std::map<std::string, Entity> entities;
};
int main()
{
chaiscript::ChaiScript chai;
chai.add(chaiscript::fun(&Entity::width), "width");
chai.add(chaiscript::fun(&Entity::height), "height");
chai.add(chaiscript::fun(&Entity::x), "x");
chai.add(chaiscript::fun(&Entity::y), "y");
chai.add(chaiscript::fun(&Entity::name), "name");
chai.add(chaiscript::fun(&Entity::updater), "updater");
chai.add(chaiscript::user_type<Entity>(), "Entity"); // this isn't strictly necessary but makes error messages nicer
chai.add(chaiscript::fun(&Factory::make_entity), "make_entity");
chai.add(chaiscript::fun(&Factory::get_entity), "get_entity");
chai.add(chaiscript::fun(&Factory::update_entities), "update_entities");
chai.add(chaiscript::user_type<Factory>(), "Factory"); // this isn't strictly necessary but makes error messages nicer
Factory f;
chai.add(chaiscript::var(&f), "f");
std::string script = R""(
f.make_entity(10,10,1,1,"entity1").updater = fun(e){ e.x += 1; e.y += 1 };
f.make_entity(10,10,10,10,"entity2").updater = fun(e){ e.x += 2; e.y += 2 };
f.make_entity(10,10,20,20,"entity3");
print(f.get_entity("entity1").x == 1)
print(f.get_entity("entity2").x == 10)
print(f.get_entity("entity3").x == 20)
f.update_entities(); // this runs the function objects we set in the previous lines
// we should now see the updated values
print(f.get_entity("entity1").x == 2)
print(f.get_entity("entity2").x == 12)
print(f.get_entity("entity3").x == 20) // this one has no updater, so it stays the same
)"";
chai.eval(script);
}

View File

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

View File

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

View File

@ -1,5 +1,4 @@
#include <chaiscript/chaiscript.hpp>
#include <chaiscript/chaiscript_stdlib.hpp>
class BaseClass
{
@ -8,7 +7,9 @@ class BaseClass
{
}
virtual ~BaseClass() = default;
BaseClass(const BaseClass &) = default;
virtual ~BaseClass() {}
virtual std::string doSomething(float, double) const = 0;
@ -68,7 +69,7 @@ class ChaiScriptDerived : public BaseClass
int main()
{
chaiscript::ChaiScript chai(chaiscript::Std_Lib::library());
chaiscript::ChaiScript chai;
chai.add(chaiscript::fun(&BaseClass::doSomething), "doSomething");
chai.add(chaiscript::fun(&BaseClass::setValue), "setValue");
chai.add(chaiscript::fun(&BaseClass::getValue), "getValue");

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