Compare commits

...

443 Commits

Author SHA1 Message Date
Rob Loach
2eb3279c39
Merge pull request #630 from ChaiScript/update-catch
Update catch.hpp to v2.13.9
2025-07-30 17:07:44 -04:00
Rob Loach
2951ce4a7a
Update catch.hpp to v2.13.9
Fixes #619
2025-07-28 09:33:41 -04:00
Rob Loach
f904cd5447
Merge pull request #626 from CTerasa-ep/fix-warnings
Fix several `noexcept` and `possibly dangling reference` warnings
2025-02-20 09:45:10 -05:00
Clemens Terasa
b44b987d4b chaiscript_eval: Fix warning by replacing lambda with ternary operator expression
Using GCC 13.3.0 I get warnings like the following:

```
In file included from .../ChaiScript/static_libs/../include/chaiscript/language/chaiscript_optimizer.hpp:10,
                 from .../ChaiScript/static_libs/../include/chaiscript/language/chaiscript_parser.hpp:26,
                 from .../ChaiScript/static_libs/chaiscript_parser.cpp:1:
.../ChaiScript/static_libs/../include/chaiscript/language/chaiscript_eval.hpp: In instantiation of ‘chaiscript::Boxed_Value chaiscript::eval::Global_Decl_AST_Node<T>::eval_internal(const chaiscript::detail::Dispatch_State&) const [with T = chaiscript::eval::Tracer<chaiscript::eval::Noop_Tracer_Detail>]’:
.../ChaiScript/static_libs/../include/chaiscript/language/chaiscript_eval.hpp:503:19:   required from here
.../ChaiScript/static_libs/../include/chaiscript/language/chaiscript_eval.hpp:504:28: warning: possibly dangling reference to a temporary [-Wdangling-reference]
  504 |         const std::string &idname = [&]() -> const std::string & {
      |                            ^~~~~~
.../ChaiScript/static_libs/../include/chaiscript/language/chaiscript_eval.hpp:510:10: note: the temporary was destroyed at the end of the full expression ‘<lambda closure object>chaiscript::eval::Global_Decl_AST_Node<chaiscript::eval::Tracer<chaiscript::eval::Noop_Tracer_Detail> >::eval_internal(const chaiscript::detail::Dispatch_State&) const::<lambda()>{((const chaiscript::eval::Global_Decl_AST_Node<chaiscript::eval::Tracer<chaiscript::eval::Noop_Tracer_Detail> >*)this)}.chaiscript::eval::Global_Decl_AST_Node<chaiscript::eval::Tracer<chaiscript::eval::Noop_Tracer_Detail> >::eval_internal(const chaiscript::detail::Dispatch_State&) const::<lambda()>()’
  504 |         const std::string &idname = [&]() -> const std::string & {
      |                                     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  505 |           if (this->children[0]->identifier == AST_Node_Type::Reference) {
      |           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  506 |             return this->children[0]->children[0]->text;
      |             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  507 |           } else {
      |           ~~~~~~~~
  508 |             return this->children[0]->text;
      |             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  509 |           }
      |           ~
  510 |         }();
      |         ~^~
```

Fix this by replacing the lambda with a simple ternary operator
expression.
2025-02-19 20:04:17 +01:00
Clemens Terasa
43dc35c3df test_module: Fix noexcept warning
With gcc 13.3.0 an `-Wnoexcept` I warnings like the following:

```
In file included from .../include/c++/13.3.0/bits/char_traits.h:57,
                 from .../include/c++/13.3.0/string_view:40,
                 from .../ChaiScript/include/chaiscript/chaiscript_defines.hpp:23,
                 from .../ChaiScript/include/chaiscript/chaiscript_basic.hpp:10,
                 from .../ChaiScript/src/test_module.cpp:2:
.../include/c++/13.3.0/bits/stl_construct.h: In instantiation of ‘constexpr decltype (::new(void*(0)) _Tp) std::construct_at(_Tp*, _Args&& ...) [with _Tp = Type2; _Args = {Type2}; decltype (::new(void*(0)) _Tp) = Type2*]’:
.../include/c++/13.3.0/bits/stl_construct.h:115:21:   required from ‘constexpr void std::_Construct(_Tp*, _Args&& ...) [with _Tp = Type2; _Args = {Type2}]’
.../include/c++/13.3.0/bits/alloc_traits.h:661:19:   required from ‘static constexpr void std::allocator_traits<std::allocator<void> >::construct(allocator_type&, _Up*, _Args&& ...) [with _Up = Type2; _Args = {Type2}; allocator_type = std::allocator<void>]’
.../include/c++/13.3.0/bits/shared_ptr_base.h:604:39:   required from ‘std::_Sp_counted_ptr_inplace<_Tp, _Alloc, _Lp>::_Sp_counted_ptr_inplace(_Alloc, _Args&& ...) [with _Args = {Type2}; _Tp = Type2; _Alloc = std::allocator<void>; __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’
.../include/c++/13.3.0/bits/shared_ptr_base.h:971:16:   required from ‘std::__shared_count<_Lp>::__shared_count(_Tp*&, std::_Sp_alloc_shared_tag<_Alloc>, _Args&& ...) [with _Tp = Type2; _Alloc = std::allocator<void>; _Args = {Type2}; __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’
.../include/c++/13.3.0/bits/shared_ptr_base.h:1712:14:   required from ‘std::__shared_ptr<_Tp, _Lp>::__shared_ptr(std::_Sp_alloc_shared_tag<_Tp>, _Args&& ...) [with _Alloc = std::allocator<void>; _Args = {Type2}; _Tp = Type2; __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’
.../include/c++/13.3.0/bits/shared_ptr.h:464:59:   required from ‘std::shared_ptr<_Tp>::shared_ptr(std::_Sp_alloc_shared_tag<_Tp>, _Args&& ...) [with _Alloc = std::allocator<void>; _Args = {Type2}; _Tp = Type2]’
.../include/c++/13.3.0/bits/shared_ptr.h:1009:14:   required from ‘std::shared_ptr<std::_NonArray<_Tp> > std::make_shared(_Args&& ...) [with _Tp = Type2; _Args = {Type2}; _NonArray<_Tp> = Type2]’
.../ChaiScript/include/chaiscript/dispatchkit/boxed_value.hpp:121:37:   required from ‘static auto chaiscript::Boxed_Value::Object_Data::get(T, bool) [with T = Type2]’
.../ChaiScript/include/chaiscript/dispatchkit/boxed_value.hpp:133:34:   required from ‘chaiscript::Boxed_Value::Boxed_Value(T&&, bool) [with T = Type2; <template-parameter-1-2> = void]’
.../ChaiScript/include/chaiscript/dispatchkit/type_conversions.hpp:480:26:   required from ‘chaiscript::Type_Conversion chaiscript::type_conversion(const Callable&) [with From = TestBaseType; To = Type2; Callable = create_chaiscript_module_test_module()::<lambda(const TestBaseType&)>; Type_Conversion = std::shared_ptr<detail::Type_Conversion_Base>]’
.../ChaiScript/src/test_module.cpp:194:58:   required from here
.../include/c++/13.3.0/bits/stl_construct.h:95:14: warning: noexcept-expression evaluates to ‘false’ because of a call to ‘Type2::Type2(Type2&&)’ [-Wnoexcept]
   95 |     noexcept(noexcept(::new((void*)0) _Tp(std::declval<_Args>()...)))
      |              ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.../ChaiScript/src/test_module.cpp:60:7: note: but ‘Type2::Type2(Type2&&)’ does not throw; perhaps it should be declared ‘noexcept’
   60 | class Type2 {
      |       ^~~~~
```

Fix this by introducing `noexcept` like proposed in the warning.
2025-02-19 20:04:17 +01:00
Clemens Terasa
681104b68f dispatchkit: boxed_value: Fix noexcept warning for Data ctor
Using gcc 13.3.0 I get many warnings like the following:

```
In file included from .../include/c++/13.3.0/bits/stl_iterator.h:85,
                 from .../include/c++/13.3.0/bits/stl_algobase.h:67,
                 from .../include/c++/13.3.0/bits/stl_tree.h:63,
                 from .../include/c++/13.3.0/map:62,
                 from .../ChaiScript/static_libs/../include/chaiscript/chaiscript_stdlib.hpp:10,
                 from .../ChaiScript/static_libs/chaiscript_stdlib.cpp:1:
.../include/c++/13.3.0/bits/stl_construct.h: In instantiation of ‘constexpr decltype (::new(void*(0)) _Tp) std::construct_at(_Tp*, _Args&& ...) [with _Tp = chaiscript::Boxed_Value::Data; _Args = {chaiscript::Type_Info, chaiscript::detail::Any, bool, std::nullptr_t, bool&}; decltype (::new(void*(0)) _Tp) = chaiscript::Boxed_Value::Data*]’:
.../include/c++/13.3.0/bits/stl_construct.h:115:21:   required from ‘constexpr void std::_Construct(_Tp*, _Args&& ...) [with _Tp = chaiscript::Boxed_Value::Data; _Args = {chaiscript::Type_Info, chaiscript::detail::Any, bool, std::nullptr_t, bool&}]’
.../include/c++/13.3.0/bits/alloc_traits.h:661:19:   required from ‘static constexpr void std::allocator_traits<std::allocator<void> >::construct(allocator_type&, _Up*, _Args&& ...) [with _Up = chaiscript::Boxed_Value::Data; _Args = {chaiscript::Type_Info, chaiscript::detail::Any, bool, std::nullptr_t, bool&}; allocator_type = std::allocator<void>]’
.../include/c++/13.3.0/bits/shared_ptr_base.h:604:39:   required from ‘std::_Sp_counted_ptr_inplace<_Tp, _Alloc, _Lp>::_Sp_counted_ptr_inplace(_Alloc, _Args&& ...) [with _Args = {chaiscript::Type_Info, chaiscript::detail::Any, bool, std::nullptr_t, bool&}; _Tp = chaiscript::Boxed_Value::Data; _Alloc = std::allocator<void>; __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’
.../include/c++/13.3.0/bits/shared_ptr_base.h:971:16:   required from ‘std::__shared_count<_Lp>::__shared_count(_Tp*&, std::_Sp_alloc_shared_tag<_Alloc>, _Args&& ...) [with _Tp = chaiscript::Boxed_Value::Data; _Alloc = std::allocator<void>; _Args = {chaiscript::Type_Info, chaiscript::detail::Any, bool, std::nullptr_t, bool&}; __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’
.../include/c++/13.3.0/bits/shared_ptr_base.h:1712:14:   required from ‘std::__shared_ptr<_Tp, _Lp>::__shared_ptr(std::_Sp_alloc_shared_tag<_Tp>, _Args&& ...) [with _Alloc = std::allocator<void>; _Args = {chaiscript::Type_Info, chaiscript::detail::Any, bool, std::nullptr_t, bool&}; _Tp = chaiscript::Boxed_Value::Data; __gnu_cxx::_Lock_policy _Lp = __gnu_cxx::_S_atomic]’
.../include/c++/13.3.0/bits/shared_ptr.h:464:59:   required from ‘std::shared_ptr<_Tp>::shared_ptr(std::_Sp_alloc_shared_tag<_Tp>, _Args&& ...) [with _Alloc = std::allocator<void>; _Args = {chaiscript::Type_Info, chaiscript::detail::Any, bool, std::nullptr_t, bool&}; _Tp = chaiscript::Boxed_Value::Data]’
.../include/c++/13.3.0/bits/shared_ptr.h:1009:14:   required from ‘std::shared_ptr<std::_NonArray<_Tp> > std::make_shared(_Args&& ...) [with _Tp = chaiscript::Boxed_Value::Data; _Args = {chaiscript::Type_Info, chaiscript::detail::Any, bool, std::nullptr_t, bool&}; _NonArray<_Tp> = chaiscript::Boxed_Value::Data]’
.../ChaiScript/static_libs/../include/chaiscript/language/../dispatchkit/boxed_value.hpp:74:38:   required from here
.../include/c++/13.3.0/bits/stl_construct.h:95:14: warning: noexcept-expression evaluates to ‘false’ because of a call to ‘chaiscript::Boxed_Value::Data::Data(const chaiscript::Type_Info&, chaiscript::detail::Any, bool, const void*, bool)’ [-Wnoexcept]
   95 |     noexcept(noexcept(::new((void*)0) _Tp(std::declval<_Args>()...)))
      |              ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In file included from .../ChaiScript/static_libs/../include/chaiscript/language/chaiscript_common.hpp:21,
                 from .../ChaiScript/static_libs/../include/chaiscript/chaiscript_stdlib.hpp:17:
.../ChaiScript/static_libs/../include/chaiscript/language/../dispatchkit/boxed_value.hpp:34:7: note: but ‘chaiscript::Boxed_Value::Data::Data(const chaiscript::Type_Info&, chaiscript::detail::Any, bool, const void*, bool)’ does not throw; perhaps it should be declared ‘noexcept’
   34 |       Data(const Type_Info &ti, chaiscript::detail::Any to, bool is_ref, const void *t_void_ptr, bool t_return_value)
      |       ^~~~
/
```

Fix this by adding a noexcept like the warning suggests.
2025-02-19 20:04:17 +01:00
Rob Loach
406a7ba1ef
Merge pull request #575 from stephenberry/develop
Added virtual destructor for ChaiScript_Basic
2024-02-20 12:52:52 -05:00
Rob Loach
8d82f237bf
Merge pull request #616 from wholivesinapineappleunderthesea/develop
Fix spelling mistakes in cheatsheet.md
2023-11-27 23:27:35 -05:00
ar
dbd2050eb2
Fix spelling mistakes in cheatsheet.md 2023-11-27 21:18:34 -05:00
Rob Loach
866ef314a8
Add /build to .gitignore (#614) 2023-10-08 17:18:49 -04:00
Rob Loach
bf9f5ae2e1
Merge pull request #608 from FellowTraveler/develop
Add C++20 support
2023-10-08 14:58:17 -04:00
FellowTraveler
0870cb5a3a Add C++20 support
ChaiScript now successfully builds on my Mac with C++20, and passes 100% of the unit tests.
2023-06-18 06:42:51 -05:00
Rob Loach
3e548184c0
Merge pull request #606 from SirNate0/patch-1
Fix cheatsheet.md typos
2023-02-21 12:03:56 -05:00
SirNate0
41da3db06a
Fix cheatsheet.md typos
Add missing parenthesis and quotes.
2023-02-21 11:33:36 -05:00
Rob Loach
2898ae679f
Merge pull request #580 from TerensTare/patch-1
Fix typo in `cheatsheet.md`
2021-09-02 12:19:25 -05:00
Terens
6ccab2af6a
Fix typo in cheatsheet.md 2021-09-02 14:16:15 +02:00
Stephen Berry
7cd229cf26 Added virtual destructor for ChaiScript_Basic
ChaiScript inherits from ChaiScript_Basic, so this is good practice.
I also need to be able to inherit from ChaiScript and dynamic cast, which is impossible without this destructor.
2021-07-28 09:04:38 -05:00
Rob Loach
6411aa7498
Merge pull request #573 from totalgee/fix_erase_at_bounds
Fix  crash with out of bounds index (issue #572)
2021-07-08 19:55:50 -04:00
Glen Fraser
5722a5177d Fix crash with out of bounds index (issue #572) 2021-07-08 18:55:36 +02:00
Rob Loach
3703a78813
Merge pull request #566 from IohannRabeson/cmake
Properly create a CMake a library called chaiscript
2021-06-09 01:22:51 -04:00
IohannRabeson
53fe932be4 Properly create a library called Chaiscript.
This allows to properly use Chaiscript as submodule with CMake.
2021-06-08 23:00:43 -04:00
Rob Loach
651abc2f5b
Merge pull request #565 from IohannRabeson/improve_cmake
Add include directory to chai target.
2021-06-07 15:38:30 -04:00
irabeson
b3ed4466f3 Add include directory to chai target.
This way, the path to the Chai's include directory is automagicaly
knowns by any CMake project using chai.
2021-06-07 11:35:52 -04:00
Rob Loach
855c3ced88
Merge pull request #562 from BerndAmend/develop
Update readme.txt and fix json namespace clash with nlohmann/json

Fixes #486, #506
2021-05-24 17:56:06 -04:00
Bernd Amend
323cd7a8d4 drop link to the build dashboard 2021-05-24 23:34:54 +02:00
Bernd Amend
535d80e8d2 drop coverity scan status 2021-05-24 23:34:54 +02:00
Bernd Amend
efeb244cd9 readme.txt update requirements to C++17 #506 2021-05-24 23:34:50 +02:00
Bernd Amend
a1a78e9cf1 remove trailing spaces from readme.txt 2021-05-24 23:31:31 +02:00
Bernd Amend
0f37802aba move namespace json into the chaiscript namespace #486 2021-05-24 23:31:31 +02:00
Rob Loach
c258670350
Merge pull request #560 from ChaiScript/master
Merge pull request #441 from ChaiScript/develop
2021-05-24 16:10:36 -04:00
Rob Loach
69123db3dc
license: Restore Jonathan Turner copyright 2021-05-24 16:09:20 -04:00
Rob Loach
439c1a96d3
Merge branch 'develop' into master 2021-05-24 16:05:30 -04:00
Rob Loach
3aa1fa8278
Merge pull request #557 from BerndAmend/develop
change .clang-format and reformat code with clang-format 11
2021-05-24 09:20:36 -04:00
Rob Loach
ef5a22b2b5
Merge pull request #558 from ChaiScript/revert-482-pair_conversion
Revert "Add pair_conversion registration helper with unit test"
2021-05-24 09:20:24 -04:00
Rob Loach
6030ea63bd
Revert "Add pair_conversion registration helper with unit test" 2021-05-24 09:19:47 -04:00
Rob Loach
9c118c2b1e
Merge pull request #482 from totalgee/pair_conversion
Add pair_conversion registration helper with unit test
2021-05-24 09:19:20 -04:00
Bernd Amend
cff6a0aced change .clang-format and reformat code with clang-format 11
I initially tried to use the existing .clang-format file,
but it does not match the code style (at least with clang-format 11)
and the formatting is not consistent across files.
Therefore, I decided to rewrite the .clang-format with some personal
preferences.

Used command
  find . -iname "*.hpp" -o -iname "*.cpp" | xargs clang-format -i -style=file
2021-05-24 10:44:15 +02:00
Rob Loach
6491b80496
Merge pull request #556 from BerndAmend/develop
Fixes for #527, #537, #553, C++20, and various compiler warnings/errors reported by g++ 11.1, clang 11, and vs2019
2021-05-23 17:23:11 -04:00
Bernd Amend
a4fd5371bd fix handling of $ in strings ChaiScript#553 2021-05-23 12:05:33 +02:00
Bernd Amend
55ec76fd39 fix testcase "Test unicode matches C++" 2021-05-22 23:54:18 +02:00
Bernd Amend
82ef037912 fix vs2019 build 2021-05-22 23:53:31 +02:00
Bernd Amend
4ec767bdc9 drop /std:c++latest and /std:c++17
Both are already set by cmake
2021-05-22 22:37:08 +02:00
Bernd Amend
7aea27412d make is_nothrow_forward_constructible_v static (warning from gcc 7) 2021-05-22 18:45:12 +02:00
Bernd Amend
8ee033cf89 remove not required () 2021-05-22 18:45:12 +02:00
Bernd Amend
59f64d8d82 set min required cmake version to 3.12
The already used functionallity already
requires a more recent cmake version.
Short summary why a never version is required:
  CMAKE_CXX_STANDARD requires >=3.1
  CMAKE_COMPILER_IS_GNUCC requires >3.7
  ENABLE_LTO can be simplified with >3.11 (3.13 VS)
2021-05-22 18:45:12 +02:00
Bernd Amend
39f7aa0900 remove trailing spaces 2021-05-22 18:45:12 +02:00
Bernd Amend
32723fcbc0 fix clangs -Wshadow warning 2021-05-22 18:45:12 +02:00
Bernd Amend
14e9ec6e97 fix implicit conversion warnings by making them explicit 2021-05-22 18:45:12 +02:00
Bernd Amend
532f044bd3 remove trailing ; 2021-05-22 18:45:12 +02:00
Bernd Amend
b5d81613cf cmake suppress some clang compiler warnings 2021-05-22 18:45:12 +02:00
Bernd Amend
2c92e83afa drop CPP17_FLAG since cmake is already taking care of it 2021-05-22 18:45:12 +02:00
Bernd Amend
c580726020 Change the default value of USE_LIBCXX to FALSE
By default clang is already using the system
standard library. Therefore it is unexpected
that chaiscript always uses libcxx if clang
is used.
2021-05-22 18:45:12 +02:00
Bernd Amend
816cb5e8e2 unify formatting if ( -> if( 2021-05-22 18:45:12 +02:00
Bernd Amend
b3ee667ca5 don't mark a function virtual that is overriden. 2021-05-22 18:45:12 +02:00
Bernd Amend
1302e28e32 replace the deprecated is_pod_v with is_trivial_v
is_pod_v was deprecated in C++20, is_pod_v can be
replaced with is_trivial_v && is_standard_layout_v.
I don't see any benefit from is_standard_layout_v,
but I could have missed something.
2021-05-22 18:45:12 +02:00
Bernd Amend
cf7821cb1e fix ChaiScript#537 2021-05-22 18:45:12 +02:00
Bernd Amend
5ff3679811 fix u8"" compilation error in g++11 with -std=c++20 2021-05-22 18:45:12 +02:00
Bernd Amend
e8e47173fb fix a couple of g++s -Wnoexcept warnings 2021-05-22 18:45:08 +02:00
Bernd Amend
19929be684 don't default implicitly deleted operator=/ctor ChaiScript#527 2021-05-22 18:44:54 +02:00
Bernd Amend
c4e1e1965e remove not required ";" 2021-05-22 14:09:24 +02:00
Bernd Amend
1e6263976f don't return voids 2021-05-22 14:05:52 +02:00
Bernd Amend
2b3bddb02d replace typedef with using 2021-05-22 14:04:04 +02:00
Bernd Amend
684522a8b7 fix -Wcovered-switch-default warnings 2021-05-22 14:01:39 +02:00
Bernd Amend
c26fd14953 remove else after return 2021-05-22 13:55:04 +02:00
Bernd Amend
bd933592a9 hash.hpp: explicitly cast to uint32_t 2021-05-22 13:51:24 +02:00
Bernd Amend
e62f0d3296 drop useless statics and/or add [[nodiscard]] 2021-05-22 13:50:57 +02:00
Bernd Amend
1235fdad7c move ctor arguments into the variables/base class ctors 2021-05-22 13:47:45 +02:00
Bernd Amend
c47b9e3b0d replace const std::string_view with std::string_view 2021-05-22 13:40:32 +02:00
Bernd Amend
180a6d4a1c update catch to version 2.13.6 2021-05-22 13:18:49 +02:00
Bernd Amend
52a9fa47c1 replace std::vector::push_back with emplace_back 2021-05-22 13:18:32 +02:00
Rob Loach
964a36bdcd
Merge pull request #504 from draghan/lambdas_can_into_predicates_unittests
Add unit test covering lambdas returning boolean
2021-04-11 16:50:31 -04:00
draghan
0a3bc48788 Add unit test covering issue #481
Implemented unit test which is validating whether a lambda from
Chaiscript could return a boolean value without throwing any exception.

The same test case is checking whether lambda with boolean return value
could be called peacefully from Chaiscript.
2021-03-27 21:17:55 +01:00
draghan
301f2e7061 Merge remote-tracking branch 'upstream/develop' into develop 2021-03-27 21:17:15 +01:00
draghan
940afb399c Revert "Fix bug #481"
This reverts commit a3c033d1db07a74e5f0c1b7a3910b51a226aba83.
2021-03-27 21:17:03 +01:00
Rob Loach
586779ccca
Merge pull request #549 from robertFrysch/develop
map_conversion: copy forced for loop var `p` (incompatible ref type)
2021-01-17 01:39:32 -05:00
frysch
ab691f687d map_conversion: copy forced for loop var p (incompatible ref type)
The underlying pair that is dereferenced from the iterator has always `const` qualified `first` member (key type). Therefore, an unnecessary temporary was created and bounded to the const ref to the pair. This could be also fixed with `for (const auto &p : from_map)`.
2021-01-15 09:14:49 +01:00
Rob Loach
cb55083603
Merge pull request #548 from ChaiScript/stack-vector-pop-back
Fix stack_vector.pop_back() pre-decrementing
2021-01-07 15:55:48 -05:00
Rob Loach
c7fcc9f7d9
Fix stack_vector.pop_back() pre-decrementing
Fixes #547, found by @balint-luko.
2021-01-07 13:15:47 -05:00
Rob Loach
d7832661e7
Merge pull request #503 from SG-Skril/develop
Fix for lambdas returning booleans

References #481
2020-12-11 14:46:50 -05:00
Rob Loach
c8c9f805f6
Merge pull request #539 from totalgee/fix_VS2019
Fixes for VS2019 and C++17 compilation
2020-10-16 09:35:50 -04:00
Glen Fraser
259f130a60 Fix build warnings from unused enums in switch; unused function arg 2020-10-16 11:56:07 +02:00
Glen Fraser
12f034b424 Change AppVeyor to use VS2019 for Windows build/testing 2020-10-16 11:32:51 +02:00
Rob Loach
7178460415
Merge pull request #540 from Rabios/patch-1
Fix typo mistake in ranged for loop
2020-09-08 00:34:51 -04:00
Rabia Alhaffar
009b2963a8
Fix typo mistake in one of for loops 2020-09-08 05:23:08 +03:00
Glen Fraser
f355d27aea Fix GCC build error "explicit specialization in non-namespace scope"
- other compilers don't complain, but for GCC needed to move the
  template constructor specialization (array of size 0) outside the
  class declaration.
2020-09-04 13:52:25 +02:00
Glen Fraser
350acbf254 Fix compile errors on VS2019 (C++17) with Function_Params
- needed to disambiguate between chaiscript::Function_Params and
  chaiscript::dispatch::detail::Function_Params in several places.
2020-09-04 12:57:49 +02:00
Glen Fraser
4993e4773b Merge branch 'develop' into temp 2020-09-04 11:46:11 +02:00
Glen Fraser
cb9a8587b6 Remove MSVC special case in 'Object copy counts' unit test 2020-09-04 11:45:08 +02:00
Glen Fraser
dd69230f19 Fix issues with Function_Params constructors (array and vector args)
- code (on MSVC) was asserting due to trying to dereference invalid
  pointers (dereferencing the end iterator, even if only to get its
  address!).
- when a Function_Params is constructed with an empty vector, you
  can't return the address of the vec.front() -- instead we use
  nullptr for the m_begin and m_end pointers.
2020-09-04 11:27:52 +02:00
Rob Loach
6abbd9dd1b
Merge pull request #523 from tankorsmash/patch-1
fix typo in cheatsheet; add cpp highlighting
2020-05-22 17:50:48 -04:00
TankorSmash
aa3c4ae797
fix typo in cheatsheet; add cpp highlighting 2020-05-22 00:24:43 -04:00
Rob Loach
50ca037da9
Merge pull request #512 from clairvoyant/develop
Fix for warnings: by-copy capture of ‘this’ and unused-local-typedefs
2020-02-26 08:01:10 -05:00
Jose Rubio
85e4598986 Fix for warnings: by-copy capture of ‘this’ and unused-local-typedefs
There are two warnings when compiling with GCC 7.4.1 or clang 5.0.1.

   1. warning: explicit by-copy capture of ‘this’ redundant with by-copy capture default
   2. warning: typedef ... locally defined but not used [-Wunused-local-typedefs]

This change removes [2] and it compacts the lambda capture clause in [1].
2020-01-13 16:36:32 +01:00
SG-Skril
0e243b006a Potential fix for issue ChaiScript#481
(bool cannot be stored in Boxed_Number)
2019-11-10 18:07:47 +01:00
Dariusz Pyś
a3c033d1db
Fix bug #481
Applied solution sent by SG-Skril here: https://github.com/ChaiScript/ChaiScript/issues/481
2019-11-10 00:46:22 +01:00
Rob Loach
a7dae37a23
Update release notes for 6.1.1 2019-11-09 09:44:07 -05:00
Rob Loach
0ec4a928a6
Merge pull request #502 from guoyunhe/patch-1
Use CMAKE_INSTALL_LIBDIR instead of lib
2019-11-09 09:35:33 -05:00
Rob Loach
d355787820
Merge pull request #495 from Josh-Thompson/#487
#487: Fix warning for implicit 'this' lambda capture in C++20.
2019-11-09 09:35:22 -05:00
Guo Yunhe
cb1867dfd1
Update CMakeLists.txt 2019-11-09 12:01:50 +02:00
Guo Yunhe
0aa186abbe
Update CMakeLists.txt 2019-11-09 11:37:32 +02:00
Guo Yunhe
63951d06f2
Update CMakeLists.txt 2019-11-09 11:36:31 +02:00
Guo Yunhe
741893204a
Update CMakeLists.txt 2019-11-09 11:19:38 +02:00
Guo Yunhe
3e62181414
Use LIBDIR instead of lib
In Linux, the library should be installed to /usr/lib64 on 64bit machine
2019-11-09 11:10:45 +02:00
Rob Loach
21695875f8
Merge pull request #500 from grdowns/vcpkg-instructions
Add vcpkg installation instructions
2019-10-07 12:37:45 -04:00
grdowns
2de0844616 Add vcpkg installation instructions 2019-09-27 02:16:37 -07:00
Rob Loach
02490c26a6
Merge pull request #497 from hckr/patch-1
cheatsheet: fix link to ChaiScript_Extras
2019-09-02 18:45:35 -04:00
Jakub Młokosiewicz
eeda632846
cheatsheet: fix link to ChaiScript_Extras 2019-09-02 23:12:57 +02:00
Joshua Thompson
af7a5d7c49 #487: Fix warning for implicit 'this' lambda capture in C++20. 2019-08-22 10:00:37 -04:00
Rob Loach
58f2e5be8b
Merge pull request #492 from ChaiScript/fix/RobLoach/docs--genering
docs: Fix gendering
2019-06-27 22:51:02 -04:00
Rob Loach
8e5d4a712c
docs: Fix gendering
Fixes #491
2019-06-26 14:51:34 -04:00
Rob Loach
f235bd558a
Merge pull request #489 from 0xd800/develop
Fix description of ChaiScriptBasic::use
2019-06-05 11:28:59 -04:00
Vladyslav Tronko
273bc4a94a Fix description of ChaiScriptBasic::use
Add missing word
2019-06-05 15:19:31 +03:00
Rob Loach
6ce716f5f2
Merge pull request #474 from ChaiScript/push_back_ref
docs: Add push_back_ref() note
2019-04-25 18:26:39 -04:00
Rob Loach
2890f95597
Merge pull request #484 from medithe/patch-1
Update cheatsheet.md: Adding Lambda correction.
2019-04-25 18:03:11 -04:00
medithe
57ebd9d403
Update cheatsheet.md: Adding Lambda correction.
Currently, the example where a lambda function was added to chaiscript didn't work for me.
I use g++7, g++8,g++9 both with c++14 and c++17 mode.
It doesn't work either in clang++-7.

If the lambda is wrapped into a std::function<> it will work again!
2019-04-25 23:18:51 +02:00
Glen Fraser
a5a756a20e Add pair_conversion registration helper with unit test 2019-04-21 20:28:30 +02:00
Jason Turner
27072a77e6 Get VS compiling 2019-04-20 12:26:12 -06:00
Jason Turner
b7e26b9076 Attempt to get C++17 work compiling for VS 2019 2019-04-20 12:09:24 -06:00
Rob Loach
62ccd6d2ff
docs: Add push_back_ref() note 2019-01-31 09:16:59 -05:00
Rob Loach
b0c1483f70
Merge pull request #468 from vocaviking/patch-1
Updated cheatsheet.md
2018-12-26 08:38:03 -05:00
vocaviking
c0f217abab
Moved ChaiScript_Extras to the bottom 2018-12-21 15:43:52 +01:00
vocaviking
cba13f94d6
Updated cheatsheet.md
- Simplified the part about ChaiScript initialization
- Added a link to the ChaiScriptExtras helper library
- Removed the Subsection about built-ins, because they are not longer in the code
2018-12-19 13:03:30 +01:00
Jason Turner
8c7ea9bd32
Merge pull request #463 from yuyaryshev/develop
Fix: added 'static' to thread_local variable in chaiscript/chaiscript…

Necessary to compile on VS
2018-11-15 09:33:07 -07:00
Yuri Yaryshev
7a67963ca7 Fix: added 'static' to thread_local variable in chaiscript/chaiscript_threading.hpp
Because it's a singleton and should be one instance per thread, without it will be singleton per call,
also it won't compile on VS2017 15.8.9
The error:
chaiscript\include\chaiscript\chaiscript_threading.hpp(107): error C2480: 'my_t': 'thread' is only valid for data items of static extent
2018-11-15 18:59:18 +03:00
Alek Mosingiewicz
8d0fc74341 Ci fix after moving to cpp17 (#455)
* Update travis configuration.

* Update GCC_VER in travis configuration.

* Leave only Visual Studio 15 in Appveyor.

* Travis - remove GCC_VER 4.9.

* Travis - update clang-xcode.

* Travis - update clang compiler.

* Travis - downgrade clang compiler to 3.4.

* Revert "Travis - downgrade clang compiler to 3.4."

This reverts commit bd6698bccea9252dd00e8f28fb31334b0e3ea743.

* Travis - clang-6.0 package and compiler.

* Travis - remove (perhaps unnecessary) compiler option.

* Travis - restore clang compiler option.

* Update .travis.yml

* Another attempt to fix Travis config for clang.

* Another attempt to fix Travis config for clang.

* Compiler package for clang.

* Compiler package for clang.

* Xcode 10.

* Remove xcode from equation.

* Force install clang-6.0.

* Does it install these packages at all???.

* Does it install these packages at all???.

* Some appveyor fixes.

* Update CMakeLists.txt

Enforce C++17 standard

* Update .travis.yml

Restore xcode, block CLANG_VER.

* experimental/variant for Apple compilers.

* Remove OSX pipeline.

* Remove OSX pipeline.

* Attempt at fixing AppVeyor pipeline.

* Restore proper VS version in AppVeyor configuration.

* Revert preprocessor changes in json.hpp.
2018-10-20 08:50:08 -06:00
Jason Turner
7931405b83
Merge pull request #457 from ninnghazad/patch-1
Single typo (Mame -> Name)
2018-10-07 15:27:55 -06:00
ninnghazad
e729e4e86c
Single typo (Mame -> Name)
Fixed a typo (Mame -> Name) i came across.
2018-09-25 15:02:47 +02:00
Jason Turner
c737f2419b
Merge pull request #453 from AlekMosingiewicz/error_on_double_conversion
Error on double conversion
2018-08-15 13:33:13 -06:00
Jason Turner
5db87a9175 Merge branch 'release-6.x' into develop 2018-08-15 13:13:44 -06:00
Jason Turner
3af55d60f2 Update version to 6.1.1 2018-08-15 13:12:36 -06:00
Jason Turner
44dab4d45c Deal with returning of & to * types 2018-08-15 13:10:23 -06:00
Jason Turner
4be5e876b8 Add failing test for returning of & to * 2018-08-15 11:19:09 -06:00
Alek Mosingiewicz
9f9436e741 Remove newlines. 2018-08-13 21:19:15 +02:00
Alek Mosingiewicz
b9741d9433 Make conversion_error inherit from bad_boxed_cast. 2018-08-13 18:25:43 +02:00
Alek Mosingiewicz
a254e11286 Make information on source and target types in Type Conversion
Exception public.
2018-08-13 17:57:38 +02:00
Alek Mosingiewicz
eb3ee28cee Some better naming for test. 2018-08-13 17:56:49 +02:00
Alek Mosingiewicz
80f11de41e Make information on source and target types in Type Conversion
Exception public.
2018-08-10 17:57:15 +02:00
Alek Mosingiewicz
27bee4a266 Bypass the mutex problem when looking for conversion, automatic
test.
2018-08-10 17:29:46 +02:00
Alek Mosingiewicz
ecd6000d54 Throw conversion error when conversion already exists. 2018-08-07 18:00:58 +02:00
Jason Turner
2dfd444178 Formatting cleanup 2018-06-11 05:27:48 -06:00
Jason Turner
07fdb3bf6e Remove backward compatibility tests 2018-06-03 16:48:03 -06:00
Jason Turner
d0d08d2ed9 Merge branch 'best_practices' into develop 2018-06-03 16:40:29 -06:00
Jason Turner
aa61df941b
Merge pull request #420 from StanEpp/c++17
Add support for chained dot calls.
2018-06-03 15:47:05 -06:00
Jason Turner
63d1b16a7e Merge branch 'upgrade-cmake' into best_practices 2018-05-30 08:32:07 -06:00
Jason Turner
a880319db8 Merge branch 'develop' into best_practices 2018-05-30 08:30:29 -06:00
Jason Turner
c19705da5d Merge remote-tracking branch 'origin/c++17' into develop 2018-05-29 13:21:09 -06:00
Jason Turner
2d762c8be3 Update copyrights to 2018 2018-05-29 11:51:15 -06:00
Jason Turner
5b66481996 Merge branch 'master' into develop 2018-05-29 11:47:12 -06:00
Jason Turner
2e77b9d0bf
Merge pull request #441 from ChaiScript/develop
Update for release to 6.1.0
2018-05-29 11:46:51 -06:00
Jason Turner
8a74bdbfe5 Tag license files for detection 2018-05-29 11:45:09 -06:00
Jason Turner
ac0d7ce949 Fix lifetime of objects in ranged for loops
Currently this is going to incur a performance cost, but it's correct.

It may need to be reevaluated.

Closes #392
2018-05-29 09:26:59 -06:00
Jason Turner
d5d5561d74 Add failing test for lifetime with ranged-for loop
References: #392
2018-05-29 08:03:59 -06:00
Jason Turner
98c362d038 Properly report which file failed to be loaded
closes #437
2018-05-29 07:45:43 -06:00
Jason Turner
145acd378b Take parse depth to 512, make it templated
Closes #442
2018-05-29 07:09:25 -06:00
Jason Turner
f09b2d8731 Update release notes and fix compiler warnings 2018-05-26 20:29:25 -06:00
Jason Turner
61dfb22af8
Merge pull request #439 from AlekMosingiewicz/handle-bom-in-script
Handle BOM in the beginning of the script
2018-05-26 14:08:29 -06:00
Jason Turner
7d5dda244e Fix capitalization for case sensitive file systems 2018-05-26 10:36:04 -06:00
Jason Turner
15e3dea53b Merge branch 'develop' of github.com:ChaiScript/ChaiScript into develop 2018-05-26 09:28:14 -06:00
Jason Turner
73f177c73e Move to official catch cmake support, update catch
This is an effort to fix the issues on Appveyor with newer versions of
CMake. Will have to double check that it does not break Travis
2018-05-26 09:26:13 -06:00
Jason Turner
98b10c6435 Another attempt to fix appveyor config 2018-05-26 06:50:33 -06:00
Jason Turner
52a26bea5f Fix indentation for appveyor config 2018-05-25 17:07:23 -06:00
Jason Turner
f8bb8dc53e Set build flags for appveyor builds 2018-05-25 17:03:36 -06:00
Jason Turner
9c26289254 Merge branch 'develop' of github.com:ChaiScript/ChaiScript into develop 2018-05-25 16:50:20 -06:00
Jason Turner
8bc7b9bfa1 Add notes for v6.1.0 release prep 2018-05-25 16:49:57 -06:00
Jason Turner
dae0f3dd62
Merge pull request #411 from stephenberry/develop
Critical fix of type_info ordering (less than operator)
2018-05-25 16:27:56 -06:00
Jason Turner
9c28f2f180 enhance building of fuzzer 2018-05-25 16:23:19 -06:00
Jason Turner
805e7c0917 Fix up some error handling 2018-05-25 14:33:17 -06:00
Jason Turner
e0f29e0f7c Limit parse depth to avoid stackoverflow 2018-05-25 08:34:17 -06:00
Alek Mosingiewicz
b3f77f0c82 Fix implicit conversion warning. 2018-05-25 12:17:22 +02:00
Alek Mosingiewicz
0f67b2f430 Another fix for Clang. 2018-05-25 12:07:50 +02:00
Alek Mosingiewicz
fb635033a9 Fix for Clang. 2018-05-25 11:56:10 +02:00
Alek Mosingiewicz
393f8d31ab Travis build quick fix. 2018-05-25 11:48:27 +02:00
Alek Mosingiewicz
1711d50eff Another attempt to remedy the problem occuring on Clang. 2018-05-25 08:38:25 +02:00
Alek Mosingiewicz
42c355a8d0 Revert "Attempt to remedy the problem occuring on Clang."
This reverts commit 0e964da42658a4e7e5bebe281f2c125575f34246.
2018-05-25 08:06:35 +02:00
Alek Mosingiewicz
0e964da426 Attempt to remedy the problem occuring on Clang. 2018-05-25 07:59:34 +02:00
Alek Mosingiewicz
51693aa0bd Skip buffer initialization. 2018-05-25 06:57:22 +02:00
Alek Mosingiewicz
51bb793664 Initialize buffer to store potential BOM data before storing
anything inside it.
2018-05-24 22:06:59 +02:00
Alek Mosingiewicz
edadb7aa98 Use readsome instead of reading the stream byte-by-byte to
detect BOM in processed file.
2018-05-24 22:04:10 +02:00
Alek Mosingiewicz
ac10575b5f Read the stream byte by byte, condition for size when skipping BOM. 2018-05-24 21:38:47 +02:00
Stephen Berry
d24743370a Merge branch 'develop' of https://github.com/ChaiScript/ChaiScript into develop 2018-05-24 12:21:35 -05:00
Alek Mosingiewicz
4ada12a34c Check EOF rather than buffer_size when skipping BOM. 2018-05-23 18:41:07 +02:00
Alek Mosingiewicz
67dcd3e8d8 Test case for BOM in user-provided string. 2018-05-22 17:12:14 +02:00
Alek Mosingiewicz
df6bc8f9b5 Add missing test cases. 2018-05-22 17:07:32 +02:00
Alek Mosingiewicz
f9615efea5 Another text size assertion. 2018-05-22 16:27:19 +02:00
Alek Mosingiewicz
d880d46214 Type cast fix. 2018-05-22 16:23:22 +02:00
Alek Mosingiewicz
be29b0a193 Merge branch 'develop' into handle-bom-in-script 2018-05-22 05:00:41 +02:00
Alek Mosingiewicz
b70a9e7a61 Non-ASCII characters now in random positions in test; test renamed. 2018-05-21 17:12:11 +02:00
Alek Mosingiewicz
60c0a0bf15 Refactor skippable BOM detection. 2018-05-21 17:04:33 +02:00
Jason Turner
062f821b46 Merge branch 'develop' of github.com:ChaiScript/ChaiScript into develop 2018-05-20 20:57:56 -06:00
Jason Turner
0520bb178c Fix capture error 2018-05-20 20:36:33 -06:00
Alek Mosingiewicz
0d44b0b456 Added doc comment. 2018-05-15 19:32:17 +02:00
Alek Mosingiewicz
322568ba39 Check for illegal characters while parsing input. 2018-05-15 19:25:28 +02:00
Alek Mosingiewicz
c09af92963 Decrement file size when BOM is present to avoid parsing errors. 2018-05-13 13:09:38 +02:00
Alek Mosingiewicz
a024db040d Catch BOM at the beginning of file. 2018-05-13 12:24:34 +02:00
Alek Mosingiewicz
efbebee9da Throw exception when user-provided input contains BOM. 2018-05-13 10:25:04 +02:00
Jason Turner
b9a5607a56
Merge pull request #438 from RobLoach/patch-1
Add Switch Statement example
2018-05-12 09:41:37 -06:00
Alek Mosingiewicz
1e8f7f9fa5 Simplify BOM test. 2018-05-10 18:40:56 +02:00
Alek Mosingiewicz
1d782338c9 Cover skipping BOM with test. 2018-05-10 18:23:39 +02:00
Alek Mosingiewicz
f37d0e13d3 Skip UTF-8 BOM before parsing begins. 2018-05-10 17:44:06 +02:00
Rob Loach
5c2fd20a9e
docs: Add Switch Statement example 2018-05-09 19:18:34 -04:00
Jason Turner
c14d9dfb6e Fix some new clang related warnings 2018-05-08 10:05:10 -06:00
Jason Turner
f695a24e1b Fix clang warning for undefined msvc symbol check 2018-05-08 09:46:01 -06:00
Jason Turner
06191646d2
Merge pull request #418 from ChaiScript/apply_unicode_patches
Apply unicode patches
2018-05-08 09:08:25 -06:00
Jason Turner
9a670d79fc Merge branch 'develop' of github.com:ChaiScript/ChaiScript into develop 2018-04-01 11:07:11 -06:00
Jason Turner
a48f358555 Better error reporting on missing type info 2018-04-01 11:06:48 -06:00
Jason Turner
3bf72420c2
Merge pull request #424 from zemasoft/develop
Fix CHAISCRIPT_NO_THREADS macro redefinition warning
2018-03-17 12:28:15 -06:00
Tomas Zeman
c2a3518eb0 Fix CHAISCRIPT_NO_THREADS macro redefinition warning
Appeared when compiling with MULTITHREAD_SUPPORT_ENABLED=FALSE.
2018-03-10 19:23:06 +01:00
Jason Turner
4139eb1efc
Merge pull request #423 from zemasoft/develop
Fix potential conversion warning on some platforms
2018-03-09 10:45:18 -07:00
Tomas Zeman
3dec2af071 Fix potential conversion warning on some platforms 2018-03-09 10:19:33 +01:00
Stan
be5709ab5c Add support for chained dot calls. 2018-03-04 22:49:36 +01:00
Jason Turner
258cb23dda Further fixes for compiled tests for VS 2015 2018-03-02 15:40:22 -07:00
Jason Turner
476a752a08 Fix last merge 2018-03-02 15:09:52 -07:00
Jason Turner
2818ec67df Merge remote-tracking branch 'origin/develop' into apply_unicode_patches 2018-03-02 15:01:41 -07:00
Jason Turner
2e9512c6b8 Adjust unicode tests for MSVC 2018-03-02 08:54:27 -07:00
Jason Turner
12797c0a03 Add C++ tests to verify strings match
Re #415
2018-03-02 08:01:03 -07:00
Jason Turner
1a9165f7fc Normalize on C++'s standards for \u and \U 2018-03-02 07:45:24 -07:00
Jason Turner
1b9027a24f Fix handling of 32 bit unicode character escapes 2018-03-01 17:03:50 -07:00
Jason Turner
81ebe1a7be Fix the compiler warnings related to unicode parsing
Re #415
2018-03-01 13:40:49 -07:00
Jason Turner
1311c97c49 Fix unit tests for unicode to be consistent with how it should work
Addresses #415
2018-03-01 12:57:56 -07:00
Jason Turner
1acfb4f7b8 Apply patch from @chris0e3 2018-03-01 11:22:20 -07:00
Jason Turner
d5faaeca1a Add failing unicode test from #415 2018-03-01 11:20:22 -07:00
Jason Turner
ef47b4582e Merge branch 'develop' of github.com:ChaiScript/ChaiScript into develop 2018-03-01 11:12:36 -07:00
Jason Turner
6a8541971e
Merge pull request #410 from arcoRocks/patch-3
Fix for #409
2018-03-01 10:44:45 -07:00
Jason Turner
9c5514f1b6
Merge pull request #414 from arcoRocks/patch-4
fix for #413
2018-03-01 10:42:55 -07:00
arcoRocks
33451163c4
to_json std::int64_t integer conversion 2018-02-20 16:28:23 +01:00
arcoRocks
e23c2bb04f
fix for #413 2018-02-20 16:23:45 +01:00
arcoRocks
906e5e2b6f
Update json_15.chai 2018-02-20 16:13:17 +01:00
Jason Turner
c902771f16 Use catch's test parser 2018-02-19 16:36:08 -07:00
Jason Turner
21b397c2cb Prep for moving to Catch2 official test parsing 2018-02-19 11:34:16 -07:00
arcoRocks
3e1916a8d5
fix for #413 2018-02-19 13:31:38 +01:00
Stephen Berry
0ad4f83366 Removed constexpr for Visual Studio compilation. Xcode (LLVM) works with constexpr on the before function, but Visual Studio (2015) does not. 2018-02-15 09:10:11 -06:00
Stephen Berry
2dbfdfe111 Critical type_info ordering fix. Was using a less than comparison on pointers, which sometimes resulted in differing behavior between compilations. 2018-02-15 08:59:20 -06:00
arcoRocks
88042c7958
Fix for #409 2018-02-15 14:33:38 +01:00
Jason Turner
0391a9c715 Remove DYNLIB disabled build for linux from travis
This is already covered by MacOS anyhow, so
we aren't missing anything in our build coverage
2018-02-02 22:19:31 -07:00
Jason Turner
5cd9e94d4a Third attempt to avoid ICE on travis 2018-02-02 21:54:08 -07:00
Jason Turner
55b16a8204 Enhance tests for execution contexts
Closes #387 references #388
2018-02-02 21:41:49 -07:00
Jason Turner
1c5c34561b
Merge pull request #388 from arcoRocks/patch-2
Fix for #387
2018-02-02 21:34:12 -07:00
Jason Turner
bbaa6ed76f
Merge pull request #400 from totalgee/to_json_fixes
In to_json(), maintain the "type" of empty maps and vectors
2018-02-02 21:33:11 -07:00
Jason Turner
e154e1e380 Move DYNLIB disabled builds to G++5 2018-02-02 21:31:19 -07:00
Jason Turner
35af4edb30 Ignore some warnings from clang++ 2018-02-02 21:04:21 -07:00
Jason Turner
9be8f36824 Fix some warnings found on g++7 2018-02-02 20:36:29 -07:00
Jason Turner
6c41ac90d8 Add to_int(int) and similar overloads
* This is so that `to_int` `to_char` `to_long` and similar work not
   only with strings but also with built-in types
2018-02-02 20:35:32 -07:00
Jason Turner
de4b497de1 Merge branch 'develop' of github.com:ChaiScript/ChaiScript into develop 2018-02-02 20:22:19 -07:00
Jason Turner
0c32c5054c Add clarification on use-after-move 2018-01-19 13:01:44 -07:00
Jason Turner
cb30a97832 Workaround for /permissive- on MSVC
Addresses #403
2018-01-19 13:01:05 -07:00
Jason Turner
695fa0b371 Proper fix for noexcept/msvc2017
From @StephanTLavavej
2018-01-19 11:54:19 -07:00
Jason Turner
ad606c7cfa Update to catch2 for MSVC2017 compat 2018-01-19 10:46:37 -07:00
Jason Turner
eb93760f1b Fix building on MSVC in C++17 mode
Closes #403 #396 #395
2018-01-19 10:26:31 -07:00
Jason Turner
be8726b41a
Merge pull request #382 from arcoRocks/patch-1
Update json_wrap.hpp
2018-01-18 16:54:45 -07:00
Glen Fraser
3d97c93e49 Add unit test to validate to_json() 2018-01-11 19:44:54 +01:00
Glen Fraser
783b8b7361 In to_json(), maintain the "type" of empty maps and vectors
- fix issue #399.
- make to_json() with an empty Map, Vector or Dynamic_Object return a
  similar/compatible type (JSON object or array), rather than "null".
- include the fix for #381 (to_json() support for null values), so
  that can also be unit tested.
2018-01-11 19:44:27 +01:00
Jason Turner
f8c8bad468 Merge remote-tracking branch 'origin/c++17' into best_practices 2017-12-16 11:52:07 -07:00
Jason Turner
6bfc130b73 Fix pull from develop, fix gcc warnings 2017-12-16 11:50:32 -07:00
Jason Turner
cd05b1f750 Merge branch 'develop' into best_practices 2017-12-16 10:22:25 -07:00
Jason Turner
6c18c64270 Formatting updates 2017-12-16 10:21:02 -07:00
Jason Turner
4a61d1e511 Enable C++latest for C++17 Visual Studio builds 2017-12-14 08:13:19 -07:00
Jason Turner
e78f8a73f9 Add .clang-format file 2017-12-04 19:55:38 -07:00
arcoRocks
f6ffcd9481
Fix for #387 2017-12-04 13:41:59 +01:00
Jason Turner
136539867c Remove outdated vim support
Closes #288
2017-11-30 10:19:56 -07:00
Jason Turner
e884f0816d Merge branch 'develop' of github.com:ChaiScript/ChaiScript into develop 2017-11-30 10:08:26 -07:00
Jason Turner
56140608ef Fix scope optimizations for ranged for and refs
Closes #383
2017-11-30 10:06:32 -07:00
Jason Turner
dee2ce5c56 Add failing test for ranged_for with variable 2017-11-30 09:47:20 -07:00
arcoRocks
ed9c0747fb
Update json_wrap.hpp 2017-11-28 08:06:46 +01:00
Jason Turner
3a019b06c3
Merge pull request #380 from stephenberry/develop
Improved parsing speed of parse_num
2017-11-27 20:26:08 -07:00
Jason Turner
035319bbd0 Fix "compiled loop" optimization 2017-11-26 22:31:35 -07:00
Jason Turner
db72ab626f Consolidate hand-rolled flat maps 2017-11-24 22:20:52 -07:00
arcoRocks
af76d1bb42
Update json_wrap.hpp
Fix for #381
2017-11-24 10:15:06 +01:00
Jason Turner
48e5a46cbd Move to QuickFlatMap from manual vector map thing 2017-11-23 22:38:15 -07:00
Stephen Berry
bcd01f3b03 Fixed issue when lacking positive exponent sign 2017-11-22 14:52:05 -06:00
Stephen Berry
2c30268bf2 Improved parsing speed of parse_num 2017-11-22 14:06:03 -06:00
Jason Turner
b47fec2f71 Comment out clone_object tests from typed_function_ordering 2017-11-21 16:37:18 -07:00
Jason Turner
6ae3f2d187 Merge remote-tracking branch 'origin/develop' into best_practices 2017-11-21 16:28:12 -07:00
Jason Turner
903454bf05
Merge pull request #290 from stephenberry/develop
Adding basic namespace handling
2017-11-21 16:27:40 -07:00
Jason Turner
f462796ee5 Add clone shortcircuit for strings 2017-11-21 16:17:53 -07:00
Jason Turner
fe405a781c Revert "Merge branch 'typed_function_ordering' into c++17"
This reverts commit 5d5a126bb15b8490ebdb92a8f0a8b2b990d8a067, reversing
changes made to dd912822a7979aad101042c62478c2441ae21d1a.
2017-11-21 16:10:13 -07:00
Jason Turner
8b523c73b8 Merge remote-tracking branch 'origin/develop' into best_practices 2017-11-21 15:34:04 -07:00
Jason Turner
f37bb847c7 Merge remote-tracking branch 'origin/c++17' into best_practices 2017-11-21 14:59:04 -07:00
Jason Turner
9f2ed24dd0
Merge pull request #369 from mlang/use-using
Use using
2017-11-21 14:54:13 -07:00
Jason Turner
fdddba1e00
Merge pull request #355 from bogemic/pvs-studio-warnings-v728
fixed PVS-Studio warnings V728
2017-11-21 14:51:56 -07:00
Jason Turner
e2aec593c1
Merge pull request #366 from mlang/future_type
Allow standard_library::future_type to bootstrap hpx::lcos::future
2017-11-21 14:42:11 -07:00
Jason Turner
bd6c83f3b1
Merge pull request #371 from dinghram/develop
from_json: change long to int64_t to remove OS ambiguity
2017-11-21 14:41:30 -07:00
Jason Turner
680f9b9242
Fix variable redeclaration from last merge conflict fix. 2017-11-21 14:06:42 -07:00
Jason Turner
e97d3723df
Merge branch 'develop' into develop 2017-11-21 13:54:54 -07:00
Jason Turner
8307663938 Look for and optimize decl assignments
Re: #356
2017-11-21 10:26:58 -07:00
Jason Turner
50a2773081 Reduce cost of cloning common built in types
Re: #356
2017-11-21 09:01:17 -07:00
Jason Turner
784c3a9720 Add slow test for creating variables
References #356
2017-11-21 07:12:17 -07:00
Jason Turner
61bce30901 Unused code removal 2017-11-21 06:30:19 -07:00
Jason Turner
7f822be5db
Merge pull request #377 from totalgee/negative_exponent_json
Fix JSON parsing for floats with negative exponents
2017-11-20 21:54:38 -07:00
Jason Turner
a1772a055b Remove some std::endl usage 2017-11-19 06:25:30 -07:00
Jason Turner
c6021f3e61 Bug fix from Function_Params refactor 2017-11-19 06:20:27 -07:00
Jason Turner
92ae85c3e8 Remove guards from catch blocks 2017-11-18 19:08:14 -07:00
Jason Turner
d59350d356 Various cleanups 2017-11-18 18:42:45 -07:00
Jason Turner
a6d30baa27 Apply some if constexpr action 2017-11-17 06:12:50 -07:00
Jason Turner
b03b90dee6 Fix bug introduced with Function_Params refactor 2017-11-17 05:26:24 -07:00
Jason Turner
28a59d2a6e Avoid creating vectors when possible 2017-11-16 09:10:48 -07:00
Jason Turner
425c679c6c Fix GLOBAL in clone_object tests 2017-11-13 09:03:55 -07:00
Jason Turner
5d5a126bb1 Merge branch 'typed_function_ordering' into c++17 2017-11-13 00:33:59 -07:00
Jason Turner
dd912822a7 Merge commit '8895ee8fc58ff13e7ee17007aeab6f78bf9f81f1' into c++17 2017-11-13 00:03:25 -07:00
Jason Turner
8895ee8fc5 Fix assignment / modification of return values 2017-11-13 00:02:22 -07:00
Jason Turner
91bcf1187e minor noexcept adjustments 2017-11-12 04:09:37 -07:00
Jason Turner
df21840feb Merge branch 'develop' into c++17 2017-11-12 03:22:16 -07:00
Jason Turner
df629c62f5
Merge pull request #373 from superfunc/develop
Fix link in readme
2017-11-04 18:21:10 -06:00
Glen Fraser
79d985d6ff Fix JSON parsing for floats with negative exponents
- also add unit tests to cover some broken (now fixed) cases.
2017-10-24 20:10:50 +02:00
superfunc
2b735d1b3a Fix link in readme 2017-10-21 15:14:27 -07:00
Jason Turner
f42bdb7541 Merge branch 'develop' into typed_function_ordering 2017-10-14 15:50:18 -06:00
dinghram
1541cce1d9 Change long to int64_t to remove OS ambiguity
Linux compilers interpret "long" as 64 bit, Visual Studio on Windows interprets "long" as 32 bit. In order to remove ambiguity, from_json should use int64_t rather than long when parsing integers.
2017-10-03 08:43:01 -06:00
Jason Turner
be225a9209 Merge branch 'develop' of github.com:ChaiScript/ChaiScript into develop 2017-10-02 09:53:23 -06:00
Jason Turner
15196af5d6 Remove one case of UB union work 2017-10-02 09:52:51 -06:00
Mario Lang
f54aa90736 Use using 2017-09-25 16:55:18 +02:00
Jason Turner
c6237cc528 Add += char for string type 2017-09-21 08:55:32 -06:00
Jason Turner
8e590387f1 Merge branch 'constexpr' into c++17 2017-09-20 17:05:31 -06:00
Jason Turner
6cae70c208 Move to module level statics from function level 2017-09-20 16:44:32 -06:00
Jason Turner
c5a9cab3dd Simple cleanup for string comparisons 2017-09-20 15:34:19 -06:00
Jason Turner
7142d0ea39 Merge pull request #367 from mlang/range-based-for
Use range-based for
2017-09-18 09:24:02 -07:00
Mario Lang
3e521d2952 Delete now useless local copy 2017-09-18 17:00:04 +02:00
Mario Lang
0fa0def112 Use range-based for 2017-09-18 15:00:52 +02:00
Mario Lang
ee3f828b8c Allow bootstrapping hpx::lcos::future
Which has an overloaded get(error_code &).  Use a lambda in
standard_library::future_type to disambiguate.
2017-09-15 10:12:47 +02:00
Jason Turner
ee0d6e676c Merge pull request #365 from mlang/samples_upgrade
-?
2017-09-14 09:34:04 -07:00
Mario Lang
a87147a12d Upgrade samples where it improves readability 2017-09-14 17:41:11 +02:00
Jason Turner
e38b05ff9a Better constexpr for comment types 2017-09-10 07:12:33 -06:00
Stephen Berry
037faddab4 Updated cheatsheet.md for latest namespace implementation 2017-09-05 13:48:12 -05:00
Stephen Berry
ff78d31583 Simplified namespace handling code and requiring all namespace registration to allow for delayed generation. This simplifies generating namespaces by the user and leads to more efficient code. 2017-09-05 13:26:55 -05:00
Stephen Berry
a9fc1d492e Merge branch 'develop' of https://github.com/ChaiScript/ChaiScript into develop 2017-09-05 12:13:29 -05:00
Stephen Berry
3f299333cc Switched to recursive mutex
Removed namespaces_nested_ref.chai
2017-09-05 12:02:11 -05:00
Jason Turner
f338586d37 Performance improvements and LOC reduction in BoxedNumber 2017-09-02 19:06:46 -06:00
Jason Turner
bfe7799d13 Come C++17 updates, namespaces, etc 2017-09-02 13:12:52 -06:00
Jason Turner
1738476321 Make comparison constexpr 2017-08-30 08:41:08 -06:00
Jason Turner
4213f24761 Various C++17 considerations 2017-08-29 16:14:44 -06:00
Jason Turner
ac78e978fe Move to template type deduction for function signature 2017-08-26 14:19:38 -06:00
Jason Turner
e6a6a20eb6 Handful for C++17 things 2017-08-26 08:24:55 -06:00
Jason Turner
f9a1784b9b Move json.hpp to variant 2017-08-25 19:48:30 -06:00
Jason Turner
4275ec6878 Make it easier to swap around some hashing algorithms 2017-08-25 15:31:24 -06:00
Jason Turner
dce9e17c34 More string_view tweaks 2017-08-25 14:49:44 -06:00
Jason Turner
04902f8209 Use C++17's emplace_back return reference 2017-08-25 12:48:34 -06:00
Jason Turner
e49df4c54d Move the parser to string_view 2017-08-25 11:17:47 -06:00
Jason Turner
ff70341af2 Avoid conversions to string_view, 2% perf savings 2017-08-24 21:14:05 -06:00
Jason Turner
d115dbfd79 move towards string_view 2017-08-24 20:46:22 -06:00
Jason Turner
9596e15049 Warning / build fixes for gcc7 2017-08-24 18:35:03 -06:00
Jason Turner
9bbe723827 Fix unhandled divide by zero 2017-08-23 21:38:41 -06:00
Jason Turner
7722841294 More if constexpr work 2017-08-23 21:23:18 -06:00
Jason Turner
dd918c524d Use if constexpr in boxed_number 2017-08-23 20:20:17 -06:00
Jason Turner
8568b61014 Merge branch 'constexpr' of github.com:ChaiScript/ChaiScript into constexpr 2017-08-23 16:13:39 -06:00
Jason Turner
b8b548bab3 more constexpr for parser 2017-08-23 16:10:10 -06:00
Jason Turner
0d76241f77 Avoid capture of constexpr value 2017-08-23 16:08:44 -06:00
Jason Turner
3feb084438 constexpr user_type objects 2017-08-22 22:22:47 -06:00
Jason Turner
d56c5b489b Fix bug exposed while moving to constexpr 2017-08-22 16:15:25 -06:00
Jason Turner
21500a1dcc Add source tracking for uninit memory sanitizer 2017-08-22 16:13:17 -06:00
Jason Turner
ac7af60d76 Make constructors return values, not shared_ptr 2017-08-22 15:54:42 -06:00
Jason Turner
b810e4f7d9 Callable traits constexpr 2017-08-22 13:29:08 -06:00
Jason Turner
ac8f876347 constexpr fixes for Visual Studio 2017-08-22 12:02:42 -06:00
Jason Turner
b51b52dea9 constexpr bind_first 2017-08-22 10:03:26 -06:00
Jason Turner
535c0344b7 Make function constexpr 2017-08-20 13:11:57 -06:00
Jason Turner
ddb2f352cd Initial simple application of constexpr to API 2017-08-17 11:27:14 -06:00
Jason Turner
58f740844d Undo perf hit to keyword lookups 2017-08-15 13:17:23 -06:00
Jason Turner
0fc420f69d Revert "Remove exception specification shared_ptr use"
This reverts commit e1cf8b9eb1d59d49149454424ec49bd0d8a3b28f.
2017-08-15 10:13:20 -06:00
Jason Turner
1ca857b890 Satisfy older clangs by adding default ctor 2017-08-11 14:20:17 -06:00
Jason Turner
710b3c4003 Fix instantiation of Static_String for older compilers 2017-08-11 08:57:44 -06:00
Jason Turner
ca8f78ff89 JSON noexcept updates 2017-08-10 22:22:13 -06:00
Jason Turner
73d543eef0 Make operator lookup noexcept 2017-08-10 20:32:39 -06:00
Jason Turner
5ba155e058 Make operators noexcept (removing std::vector usage) 2017-08-10 19:52:32 -06:00
Jason Turner
5d56051532 Various noexcept additions 2017-08-10 19:47:03 -06:00
Jason Turner
e1cf8b9eb1 Remove exception specification shared_ptr use 2017-08-10 10:28:16 -06:00
Jason Turner
7986ea08b6 More work towards all noexcept, warning cleanups 2017-08-09 14:36:45 -06:00
Jason Turner
34534c1386 Changes that noexcept want to happen 2017-08-08 17:06:36 -06:00
Jason Turner
171765cfdb Add back in extent capture 2017-08-06 18:19:43 -06:00
Jason Turner
7f6f1d8a59 Fix clang warnings, fix misplaced noexcept 2017-07-31 16:12:16 -06:00
Jason Turner
2662395cac Merge pull request #359 from njlr/develop
Buck build support
2017-07-29 16:12:01 -06:00
Jason Turner
3f8b697e9e Fix windows noexcept build 2017-07-23 07:38:20 -06:00
Jason Turner
e07cd88659 Add noexcept where appropriate
This modifies no logic, it simply adds the keyword `noexcept`

I believe this is 100% correct. It calls methods that are not
guaranteed to be `noexcept`, such as `operator[]` but have
no logically way of throwing.
2017-07-22 20:33:30 -06:00
Jason Turner
f20cdc7c8f fix compilation of performance tests 2017-07-21 05:59:45 -06:00
Jason Turner
755f650a8d strip noexcept 2017-07-21 05:44:20 -06:00
njlr
cdf152b013 * Added Buckaroo.pm package 2017-07-21 11:09:53 +01:00
njlr
f640784d56 Merge github.com:ChaiScript/ChaiScript into develop 2017-07-21 11:06:10 +01:00
Jason Turner
ef333e491a remove existing constexpr 2017-07-20 21:16:54 -06:00
Jason Turner
f753961ab7 Merge pull request #357 from ChaiScript/remove_enable_shared_from_this
Remove enable shared from this
2017-07-20 22:01:02 -05:00
Jason Turner
0f74597139 Limit when coverage happens to only one build target 2017-07-20 15:08:53 -06:00
Jason Turner
f465d2ceca Make sure to not deref null parse node 2017-07-20 06:10:31 -06:00
Jason Turner
14eaefdceb Make front() back() checked 2017-07-19 15:52:34 -06:00
Jason Turner
f03659c865 More careful testing of 'for' parses 2017-07-19 13:19:36 -06:00
Jason Turner
b42316a275 More careful with json errors 2017-07-19 13:19:17 -06:00
Jason Turner
d8da295e40 Check string accesses during JSON parsing 2017-07-19 10:47:17 -06:00
Jason Turner
cfb2e663d3 Fix unhandled exception found via libfuzzer 2017-07-19 10:09:44 -06:00
Jason Turner
ea03a5462f Wrap up build issues for dropping of shared_ptr 2017-07-18 16:58:09 -06:00
Mike Bogdanov
0c31d81711 fixed PVS-Studio warnings V728 2017-07-13 12:41:23 +03:00
Jason Turner
77315ae4b9 Fix non-shared_ptr tree code 2017-06-22 09:32:49 -06:00
Jason Turner
5a5600914c Move away from shared_ptr for parse nodes 2017-06-21 21:27:48 -06:00
Jason Turner
700a620552 Add option to compile in C++17 mode for testing 2017-06-06 16:47:23 -06:00
Jason Turner
36e61dec0a Fix defaults for dynload options 2017-06-06 14:59:05 -06:00
Jason Turner
76c7712507 Test custom exception handling #351 2017-06-05 19:36:40 -06:00
Jason Turner
d720d069ca Attempt to add visual studio 2017 to appveyor 2017-05-31 14:56:51 -06:00
Jason Turner
94f7bfec2b Remove gcc-7 from package list for travis 2017-05-31 14:46:20 -06:00
Jason Turner
562ca5aee6 gcc-6 only, not 7 yet 2017-05-31 14:44:14 -06:00
Jason Turner
ab90c61710 Add gcc6/7 to travis 2017-05-31 14:36:09 -06:00
Jason Turner
bdd0a12bb7 ChaiScript can only support static in non-threading mode 2017-05-31 14:18:30 -06:00
Jason Turner
3b48983bc2 Revert "Add workaround for chaiscript used as static"
This reverts commit a281d9571e00788784a10bdae054f92cb3e3fb1a.
2017-05-31 13:54:45 -06:00
Jason Turner
bd736eddec Deprecate GLOBAL #247 2017-05-30 11:33:12 -06:00
Jason Turner
3b1e9011e7 Merge branch 'develop' of github.com:ChaiScript/ChaiScript into develop 2017-05-30 09:20:26 -06:00
Jason Turner
9f8b57c145 Enable ChaiScript compilation for C++17
Closes #348

This works by taking into account the fact that `noexcept` is now part
of the type system in C++17. However, this would conflict with pre-C++17
compilers, so I have added a feature macro around it
2017-05-30 09:16:20 -06:00
Jason Turner
a999ea3692 Fix handling of const return types #430 2017-05-30 08:38:47 -06:00
Jason Turner
5c9b16bdce Fix handling of const return types #430 2017-05-30 08:38:15 -06:00
Jason Turner
252ea8072d Add failing test for const return type #340 2017-05-30 08:29:43 -06:00
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
njlr
bd4a458c31 * Added Buck build 2017-03-08 19:47:07 +00: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
93bc6109e7 Merge branch 'develop' into typed_function_ordering 2016-12-05 19:19:41 -07:00
Jason Turner
4119e6e7d8 Merge branch 'develop' into typed_function_ordering 2016-10-26 14:33:33 -06:00
Stephen Berry
08abf41dfb Another cheatsheet.md namespace update 2016-10-18 09:37:56 -05:00
Stephen Berry
9f1ba21c5e Cleaning up namespace documentation 2016-10-18 09:34:55 -05:00
Stephen Berry
96d2eddce1 Fixing cheatsheet.md namespace documentation 2016-10-18 09:29:33 -05:00
Stephen Berry
c45be80bf5 Added namespace documentation to the cheatsheet.md 2016-10-18 09:26:47 -05:00
Stephen Berry
d61e322c1d Added unit tests for namespaces.
These demonstrate the global scope of namespaces, defining functions and variables within namespaces, and namespace nesting by copy or reference.
2016-10-18 08:57:51 -05:00
Stephen Berry
d2c2962eb7 Added braces to better distinguish case statements.
Added more comments to namespace handling functions.
Added mutex protection to import.
2016-10-17 08:26:26 -05:00
Stephen Berry
a01687d7ad Added basic namespace handling. The new code is wrapped in NAMESPACE HANDLING comments.
C++:
register_namespace(): registers a namespace with an instance of ChaiScript (supports delayed namespace generation)
import(): imports a namespace as a global Dynamic_Object

ChaiScript:
import(): imports a namespace
namespace(): generates and registers a new namespace
2016-10-12 09:42:57 -05:00
Jason Turner
7d11b7c5f1 Merge branch 'develop' into typed_function_ordering 2016-04-20 06:41:37 -06:00
Jason Turner
82a69ca043 Merge branch 'develop' into typed_function_ordering 2016-03-15 12:46:47 -06:00
Jason Turner
dfb2394b0b Merge branch 'update_travis_toolchain' into typed_function_ordering 2016-03-11 15:00:28 -07:00
Jason Turner
c07f413694 Merge branch 'develop' into typed_function_ordering 2016-03-04 13:33:29 -07:00
Jason Turner
172ab7b8e4 Merge branch 'develop' into typed_function_ordering 2016-02-18 08:57:55 -07:00
Jason Turner
fe8ddd1869 Merge branch 'develop' into typed_function_ordering 2016-01-20 18:32:16 -07:00
Jason Turner
5cb6f6a1a2 Merge branch 'develop' into typed_function_ordering 2016-01-20 18:28:28 -07:00
Jason Turner
95256417ac Merge branch 'add_performance_tests' of github.com:ChaiScript/ChaiScript into typed_function_ordering 2015-10-25 15:00:08 -06:00
Jason Turner
2d2251c1da Merge branch 'develop' of github.com:ChaiScript/ChaiScript into typed_function_ordering 2015-08-26 18:58:34 -06:00
Jason Turner
0adacc0b5e Merge branch 'develop' of github.com:ChaiScript/ChaiScript into typed_function_ordering 2015-08-26 18:47:43 -06:00
Jason Turner
818fd0b823 Add function ordering test 2015-08-26 18:47:32 -06:00
Jason Turner
bd9af5eff4 Order typed functions over untyped
specifically the chaiscript defined ones
2015-08-14 21:58:54 -06:00
285 changed files with 29710 additions and 23048 deletions

33
.clang-format Normal file
View File

@ -0,0 +1,33 @@
# clang-format: 11
AccessModifierOffset: -2
AlignAfterOpenBracket: Align
AlignConsecutiveBitFields: false
AllowShortBlocksOnASingleLine: false
AllowShortFunctionsOnASingleLine: Inline
AllowShortLambdasOnASingleLine: All
AlwaysBreakTemplateDeclarations: true
BasedOnStyle: WebKit
BinPackArguments: true
BinPackParameters: true
BreakBeforeBraces: Attach
ColumnLimit: 0
Cpp11BracedListStyle: true
FixNamespaceComments: true
IncludeBlocks: Preserve
IndentCaseLabels: true
IndentPPDirectives: None
IndentWidth: 2
KeepEmptyLinesAtTheStartOfBlocks: false
NamespaceIndentation: All
PenaltyBreakBeforeFirstCallParameter: 200
PenaltyBreakComment: 5
PenaltyBreakFirstLessLess: 50
PenaltyExcessCharacter: 4
PointerAlignment: Right
SortIncludes: true
SpaceAfterTemplateKeyword: false
SpaceBeforeCpp11BracedList: false
SpaceInEmptyBlock: false
Standard: Latest
TabWidth: 2
UseTab: Never

6
.gitignore vendored Normal file
View File

@ -0,0 +1,6 @@
/buck-out/
/.buckd/
/buckaroo/
.buckconfig.local
BUCKAROO_DEPS
/build

View File

@ -5,9 +5,12 @@ addons:
apt:
sources:
- ubuntu-toolchain-r-test
- llvm-toolchain-trusty-5.0
- sourceline: 'deb http://apt.llvm.org/trusty/ llvm-toolchain-trusty-5.0 main'
key_url: 'https://apt.llvm.org/llvm-snapshot.gpg.key'
packages:
- g++-4.9
- g++-5
- g++-7
- g++-8
coverity_scan:
project:
name: "ChaiScript/ChaiScript"
@ -21,16 +24,28 @@ matrix:
include:
- os: linux
sudo: false
env: GCC_VER="4.9"
env: GCC_VER="7"
compiler: gcc
# - os: linux
#sudo: false
#env: GCC_VER="6" 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="7" CPPCHECK=1 CMAKE_OPTIONS="-D RUN_FUZZY_TESTS:BOOL=TRUE"
compiler: gcc
- os: linux
sudo: false
env: GCC_VER="5"
env: GCC_VER="8" 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: xcode10
# env: CLANG_VER="5.0"
#- os: osx
# compiler: clang
# osx_image: xcode10
# env: CLANG_VER="5.0" CMAKE_OPTIONS="-D DYNLOAD_ENABLED:BOOL=FALSE -D MULTITHREAD_SUPPORT_ENABLED:BOOL=FALSE -D USE_STD_MAKE_SHARED:BOOL=TRUE" BUILD_ONLY=1
env:
global:
@ -40,14 +55,14 @@ env:
before_install:
- if [ "${GCC_VER}" != "" ]; then export CXX="g++-$GCC_VER" CC="gcc-$GCC_VER" GCOV="gcov-$GCC_VER" ; fi
- if [ "${GCC_VER}" == "5" ]; then export CPPCHECK=1 COVERAGE=1 FUZZY_CMD="-D RUN_FUZZY_TESTS:BOOL=TRUE" ; fi
#- if [ "${CLANG_VER}" != "" ]; then export CXX="clang++-$CLANG_VER"; fi
- pip install --user cpp-coveralls
script:
- cmake -D ENABLE_COVERAGE:BOOL=TRUE -D CMAKE_BUILD_TYPE:STRING=Debug $FUZZY_CMD .
- cmake -D ENABLE_COVERAGE:BOOL=TRUE -D CMAKE_BUILD_TYPE:STRING=Debug $CMAKE_OPTIONS .
- cmake --build . -- -j2
- ctest
- if [ ${COVERAGE} = 1 ]; then bash <(curl -s https://raw.githubusercontent.com/codecov/codecov-bash/master/codecov) -x $GCOV -a "-s `pwd`" ; fi
- 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

11
BUCK Normal file
View File

@ -0,0 +1,11 @@
prebuilt_cxx_library(
name = 'chaiscript',
header_only = True,
header_namespace = 'chaiscript',
exported_headers = subdir_glob([
('include/chaiscript', '**/*.hpp'),
]),
visibility = [
'PUBLIC',
],
)

View File

@ -1,19 +1,16 @@
cmake_minimum_required(VERSION 2.8)
cmake_minimum_required(VERSION 3.12)
cmake_policy(SET CMP0054 NEW)
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
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# required since cmake 3.4 at least for libc++
set(CMAKE_ENABLE_EXPORTS ON)
project(chaiscript)
option(MULTITHREAD_SUPPORT_ENABLED "Multithreaded Support Enabled" TRUE)
option(DYNLOAD_ENABLED "Dynamic Loading Support Enabled" TRUE)
option(BUILD_MODULES "Build Extra Modules (stl)" TRUE)
@ -48,12 +45,14 @@ if(CMAKE_COMPILER_IS_GNUCC OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
if(ENABLE_ADDRESS_SANITIZER)
add_definitions(-fsanitize=address -g)
set(LINKER_FLAGS "${LINKER_FLAGS} -fsanitize=address")
option(BUILD_LIBFUZZ_TESTER "Build libfuzzer tool" FALSE)
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")
add_definitions(-fsanitize=memory -fsanitize-memory-track-origins -g)
set(LINKER_FLAGS "${LINKER_FLAGS} -fsanitize=memory -fsanitize-memory-track-origins ")
endif()
option(ENABLE_UNDEFINED_SANITIZER "Enable undefined behavior sanitizer testing in gcc/clang" FALSE)
@ -63,27 +62,26 @@ if(CMAKE_COMPILER_IS_GNUCC OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
endif()
option(ENABLE_LTO "Enable Link Time Optimization" FALSE)
if (ENABLE_LTO)
add_definitions(-flto)
set(LINKER_FLAGS "${LINKER_FLAGS} -flto")
if(ENABLE_LTO)
check_ipo_supported()
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE)
endif()
option(GPROF_OUTPUT "Generate profile data" FALSE)
if (GPROF_OUTPUT)
if(GPROF_OUTPUT)
add_definitions(-pg)
set(LINKER_FLAGS "${LINKER_FLAGS} -pg")
endif()
option(PROFILE_GENERATE "Generate profile data" FALSE)
if (PROFILE_GENERATE)
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)
if(PROFILE_USE)
add_definitions(-fprofile-use)
set(LINKER_FLAGS "${LINKER_FLAGS} -fprofile-use")
endif()
@ -101,7 +99,7 @@ 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 6)
set(CPACK_PACKAGE_VERSION_MAJOR 7)
set(CPACK_PACKAGE_VERSION_MINOR 0)
set(CPACK_PACKAGE_VERSION_PATCH 0)
@ -122,12 +120,13 @@ configure_file(Doxyfile.in ${CMAKE_BINARY_DIR}/Doxyfile)
include(CTest)
include(CPack)
include(cmake/Catch.cmake)
if(NOT MINGW)
find_library(READLINE_LIBRARY NAMES readline PATH /usr/lib /usr/local/lib /opt/local/lib)
endif()
if (UNIX AND NOT APPLE)
if(UNIX AND NOT APPLE)
find_program(VALGRIND NAMES valgrind PATH /usr/bin /usr/local/bin)
endif()
@ -145,22 +144,10 @@ else()
set(READLINE_FLAG)
endif()
if(CMAKE_COMPILER_IS_GNUCC)
execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpversion OUTPUT_VARIABLE GCC_VERSION)
if(GCC_VERSION VERSION_LESS 4.9)
set(CPP11_FLAG "-std=c++1y")
else()
set(CPP11_FLAG "-std=c++14")
endif()
else()
set(CPP11_FLAG "-std=c++14")
endif()
if(MSVC)
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")
if(MSVC_VERSION STREQUAL "1800")
# VS2013 doesn't have magic statics
add_definitions(/w44640)
else()
@ -168,7 +155,7 @@ if(MSVC)
add_definitions(/w34062)
endif()
add_definitions(/bigobj)
add_definitions(/bigobj /permissive- /utf-8)
# Note on MSVC compiler flags.
# The code base selective disables warnings as necessary when the compiler is complaining too much
# about something that is perfectly valid, or there is simply no technical way around it
@ -178,10 +165,10 @@ if(MSVC)
# how to workaround or fix the error. So I'm disabling it globally.
add_definitions(/wd4503)
else()
add_definitions(-Wall -Wextra -Wconversion -Wshadow -Wnon-virtual-dtor -Wold-style-cast -Wcast-align -Wcast-qual -Wunused -Woverloaded-virtual -pedantic ${CPP11_FLAG})
add_definitions(-Wall -Wextra -Wconversion -Wshadow -Wnon-virtual-dtor -Wold-style-cast -Wcast-align -Wcast-qual -Wunused -Woverloaded-virtual -Wno-noexcept-type -Wpedantic -Werror=return-type)
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)
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "AppleClang")
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 -Wno-unused-template -Wno-undef -Wno-double-promotion)
else()
add_definitions(-Wnoexcept)
endif()
@ -192,16 +179,12 @@ else()
endif()
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
option(USE_LIBCXX "Use clang's libcxx" TRUE)
option(USE_LIBCXX "Use clang's libcxx" FALSE)
if(USE_LIBCXX)
add_definitions(-stdlib=libc++)
set(LINKER_FLAGS "${LINKER_FLAGS} ${CPP11_FLAG} -stdlib=libc++")
else()
set(LINKER_FLAGS "${LINKER_FLAGS} ${CPP11_FLAG}")
set(LINKER_FLAGS "${LINKER_FLAGS} -stdlib=libc++")
endif()
elseif(CMAKE_COMPILER_IS_GNUCC)
set(LINKER_FLAGS "${LINKER_FLAGS} ${CPP11_FLAG}")
endif()
# limitations in MinGW require us to make an optimized build
@ -221,9 +204,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)
@ -260,9 +249,12 @@ set(CHAISCRIPT_LIBS stdlib parser)
add_executable(chai src/main.cpp ${Chai_INCLUDES})
target_link_libraries(chai ${LIBS} ${CHAISCRIPT_LIBS})
add_library(chaiscript INTERFACE)
target_include_directories(chaiscript INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/include)
if(BUILD_SAMPLES)
add_executable(example samples/example.cpp)
target_link_libraries(example ${LIBS})
add_executable(sanity_checks src/sanity_checks.cpp)
target_link_libraries(sanity_checks ${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)
@ -286,6 +278,7 @@ if(BUILD_MODULES)
set(MODULES stl_extra)
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)
@ -293,37 +286,22 @@ file(GLOB PERFORMANCE_TESTS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/performance_tes
list(SORT PERFORMANCE_TESTS)
if (RUN_FUZZY_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
COMMAND ${CMAKE_COMMAND} -E tar xjf ${CMAKE_CURRENT_SOURCE_DIR}/unittests/fuzzy_tests-2017-07-20.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_TESTS RELATIVE ${CMAKE_BINARY_DIR}/unittests/ ${CMAKE_BINARY_DIR}/unittests/MINIMIZED/*)
list(SORT FUZZY_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})
foreach(filename ${FUZZY_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})
add_test(fuzz.${filename} chai "-e" "--exception" "--any-exception" ${CMAKE_CURRENT_SOURCE_DIR}/unittests/fuzz_unit_test.inc ${CMAKE_BINARY_DIR}/unittests/${filename})
endforeach()
set_property(TEST ${FUZZY_EXCEPTION_TESTS}
@ -337,37 +315,6 @@ 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) }")
@ -399,7 +346,7 @@ if(BUILD_TESTING)
list(APPEND TESTS unit.${filename})
endforeach()
if (RUN_PERFORMANCE_TESTS)
if(RUN_PERFORMANCE_TESTS)
foreach(filename ${PERFORMANCE_TESTS})
message(STATUS "Adding performance test ${filename}")
@ -425,8 +372,11 @@ if(BUILD_TESTING)
if(NOT UNIT_TEST_LIGHT)
add_executable(compiled_tests unittests/compiled_tests.cpp)
target_link_libraries(compiled_tests ${LIBS} ${CHAISCRIPT_LIBS})
ADD_CATCH_TESTS(compiled_tests)
catch_discover_tests(compiled_tests TEST_PREFIX "compiled.")
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})
@ -453,10 +403,8 @@ if(BUILD_TESTING)
"CHAI_USE_PATH=${CMAKE_CURRENT_SOURCE_DIR}/unittests/"
"CHAI_MODULE_PATH=${CMAKE_CURRENT_BINARY_DIR}/"
)
endif()
add_executable(multifile_test
unittests/multifile_test_main.cpp
unittests/multifile_test_chai.cpp
@ -465,11 +413,19 @@ if(BUILD_TESTING)
target_link_libraries(multifile_test ${LIBS})
add_test(NAME MultiFile_Test COMMAND multifile_test)
install(TARGETS test_module RUNTIME DESTINATION bin LIBRARY DESTINATION lib/chaiscript)
install(TARGETS test_module RUNTIME DESTINATION bin LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}/chaiscript")
endif()
endif()
install(TARGETS chai chaiscript_stdlib-${CHAI_VERSION} ${MODULES} RUNTIME DESTINATION bin LIBRARY DESTINATION lib/chaiscript)
if(BUILD_LIBFUZZ_TESTER)
add_executable(fuzzer src/libfuzzer_client.cpp src/sha3.cpp)
target_compile_options(fuzzer PRIVATE "-fsanitize=fuzzer,address")
target_link_libraries(fuzzer PRIVATE ${LIBS} "-fsanitize=fuzzer,address")
endif()
install(TARGETS chai chaiscript_stdlib-${CHAI_VERSION} ${MODULES} RUNTIME DESTINATION bin LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}/chaiscript")
install(DIRECTORY include/chaiscript DESTINATION include
PATTERN "*.hpp"
@ -490,8 +446,6 @@ install(DIRECTORY samples DESTINATION share/chaiscript
configure_file(contrib/pkgconfig/chaiscript.pc.in lib/pkgconfig/chaiscript.pc @ONLY)
install(FILES "${chaiscript_BINARY_DIR}/lib/pkgconfig/chaiscript.pc"
DESTINATION lib/pkgconfig)
DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
ENDIF()

View File

@ -1,5 +1,7 @@
Copyright 2009-2016 Jason Turner
Copyright 2009-2012 Jonathan Turner.
BSD-3-Clause License
Copyright 2009-2018 Jason Turner
Copyright 2009-2012 Jonathan Turner.
All Rights Reserved.
Redistribution and use in source and binary forms, with or without

View File

@ -1,15 +1,16 @@
version: 5.8.x.{build}
os: Visual Studio 2015
version: 6.1.x.{build}
image:
- Visual Studio 2019
environment:
matrix:
- {}
- VS_VERSION: "Visual Studio 16"
build_script:
- cmd: >-
mkdir build
cd build
cmake c:\Projects\chaiscript -G "Visual Studio 14"
cmake c:\Projects\chaiscript -G "%VS_VERSION%" -DBUILD_TESTING:BOOL=ON -DBUILD_MODULES:BOOL=ON
cmake --build . --config Debug
test_script:

3
buckaroo.json Normal file
View File

@ -0,0 +1,3 @@
{
"name": "ChaiScript"
}

View File

@ -5,23 +5,24 @@ ChaiScript tries to follow the [Semantic Versioning](http://semver.org/) scheme.
* 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
chaiscript::ChaiScript chai; // initializes ChaiScript, adding the standard ChaiScript types (map, string, ...)
```
Note that ChaiScript cannot be used as a global / static object unless it is being compiled with `CHAISCRIPT_NO_THREADS`.
# Adding Things To The Engine
## Adding a Function / Method / Member
### General
```
```cpp
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");
@ -29,27 +30,27 @@ chai.add(chaiscript::fun(&Class::member_name), "member_name");
### Bound Member Functions
```
```cpp
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
### With Overloads
#### Preferred
```
```cpp
chai.add(chaiscript::fun<ReturnType (ParamType1, ParamType2)>(&function_with_overloads), "function_name");
```
#### Alternative
```cpp
chai.add(chaiscript::fun(static_cast<ReturnType (*)(ParamType1, ParamType2)>(&function_with_overloads)), "function_name");
```
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
This overload technique is also used when exposing base members using derived type
```
```cpp
struct Base
{
int data;
@ -63,18 +64,18 @@ chai.add(chaiscript::fun(static_cast<int(Derived::*)>(&Derived::data)), "data");
### Lambda
```
```cpp
chai.add(
chaiscript::fun<std::string (bool)>(
[](bool type) {
if (type) { return "x"; }
else { return "y"; }
chaiscript::fun<std::function<std::string (bool)>>(
[](bool type) {
if (type) { return "x"; }
else { return "y"; }
}), "function_name");
```
### Constructors
```
```cpp
chai.add(chaiscript::constructor<MyType ()>(), "MyType");
chai.add(chaiscript::constructor<MyType (const MyType &)>(), "MyType");
```
@ -83,13 +84,13 @@ chai.add(chaiscript::constructor<MyType (const MyType &)>(), "MyType");
It's not strictly necessary to add types, but it helps with many things. Cloning, better errors, etc.
```
```cpp
chai.add(chaiscript::user_type<MyClass>(), "MyClass");
```
## Adding Type Conversions
User defined type conversions are possible, defined in either script or in C++.
User-defined type conversions are possible, defined in either script or in C++.
@ -106,27 +107,27 @@ add_type_conversion(type("string"), type("Type_Info"), fun(s) { return type(s);
Invoking a C++ type conversion possible with `static_cast`
```
```cpp
chai.add(chaiscript::type_conversion<T, bool>());
```
Calling a user defined type conversion that takes a lambda
Calling a user-defined type conversion that takes a lambda
```
```cpp
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.
If you want objects to be convertable between base and derived classes, you must tell ChaiScript about the relationship.
```
```cpp
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.
```
```cpp
chai.add(chaiscript::base_class<Base, Derived>());
chai.add(chaiscript::base_class<Derived, MoreDerived>());
chai.add(chaiscript::base_class<Base, MoreDerived>());
@ -154,7 +155,7 @@ This allows you to pass a ChaiScript function to a function requiring `std::vect
```
chai.add(chaiscript::var(somevar), "somevar"); // copied in
chai.add(chaiscript::var(std::ref(somevar), "somevar"); // by reference, shared between C++ and chai
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
@ -163,10 +164,28 @@ chai.add_global(chaiscript::var(somevar), "somevar"); // global non-const, throw
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.
## Adding Namespaces
Namespaces will not be populated until `import` is called.
This saves memory and computing costs if a namespace is not imported into every ChaiScript instance.
```cpp
chai.register_namespace([](chaiscript::Namespace& math) {
math["pi"] = chaiscript::const_var(3.14159);
math["sin"] = chaiscript::var(chaiscript::fun([](const double x) { return sin(x); })); },
"math");
```
Import namespace in ChaiScript
```
import("math")
print(math.pi) // prints 3.14159
```
# Using STL
ChaiScript recognizes many types from STL, but you have to add specific instantiation yourself.
```cpp
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"));
@ -184,7 +203,7 @@ chai.eval(R"_(
## General
```
```cpp
chai.eval("print(\"Hello World\")");
chai.eval(R"(print("Hello World"))");
```
@ -195,13 +214,13 @@ Returns values are of the type `Boxed_Value` which is meant to be opaque to the
### Prefered
```
```cpp
chai.eval<double>("5.3 + 2.1"); // returns 7.4 as a C++ double
```
### Alternative
```
```cpp
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
@ -209,7 +228,7 @@ chaiscript::boxed_cast<double>(v); // free function version, does not know about
### Converting Between Algebraic Types
```
```cpp
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
@ -239,7 +258,7 @@ int main()
## Sharing Values
```
```cpp
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
@ -249,7 +268,7 @@ chai.eval("print(i)"); // prints 3
## Catching Eval Errors
```
```cpp
try {
chai.eval("2.3 + \"String\"");
} catch (const chaiscript::exception::eval_error &e) {
@ -259,7 +278,7 @@ try {
## Catching Errors Thrown From Script
```
```cpp
try {
chai.eval("throw(runtime_error(\"error\"))", chaiscript::exception_specification<int, double, float, const std::string &, const std::exception &>());
} catch (const double e) {
@ -267,26 +286,26 @@ try {
} catch (float) {
} catch (const std::string &) {
} catch (const std::exception &e) {
// This is the one what will be called in the specific throw() above
// This is the one that will be called in the specific throw() above
}
```
## Sharing Functions
```
```cpp
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)>>(`+`);
```cpp
auto p = chai.eval<std::function<int (int, int)>>("`+`");
p(5, 6); // calls chaiscript's '+' function, returning 11
```
```
```cpp
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++
```
@ -326,7 +345,7 @@ while (some_condition()) { /* do something */ }
```
// ranged for
for (x : [1,2,3]) { print(i); }
for (i : [1, 2, 3]) { print(i); }
```
Each of the loop styles can be broken using the `break` statement. For example:
@ -350,13 +369,44 @@ if (expression) { }
if (statement; expression) { }
```
## Built in Types
## Switch Statements
``` chaiscript
var myvalue = 2
switch (myvalue) {
case (1) {
print("My Value is 1");
break;
}
case (2) {
print("My Value is 2");
break;
}
default {
print("My Value is something else.";
}
}
```
## Built-in Types
There are a number of built-in types that are part of ChaiScript.
### Vectors and Maps
```
var v = [1,2,3u,4ll,"16", `+`]; // creates vector of heterogenous values
var m = ["a":1, "b":2]; // map of string:value pairs
// Add a value to the vector by value.
v.push_back(123);
// Add an object to the vector by reference.
v.push_back_ref(m);
```
### Numbers
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
@ -377,7 +427,7 @@ 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.
converted into a `std::function` object.
### General
@ -476,6 +526,20 @@ o.f = fun(y) { print(this.x + y); }
o.f(10); // prints 13
```
## Namespaces
Namespaces in ChaiScript are Dynamic Objects with global scope
```
namespace("math") // create a new namespace
math.square = fun(x) { x * x } // add a function to the "math" namespace
math.sum_squares = fun(x, y) { math.square(x) + math.square(y) }
print(math.square(4)) // prints 16
print(math.sum_squares(2, 5)) // prints 29
```
### Option Explicit
If you want to disable dynamic parameter definitions, you can `set_explicit`.
@ -513,27 +577,10 @@ If both a 2 parameter and a 3 parameter signature match, the 3 parameter functio
* `__LINE__` Current file line number
* `__FILE__` Full path of current file
* `__CLASS__` Name of current class
* `__FUNC__` Mame of current function
* `__FUNC__` Name 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
};
```
# Built-in Functions
## Evaluation
@ -550,3 +597,6 @@ Both `use` and `eval_file` search the 'usepaths' passed to the ChaiScript constr
* `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
## Extras
ChaiScript itself does not provide a link to the math functions defined in `<cmath>`. You can either add them yourself, or use the [ChaiScript_Extras](https://github.com/ChaiScript/ChaiScript_Extras) helper library. (Which also provides some additional string functions.)

175
cmake/Catch.cmake Normal file
View File

@ -0,0 +1,175 @@
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
# file Copyright.txt or https://cmake.org/licensing for details.
#[=======================================================================[.rst:
Catch
-----
This module defines a function to help use the Catch test framework.
The :command:`catch_discover_tests` discovers tests by asking the compiled test
executable to enumerate its tests. This does not require CMake to be re-run
when tests change. However, it may not work in a cross-compiling environment,
and setting test properties is less convenient.
This command is intended to replace use of :command:`add_test` to register
tests, and will create a separate CTest test for each Catch test case. Note
that this is in some cases less efficient, as common set-up and tear-down logic
cannot be shared by multiple test cases executing in the same instance.
However, it provides more fine-grained pass/fail information to CTest, which is
usually considered as more beneficial. By default, the CTest test name is the
same as the Catch name; see also ``TEST_PREFIX`` and ``TEST_SUFFIX``.
.. command:: catch_discover_tests
Automatically add tests with CTest by querying the compiled test executable
for available tests::
catch_discover_tests(target
[TEST_SPEC arg1...]
[EXTRA_ARGS arg1...]
[WORKING_DIRECTORY dir]
[TEST_PREFIX prefix]
[TEST_SUFFIX suffix]
[PROPERTIES name1 value1...]
[TEST_LIST var]
)
``catch_discover_tests`` sets up a post-build command on the test executable
that generates the list of tests by parsing the output from running the test
with the ``--list-test-names-only`` argument. This ensures that the full
list of tests is obtained. Since test discovery occurs at build time, it is
not necessary to re-run CMake when the list of tests changes.
However, it requires that :prop_tgt:`CROSSCOMPILING_EMULATOR` is properly set
in order to function in a cross-compiling environment.
Additionally, setting properties on tests is somewhat less convenient, since
the tests are not available at CMake time. Additional test properties may be
assigned to the set of tests as a whole using the ``PROPERTIES`` option. If
more fine-grained test control is needed, custom content may be provided
through an external CTest script using the :prop_dir:`TEST_INCLUDE_FILES`
directory property. The set of discovered tests is made accessible to such a
script via the ``<target>_TESTS`` variable.
The options are:
``target``
Specifies the Catch executable, which must be a known CMake executable
target. CMake will substitute the location of the built executable when
running the test.
``TEST_SPEC arg1...``
Specifies test cases, wildcarded test cases, tags and tag expressions to
pass to the Catch executable with the ``--list-test-names-only`` argument.
``EXTRA_ARGS arg1...``
Any extra arguments to pass on the command line to each test case.
``WORKING_DIRECTORY dir``
Specifies the directory in which to run the discovered test cases. If this
option is not provided, the current binary directory is used.
``TEST_PREFIX prefix``
Specifies a ``prefix`` to be prepended to the name of each discovered test
case. This can be useful when the same test executable is being used in
multiple calls to ``catch_discover_tests()`` but with different
``TEST_SPEC`` or ``EXTRA_ARGS``.
``TEST_SUFFIX suffix``
Similar to ``TEST_PREFIX`` except the ``suffix`` is appended to the name of
every discovered test case. Both ``TEST_PREFIX`` and ``TEST_SUFFIX`` may
be specified.
``PROPERTIES name1 value1...``
Specifies additional properties to be set on all tests discovered by this
invocation of ``catch_discover_tests``.
``TEST_LIST var``
Make the list of tests available in the variable ``var``, rather than the
default ``<target>_TESTS``. This can be useful when the same test
executable is being used in multiple calls to ``catch_discover_tests()``.
Note that this variable is only available in CTest.
#]=======================================================================]
#------------------------------------------------------------------------------
function(catch_discover_tests TARGET)
cmake_parse_arguments(
""
""
"TEST_PREFIX;TEST_SUFFIX;WORKING_DIRECTORY;TEST_LIST"
"TEST_SPEC;EXTRA_ARGS;PROPERTIES"
${ARGN}
)
if(NOT _WORKING_DIRECTORY)
set(_WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")
endif()
if(NOT _TEST_LIST)
set(_TEST_LIST ${TARGET}_TESTS)
endif()
## Generate a unique name based on the extra arguments
string(SHA1 args_hash "${_TEST_SPEC} ${_EXTRA_ARGS}")
string(SUBSTRING ${args_hash} 0 7 args_hash)
# Define rule to generate test list for aforementioned test executable
set(ctest_include_file "${CMAKE_CURRENT_BINARY_DIR}/${TARGET}_include-${args_hash}.cmake")
set(ctest_tests_file "${CMAKE_CURRENT_BINARY_DIR}/${TARGET}_tests-${args_hash}.cmake")
get_property(crosscompiling_emulator
TARGET ${TARGET}
PROPERTY CROSSCOMPILING_EMULATOR
)
add_custom_command(
TARGET ${TARGET} POST_BUILD
BYPRODUCTS "${ctest_tests_file}"
COMMAND "${CMAKE_COMMAND}"
-D "TEST_TARGET=${TARGET}"
-D "TEST_EXECUTABLE=$<TARGET_FILE:${TARGET}>"
-D "TEST_EXECUTOR=${crosscompiling_emulator}"
-D "TEST_WORKING_DIR=${_WORKING_DIRECTORY}"
-D "TEST_SPEC=${_TEST_SPEC}"
-D "TEST_EXTRA_ARGS=${_EXTRA_ARGS}"
-D "TEST_PROPERTIES=${_PROPERTIES}"
-D "TEST_PREFIX=${_TEST_PREFIX}"
-D "TEST_SUFFIX=${_TEST_SUFFIX}"
-D "TEST_LIST=${_TEST_LIST}"
-D "CTEST_FILE=${ctest_tests_file}"
-P "${_CATCH_DISCOVER_TESTS_SCRIPT}"
VERBATIM
)
file(WRITE "${ctest_include_file}"
"if(EXISTS \"${ctest_tests_file}\")\n"
" include(\"${ctest_tests_file}\")\n"
"else()\n"
" add_test(${TARGET}_NOT_BUILT-${args_hash} ${TARGET}_NOT_BUILT-${args_hash})\n"
"endif()\n"
)
if(NOT ${CMAKE_VERSION} VERSION_LESS "3.10.0")
# Add discovered tests to directory TEST_INCLUDE_FILES
set_property(DIRECTORY
APPEND PROPERTY TEST_INCLUDE_FILES "${ctest_include_file}"
)
else()
# Add discovered tests as directory TEST_INCLUDE_FILE if possible
get_property(test_include_file_set DIRECTORY PROPERTY TEST_INCLUDE_FILE SET)
if (NOT ${test_include_file_set})
set_property(DIRECTORY
PROPERTY TEST_INCLUDE_FILE "${ctest_include_file}"
)
else()
message(FATAL_ERROR
"Cannot set more than one TEST_INCLUDE_FILE"
)
endif()
endif()
endfunction()
###############################################################################
set(_CATCH_DISCOVER_TESTS_SCRIPT
${CMAKE_CURRENT_LIST_DIR}/CatchAddTests.cmake
)

76
cmake/CatchAddTests.cmake Normal file
View File

@ -0,0 +1,76 @@
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
# file Copyright.txt or https://cmake.org/licensing for details.
set(prefix "${TEST_PREFIX}")
set(suffix "${TEST_SUFFIX}")
set(spec ${TEST_SPEC})
set(extra_args ${TEST_EXTRA_ARGS})
set(properties ${TEST_PROPERTIES})
set(script)
set(suite)
set(tests)
function(add_command NAME)
set(_args "")
foreach(_arg ${ARGN})
if(_arg MATCHES "[^-./:a-zA-Z0-9_]")
set(_args "${_args} [==[${_arg}]==]") # form a bracket_argument
else()
set(_args "${_args} ${_arg}")
endif()
endforeach()
set(script "${script}${NAME}(${_args})\n" PARENT_SCOPE)
endfunction()
# Run test executable to get list of available tests
if(NOT EXISTS "${TEST_EXECUTABLE}")
message(FATAL_ERROR
"Specified test executable '${TEST_EXECUTABLE}' does not exist"
)
endif()
execute_process(
COMMAND ${TEST_EXECUTOR} "${TEST_EXECUTABLE}" ${spec} --list-test-names-only
OUTPUT_VARIABLE output
RESULT_VARIABLE result
)
# Catch --list-test-names-only reports the number of tests, so 0 is... surprising
if(${result} EQUAL 0)
message(WARNING
"Test executable '${TEST_EXECUTABLE}' contains no tests!\n"
)
elseif(${result} LESS 0)
message(FATAL_ERROR
"Error running test executable '${TEST_EXECUTABLE}':\n"
" Result: ${result}\n"
" Output: ${output}\n"
)
endif()
string(REPLACE "\n" ";" output "${output}")
# Parse output
foreach(line ${output})
set(test ${line})
# ...and add to script
add_command(add_test
"${prefix}${test}${suffix}"
${TEST_EXECUTOR}
"${TEST_EXECUTABLE}"
${test}
${extra_args}
)
add_command(set_tests_properties
"${prefix}${test}${suffix}"
PROPERTIES
WORKING_DIRECTORY "${TEST_WORKING_DIR}"
${properties}
)
list(APPEND tests "${prefix}${test}${suffix}")
endforeach()
# Create a list of all discovered tests, which users may use to e.g. set
# properties on the tests
add_command(set ${TEST_LIST} ${tests})
# Write CTest script
file(WRITE "${CTEST_FILE}" "${script}")

View File

@ -0,0 +1,185 @@
#==================================================================================================#
# supported macros #
# - TEST_CASE, #
# - SCENARIO, #
# - TEST_CASE_METHOD, #
# - CATCH_TEST_CASE, #
# - CATCH_SCENARIO, #
# - CATCH_TEST_CASE_METHOD. #
# #
# Usage #
# 1. make sure this module is in the path or add this otherwise: #
# set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake.modules/") #
# 2. make sure that you've enabled testing option for the project by the call: #
# enable_testing() #
# 3. add the lines to the script for testing target (sample CMakeLists.txt): #
# project(testing_target) #
# set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake.modules/") #
# enable_testing() #
# #
# find_path(CATCH_INCLUDE_DIR "catch.hpp") #
# include_directories(${INCLUDE_DIRECTORIES} ${CATCH_INCLUDE_DIR}) #
# #
# file(GLOB SOURCE_FILES "*.cpp") #
# add_executable(${PROJECT_NAME} ${SOURCE_FILES}) #
# #
# include(ParseAndAddCatchTests) #
# ParseAndAddCatchTests(${PROJECT_NAME}) #
# #
# The following variables affect the behavior of the script: #
# #
# PARSE_CATCH_TESTS_VERBOSE (Default OFF) #
# -- enables debug messages #
# PARSE_CATCH_TESTS_NO_HIDDEN_TESTS (Default OFF) #
# -- excludes tests marked with [!hide], [.] or [.foo] tags #
# PARSE_CATCH_TESTS_ADD_FIXTURE_IN_TEST_NAME (Default ON) #
# -- adds fixture class name to the test name #
# PARSE_CATCH_TESTS_ADD_TARGET_IN_TEST_NAME (Default ON) #
# -- adds cmake target name to the test name #
# PARSE_CATCH_TESTS_ADD_TO_CONFIGURE_DEPENDS (Default OFF) #
# -- causes CMake to rerun when file with tests changes so that new tests will be discovered #
# #
#==================================================================================================#
cmake_minimum_required(VERSION 2.8.8)
option(PARSE_CATCH_TESTS_VERBOSE "Print Catch to CTest parser debug messages" OFF)
option(PARSE_CATCH_TESTS_NO_HIDDEN_TESTS "Exclude tests with [!hide], [.] or [.foo] tags" OFF)
option(PARSE_CATCH_TESTS_ADD_FIXTURE_IN_TEST_NAME "Add fixture class name to the test name" ON)
option(PARSE_CATCH_TESTS_ADD_TARGET_IN_TEST_NAME "Add target name to the test name" ON)
option(PARSE_CATCH_TESTS_ADD_TO_CONFIGURE_DEPENDS "Add test file to CMAKE_CONFIGURE_DEPENDS property" OFF)
function(PrintDebugMessage)
if(PARSE_CATCH_TESTS_VERBOSE)
message(STATUS "ParseAndAddCatchTests: ${ARGV}")
endif()
endfunction()
# This removes the contents between
# - block comments (i.e. /* ... */)
# - full line comments (i.e. // ... )
# contents have been read into '${CppCode}'.
# !keep partial line comments
function(RemoveComments CppCode)
string(ASCII 2 CMakeBeginBlockComment)
string(ASCII 3 CMakeEndBlockComment)
string(REGEX REPLACE "/\\*" "${CMakeBeginBlockComment}" ${CppCode} "${${CppCode}}")
string(REGEX REPLACE "\\*/" "${CMakeEndBlockComment}" ${CppCode} "${${CppCode}}")
string(REGEX REPLACE "${CMakeBeginBlockComment}[^${CMakeEndBlockComment}]*${CMakeEndBlockComment}" "" ${CppCode} "${${CppCode}}")
string(REGEX REPLACE "\n[ \t]*//+[^\n]+" "\n" ${CppCode} "${${CppCode}}")
set(${CppCode} "${${CppCode}}" PARENT_SCOPE)
endfunction()
# Worker function
function(ParseFile SourceFile TestTarget)
# According to CMake docs EXISTS behavior is well-defined only for full paths.
get_filename_component(SourceFile ${SourceFile} ABSOLUTE)
if(NOT EXISTS ${SourceFile})
message(WARNING "Cannot find source file: ${SourceFile}")
return()
endif()
PrintDebugMessage("parsing ${SourceFile}")
file(STRINGS ${SourceFile} Contents NEWLINE_CONSUME)
# Remove block and fullline comments
RemoveComments(Contents)
# Find definition of test names
string(REGEX MATCHALL "[ \t]*(CATCH_)?(TEST_CASE_METHOD|SCENARIO|TEST_CASE)[ \t]*\\([^\)]+\\)+[ \t\n]*{+[ \t]*(//[^\n]*[Tt][Ii][Mm][Ee][Oo][Uu][Tt][ \t]*[0-9]+)*" Tests "${Contents}")
if(PARSE_CATCH_TESTS_ADD_TO_CONFIGURE_DEPENDS AND Tests)
PrintDebugMessage("Adding ${SourceFile} to CMAKE_CONFIGURE_DEPENDS property")
set_property(
DIRECTORY
APPEND
PROPERTY CMAKE_CONFIGURE_DEPENDS ${SourceFile}
)
endif()
foreach(TestName ${Tests})
# Strip newlines
string(REGEX REPLACE "\\\\\n|\n" "" TestName "${TestName}")
# Get test type and fixture if applicable
string(REGEX MATCH "(CATCH_)?(TEST_CASE_METHOD|SCENARIO|TEST_CASE)[ \t]*\\([^,^\"]*" TestTypeAndFixture "${TestName}")
string(REGEX MATCH "(CATCH_)?(TEST_CASE_METHOD|SCENARIO|TEST_CASE)" TestType "${TestTypeAndFixture}")
string(REPLACE "${TestType}(" "" TestFixture "${TestTypeAndFixture}")
# Get string parts of test definition
string(REGEX MATCHALL "\"+([^\\^\"]|\\\\\")+\"+" TestStrings "${TestName}")
# Strip wrapping quotation marks
string(REGEX REPLACE "^\"(.*)\"$" "\\1" TestStrings "${TestStrings}")
string(REPLACE "\";\"" ";" TestStrings "${TestStrings}")
# Validate that a test name and tags have been provided
list(LENGTH TestStrings TestStringsLength)
if(TestStringsLength GREATER 2 OR TestStringsLength LESS 1)
message(FATAL_ERROR "You must provide a valid test name and tags for all tests in ${SourceFile}")
endif()
# Assign name and tags
list(GET TestStrings 0 Name)
if("${TestType}" STREQUAL "SCENARIO")
set(Name "Scenario: ${Name}")
endif()
if(PARSE_CATCH_TESTS_ADD_FIXTURE_IN_TEST_NAME AND TestFixture)
set(CTestName "${TestFixture}:${Name}")
else()
set(CTestName "${Name}")
endif()
if(PARSE_CATCH_TESTS_ADD_TARGET_IN_TEST_NAME)
set(CTestName "${TestTarget}:${CTestName}")
endif()
# add target to labels to enable running all tests added from this target
set(Labels ${TestTarget})
if(TestStringsLength EQUAL 2)
list(GET TestStrings 1 Tags)
string(TOLOWER "${Tags}" Tags)
# remove target from labels if the test is hidden
if("${Tags}" MATCHES ".*\\[!?(hide|\\.)\\].*")
list(REMOVE_ITEM Labels ${TestTarget})
endif()
string(REPLACE "]" ";" Tags "${Tags}")
string(REPLACE "[" "" Tags "${Tags}")
endif()
list(APPEND Labels ${Tags})
list(FIND Labels "!hide" IndexOfHideLabel)
set(HiddenTagFound OFF)
foreach(label ${Labels})
string(REGEX MATCH "^!hide|^\\." result ${label})
if(result)
set(HiddenTagFound ON)
break()
endif(result)
endforeach(label)
if(PARSE_CATCH_TESTS_NO_HIDDEN_TESTS AND ${HiddenTagFound})
PrintDebugMessage("Skipping test \"${CTestName}\" as it has [!hide], [.] or [.foo] label")
else()
PrintDebugMessage("Adding test \"${CTestName}\"")
if(Labels)
PrintDebugMessage("Setting labels to ${Labels}")
endif()
# Add the test and set its properties
add_test(NAME "\"${CTestName}\"" COMMAND ${TestTarget} ${Name} ${AdditionalCatchParameters})
set_tests_properties("\"${CTestName}\"" PROPERTIES FAIL_REGULAR_EXPRESSION "No tests ran"
LABELS "${Labels}")
endif()
endforeach()
endfunction()
# entry point
function(ParseAndAddCatchTests TestTarget)
PrintDebugMessage("Started parsing ${TestTarget}")
get_target_property(SourceFiles ${TestTarget} SOURCES)
PrintDebugMessage("Found the following sources: ${SourceFiles}")
foreach(SourceFile ${SourceFiles})
ParseFile(${SourceFile} ${TestTarget})
endforeach()
PrintDebugMessage("Finished parsing ${TestTarget}")
endfunction()

1
contrib/vim Normal file
View File

@ -0,0 +1 @@
vim support can be found at https://github.com/ChaiScript/vim-chaiscript

View File

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

View File

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

View File

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

View File

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

View File

@ -1,31 +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-2017, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2018, 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_
/// @mainpage
/// [ChaiScript](http://www.chaiscript.com") is a scripting language designed specifically for integration with C++. It provides
/// seamless integration with C++ on all levels, including shared_ptr objects, functors and exceptions.
///
/// The parts of the ChaiScript API that the average user will be concerned with are contained in the
///
/// The parts of the ChaiScript API that the average user will be concerned with are contained in the
/// chaiscript namespace and the chaiscript::ChaiScript class.
///
/// The end user parts of the API are extremely simple both in size and ease of use.
///
/// Currently, all source control and project management aspects of ChaiScript occur on [github](http://www.github.com/ChaiScript/ChaiScript").
/// Currently, all source control and project management aspects of ChaiScript occur on
/// [github](http://www.github.com/ChaiScript/ChaiScript").
///
/// ------------------------------------------------------------
///
///
/// @sa chaiscript
/// @sa chaiscript::ChaiScript
/// @sa ChaiScript_Language for Built in Functions
@ -51,16 +49,16 @@
/// - @ref functionobjects
/// - @ref threading
/// - @ref exceptions
///
///
///
///
/// @subsection basics Basics
///
///
/// Basic simple example:
///
/// ~~~~~~~{.cpp}
/// //main.cpp
/// #include <chaiscript/chaiscript.hpp>
///
///
/// double function(int i, double j)
/// {
/// return i * j;
@ -72,7 +70,7 @@
/// chai.add(chaiscript::fun(&function), "function");
///
/// double d = chai.eval<double>("function(3, 4.75);");
/// }
/// }
/// ~~~~~~~
///
/// ------------------------------------------------------
@ -81,14 +79,14 @@
///
/// ChaiScript is a header only library with only one dependency: The
/// operating system provided dynamic library loader, which has to be specified on some platforms.
///
///
/// @subsubsection compilinggcc Compiling with GCC
///
///
/// To compile the above application on a Unix like operating system (MacOS, Linux) with GCC you need to link
/// the dynamic loader. For example:
///
/// ~~~~~~~~
/// gcc main.cpp -I/path/to/chaiscript/headers -ldl
/// gcc main.cpp -I/path/to/chaiscript/headers -ldl
/// ~~~~~~~~
///
/// Alternatively, you may compile without threading support.
@ -111,11 +109,11 @@
/// chaiscript::ChaiScript chai;
/// chai("print(@"hello world@")");
/// ~~~~~~~~
///
///
/// @sa chaiscript::ChaiScript::operator()(const std::string &)
///
/// @subsubsection evalmethod Method 'eval'
///
///
/// The eval method is somewhat more verbose and can be used to get type safely return values
/// from the script.
///
@ -129,15 +127,15 @@
/// @sa chaiscript::ChaiScript::eval
///
/// @subsubsection evalfilemethod Method 'eval_file'
///
///
/// The 'eval_file' method loads a file from disk and executes the script in it
///
///
/// ~~~~~~~~{.cpp}
/// chaiscript::ChaiScript chai;
/// chai.eval_file("myfile.chai");
/// std::string result = chai.eval_file<std::string>("myfile.chai") // extract the last value returned from the file
/// ~~~~~~~~
///
///
/// @sa chaiscript::ChaiScript::eval_file
///
/// --------------------------------------------------
@ -149,10 +147,10 @@
/// @subsubsection adding_objects Adding Objects
///
/// Named objects can be created with the chaiscript::var function. Note: adding a object
/// adds it to the current thread scope, not to a global scope. If you have multiple
/// adds it to the current thread scope, not to a global scope. If you have multiple
/// threads that need to access the same variables you will need to add them
/// separately for each thread, from the thread itself.
///
///
/// ~~~~~~~~~{.cpp}
/// using namespace chaiscript;
/// ChaiScript chai;
@ -167,23 +165,23 @@
/// chai.add(const_var(i), "i");
/// chai("i = 5"); // exception throw, cannot assign const var
/// ~~~~~~~~~
///
///
/// Named variables can only be accessed from the context they are created in.
/// If you want a global variable, it must be const, and created with the
/// If you want a global variable, it must be const, and created with the
/// chaiscript::ChaiScript::add_global_const function.
///
/// ~~~~~~~~~{.cpp}
/// chai.add_global_const(const_var(i), "i");
/// chai("def somefun() { print(i); }; somefun();");
/// ~~~~~~~~~
///
///
/// @subsubsection adding_functions Adding Functions
///
///
/// Functions, methods and members are all added using the same function: chaiscript::fun.
///
/// ~~~~~~~~~{.cpp}
/// using namespace chaiscript;
///
///
/// class MyClass {
/// public:
/// int memberdata;
@ -193,7 +191,7 @@
/// void overloadedmethod();
/// void overloadedmethod(const std::string &);
/// };
///
///
/// ChaiScript chai;
/// chai.add(fun(&MyClass::memberdata), "memberdata");
/// chai.add(fun(&MyClass::method), "method");
@ -208,7 +206,7 @@
/// ~~~~~~~~~
///
/// There are also shortcuts built into chaiscript::fun for binding up to the first two parameters of the function.
///
///
/// ~~~~~~~~~{.cpp}
/// MyClass obj;
/// chai.add(fun(&MyClass::method, &obj), "method");
@ -220,7 +218,7 @@
/// @subsubsection addingtypeinfo Adding Type Info
///
/// ChaiScript will automatically support any type implicitly provided to it in the form
/// of objects and function parameters / return types. However, it can be nice to let ChaiScript
/// of objects and function parameters / return types. However, it can be nice to let ChaiScript
/// know more details about the types you are giving it. For instance, the "clone" functionality
/// cannot work unless there is a copy constructor registered and the name of the type is known
/// (so that ChaiScript can look up the copy constructor).
@ -232,23 +230,23 @@
/// ~~~~~~~~
///
/// @subsubsection adding_modules Adding Modules
///
///
/// Modules are holders for collections of ChaiScript registrations.
///
/// ~~~~~~~~{.cpp}
/// ModulePtr module = get_sum_module();
/// chai.add(module);
/// ~~~~~~~~
///
///
/// @sa chaiscript::Module
///
/// -----------------------------------------------------------------------
///
/// @subsection operatoroverloading Operator Overloading
///
///
/// Operators are just like any other function in ChaiScript, to overload an operator, simply register it.
///
/// ~~~~~~~~{.cpp}
///
/// ~~~~~~~~{.cpp}
/// class MyClass {
/// MyClass operator+(const MyClass &) const;
/// };
@ -270,7 +268,7 @@
/// -----------------------------------------------------------------------
///
/// @subsection add_class Class Helper Utility
///
///
/// Much of the work of adding new classes to ChaiScript can be reduced with the help
/// of the add_class helper utility.
///
@ -295,8 +293,8 @@
/// constructor<Test(const Test &)>() },
/// { {fun(&Test::function), "function"},
/// {fun(&Test::function2), "function2"},
/// {fun(&Test::function2), "function3"}
/// {fun(static_cast<std::string Test::*(double)>(&Test::functionOverload)), "functionOverload"}
/// {fun(&Test::function2), "function3"}
/// {fun(static_cast<std::string Test::*(double)>(&Test::functionOverload)), "functionOverload"}
/// {fun(static_cast<std::string Test::*(int)>(&Test::functionOverload)), "functionOverload"} }
/// );
///
@ -305,7 +303,7 @@
/// chai.add(m);
/// }
/// ~~~~~~~~
///
///
/// @sa @ref adding_modules
///
/// -----------------------------------------------------------------------
@ -315,8 +313,8 @@
/// As much as possible, ChaiScript attempts to convert between &, *, const &, const *, std::shared_ptr<T>,
/// std::shared_ptr<const T>, std::reference_wrapper<T>, std::reference_wrapper<const T> and value types automatically.
///
/// If a chaiscript::var object was created in C++ from a pointer, it cannot be converted to a shared_ptr (this would add invalid reference counting).
/// Const may be added, but never removed.
/// If a chaiscript::var object was created in C++ from a pointer, it cannot be converted to a shared_ptr (this would add invalid reference
/// counting). Const may be added, but never removed.
///
/// The take away is that you can pretty much expect function calls to Just Work when you need them to.
///
@ -359,16 +357,16 @@
/// chai("fun8(i)");
/// chai("fun9(i)");
/// chai("fun10(i)");
/// }
/// }
/// ~~~~~~~~
///
/// See the unit test unittests/boxed_cast_test.cpp for a complete breakdown of the automatic casts that
/// See the unit test unittests/boxed_cast_test.cpp for a complete breakdown of the automatic casts that
/// available and tested.
///
///
/// -----------------------------------------------------------------------
///
/// @subsection baseclasses Base Classes
///
///
/// ChaiScript supports handling of passing a derived class object to a function expecting a base class object.
/// For the process to work, the base/derived relationship must be registered with the engine.
///
@ -387,7 +385,7 @@
/// chai("myfunction(d)");
/// }
/// ~~~~~~~~
///
///
/// -----------------------------------------------------------------------
///
///
@ -401,7 +399,7 @@
/// {
/// t_func("bob");
/// }
///
///
/// int main()
/// {
/// chaiscript::ChaiScript chai;
@ -413,16 +411,16 @@
/// f(); // call the ChaiScript function dump_system, from C++
/// }
/// ~~~~~~~~
///
///
/// -----------------------------------------------------------------------
///
///
/// @subsection threading Threading
///
///
/// Thread safety is automatically handled within the ChaiScript system. Objects can be added
/// and scripts executed from multiple threads. For each thread that executes scripts, a new
/// context is created and managed by the engine.
///
///
/// Thread safety can be disabled by defining CHAISCRIPT_NO_THREADS when using the library.
///
/// Disabling thread safety increases performance in many cases.
@ -431,10 +429,10 @@
///
///
/// @subsection exceptions Exception Handling
///
///
/// @subsubsection exceptionsbasics Exception Handling Basics
///
/// Exceptions can be thrown in ChaiScript and caught in C++ or thrown in C++ and caught in
/// Exceptions can be thrown in ChaiScript and caught in C++ or thrown in C++ and caught in
/// ChaiScript.
///
/// ~~~~~~~~{.cpp}
@ -442,14 +440,14 @@
/// {
/// throw std::runtime_error("err");
/// }
///
///
/// int main()
/// {
/// // Throw in C++, catch in ChaiScript
/// chaiscript::ChaiScript chai;
/// chai.add(chaiscript::fun(&throwexception), "throwexception");
/// chai("try { throwexception(); } catch (e) { print(e.what()); }"); // prints "err"
///
///
/// // Throw in ChaiScript, catch in C++
/// try {
/// chai("throw(1)");
@ -459,18 +457,19 @@
/// }
/// }
/// ~~~~~~~~
///
///
/// @subsubsection exceptionsautomatic Exception Handling Automatic Unboxing
///
/// As an alternative to the manual unboxing of exceptions shown above, exception specifications allow the user to tell
/// ChaiScript what possible exceptions are expected from the script being executed.
/// As an alternative to the manual unboxing of exceptions shown above, exception specifications allow the user to tell
/// ChaiScript what possible exceptions are expected from the script being executed.
///
/// Example:
/// ~~~~~~~~{.cpp}
/// chaiscript::ChaiScript chai;
///
/// try {
/// chai.eval("throw(runtime_error(@"error@"))", chaiscript::exception_specification<int, double, float, const std::string &, const std::exception &>());
/// chai.eval("throw(runtime_error(@"error@"))", chaiscript::exception_specification<int, double, float, const std::string &, const
/// std::exception &>());
/// } catch (const double e) {
/// } catch (int) {
/// } catch (float) {
@ -480,11 +479,9 @@
/// }
/// ~~~~~~~~
///
/// @sa chaiscript::Exception_Handler for details on automatic exception unboxing
/// @sa chaiscript::Exception_Handler for details on automatic exception unboxing
/// @sa chaiscript::exception_specification
/// @page LangObjectSystemRef ChaiScript Language Object Model Reference
///
///
@ -495,7 +492,7 @@
/// attr Rectangle::width
/// def Rectangle::Rectangle() { this.height = 10; this.width = 20 }
/// def Rectangle::area() { this.height * this.width }
///
///
/// var rect = Rectangle()
/// rect.height = 30
/// print(rect.area())
@ -521,7 +518,7 @@
/// @page LangInPlaceRef ChaiScript Language In-Place Creation Reference
/// @section inplacevector Vector
///
///
/// ~~~~~~~~~
/// In-place Vector ::= "[" [expression ("," expression)*] "]"
/// ~~~~~~~~~
@ -541,9 +538,9 @@
/// ~~~~~~~~
/// @page LangGettingStarted ChaiScript Language Getting Started
///
///
/// ChaiScript is a simple language that should feel familiar to anyone who knows
/// C++ or ECMAScript (JavaScript).
/// C++ or ECMAScript (JavaScript).
///
/// -----------------------------------------------------------------------
///
@ -575,10 +572,10 @@
/// @section chaiscriptifs Conditionals
///
/// If statements work as expected
///
///
/// ~~~~~~~~
/// var b = true;
///
///
/// if (b) {
/// // do something
/// } else if (c < 10) {
@ -593,9 +590,9 @@
/// -----------------------------------------------------------------------
///
/// @section chaiscriptfunctions Functions
///
///
/// Functions are defined with the def keyword
///
///
/// ~~~~~~~~
/// def myfun(x) { print(x); }
///
@ -612,7 +609,7 @@
/// eval> myfun2(12)
/// 10 or greater
/// ~~~~~~~~
///
///
/// @sa @ref keyworddef
/// @sa @ref keywordattr
/// @sa @ref LangObjectSystemRef
@ -620,7 +617,7 @@
/// -----------------------------------------------------------------------
///
/// @section chaiscriptfunctionobjects Function Objects
///
///
/// Functions are first class types in ChaiScript and can be used as variables.
///
/// ~~~~~~~~
@ -628,8 +625,8 @@
/// eval> p(1);
/// 1
/// ~~~~~~~~
///
/// They can also be passed to functions.
///
/// They can also be passed to functions.
///
/// ~~~~~~~~
/// eval> def callfunc(f, lhs, rhs) { return f(lhs, rhs); }
@ -639,7 +636,7 @@
/// ~~~~~~~~
///
/// Operators can also be treated as functions by using the back tick operator. Building on the above example:
///
///
/// ~~~~~~~~
/// eval> callfunc(`+`, 1, 4);
/// 5
@ -652,7 +649,6 @@
/// @sa @ref LangKeywordRef
/// @sa ChaiScript_Language for Built in Functions
/// @page LangKeywordRef ChaiScript Language Keyword Reference
///
///
@ -660,8 +656,8 @@
///
/// @section keywordattr attr
/// Defines a ChaiScript object attribute
///
/// ~~~~~~~~
///
/// ~~~~~~~~
/// Attribute Definition ::= "attr" class_name "::" attribute_name
/// ~~~~~~~~
///
@ -690,7 +686,7 @@
/// ~~~~~~~~
///
/// @sa @ref keywordfor
/// @sa @ref keywordwhile
/// @sa @ref keywordwhile
///
///
/// -----------------------------------------------------------------------
@ -702,7 +698,7 @@
/// Function Definition ::= "def" identifier "(" [[type] arg ("," [type] arg)*] ")" [":" guard] block
/// Method Definition ::= "def" class_name "::" method_name "(" [[type] arg ("," [type] arg)*] ")" [":" guard] block
/// ~~~~~~~~
///
///
/// identifier: name of function. Required.
/// args: comma-delimited list of parameter names with optional type specifiers. Optional.
/// guards: guarding statement that act as a prerequisite for the function. Optional.
@ -722,7 +718,7 @@
/// -----------------------------------------------------------------------
///
/// @section keywordelse else
/// @sa @ref keywordif
/// @sa @ref keywordif
///
///
/// -----------------------------------------------------------------------
@ -762,7 +758,7 @@
/// Else If Block ::= "else if" "(" condition ")" block
/// Else Block ::= "else" block
/// ~~~~~~~~
///
///
/// _Example_
///
/// ~~~~~~~~
@ -780,8 +776,8 @@
///
/// @section keywordtry try
/// ~~~~~~~~
/// Try Block ::= "try" block
/// ("catch" ["(" [type] variable ")"] [":" guards] block)+
/// Try Block ::= "try" block
/// ("catch" ["(" [type] variable ")"] [":" guards] block)+
/// ["finally" block]
/// ~~~~~~~~
///
@ -791,7 +787,7 @@
/// -----------------------------------------------------------------------
///
/// @section keywordwhile while
///
///
/// Begins a conditional block of code that loops 0 or more times, as long as the condition is true
///
/// ~~~~~~~~
@ -804,7 +800,7 @@
/// -----------------------------------------------------------------------
///
/// @section keywordvar var
///
///
/// Defines a variable
///
/// ~~~~~~~~
@ -813,7 +809,6 @@
///
/// Synonym for @ref keywordauto
/// @namespace chaiscript
/// @brief Namespace chaiscript contains every API call that the average user will be concerned with.
@ -821,25 +816,22 @@
/// @brief Classes and functions reserved for internal use. Items in this namespace are not supported.
#include "chaiscript_basic.hpp"
#include "language/chaiscript_parser.hpp"
#include "chaiscript_stdlib.hpp"
#include "language/chaiscript_parser.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)
{
}
namespace chaiscript {
class ChaiScript : public ChaiScript_Basic {
public:
ChaiScript(std::vector<std::string> t_modulepaths = {},
std::vector<std::string> t_usepaths = {},
std::vector<Options> t_opts = chaiscript::default_options())
: ChaiScript_Basic(chaiscript::Std_Lib::library(),
std::make_unique<parser::ChaiScript_Parser<eval::Noop_Tracer, optimizer::Optimizer_Default>>(),
std::move(t_modulepaths),
std::move(t_usepaths),
std::move(t_opts)) {
}
};
}
} // namespace chaiscript
#endif /* CHAISCRIPT_HPP_ */

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)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_BASIC_HPP_
@ -9,13 +9,13 @@
#include "chaiscript_defines.hpp"
#include "dispatchkit/dispatchkit.hpp"
#include "dispatchkit/function_call.hpp"
#include "dispatchkit/dynamic_object.hpp"
#include "dispatchkit/boxed_number.hpp"
#include "dispatchkit/dispatchkit.hpp"
#include "dispatchkit/dynamic_object.hpp"
#include "dispatchkit/function_call.hpp"
#include "language/chaiscript_eval.hpp"
#include "language/chaiscript_engine.hpp"
#include "language/chaiscript_eval.hpp"
// This file includes all of the basic requirements for ChaiScript,
// to use, you might do something like:
@ -34,6 +34,4 @@ ChaiScript_Basic chai(
// If you want a fully packaged ready to go ChaiScript, use chaiscript.hpp
#endif /* CHAISCRIPT_BASIC_HPP_ */

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)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_DEFINES_HPP_
@ -20,9 +20,10 @@ static_assert(_MSC_FULL_VER >= 190024210, "Visual C++ 2015 Update 3 or later req
#define CHAISCRIPT_COMPILER_VERSION __VERSION__
#endif
#include <string_view>
#include <vector>
#if defined( _LIBCPP_VERSION )
#if defined(_LIBCPP_VERSION)
#define CHAISCRIPT_LIBCPP
#endif
@ -48,16 +49,14 @@ static_assert(_MSC_FULL_VER >= 190024210, "Visual C++ 2015 Update 3 or later req
#endif
#endif
#if defined(__llvm__)
#define CHAISCRIPT_CLANG
#endif
#ifdef CHAISCRIPT_HAS_DECLSPEC
#ifdef CHAISCRIPT_HAS_DECLSPEC
#define CHAISCRIPT_MODULE_EXPORT extern "C" __declspec(dllexport)
#else
#define CHAISCRIPT_MODULE_EXPORT extern "C"
#define CHAISCRIPT_MODULE_EXPORT extern "C"
#endif
#if defined(CHAISCRIPT_MSVC) || (defined(__GNUC__) && __GNUC__ >= 5) || defined(CHAISCRIPT_CLANG)
@ -70,154 +69,176 @@ static_assert(_MSC_FULL_VER >= 190024210, "Visual C++ 2015 Update 3 or later req
#define CHAISCRIPT_DEBUG false
#endif
#include <cmath>
#include <memory>
#include <string>
#include <cmath>
namespace chaiscript {
static const int version_major = 6;
static const int version_minor = 0;
static const int version_patch = 0;
constexpr static const int version_major = 7;
constexpr static const int version_minor = 0;
constexpr 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;
constexpr static const char *compiler_version = CHAISCRIPT_COMPILER_VERSION;
constexpr static const char *compiler_name = CHAISCRIPT_COMPILER_NAME;
constexpr static const bool debug_build = CHAISCRIPT_DEBUG;
template<typename B, typename D, typename ...Arg>
inline std::shared_ptr<B> make_shared(Arg && ... arg)
{
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)...)));
return std::shared_ptr<B>(static_cast<B *>(new D(std::forward<Arg>(arg)...)));
#endif
}
template<typename B, typename D, typename... Arg>
inline std::unique_ptr<B> make_unique(Arg &&...arg) {
#ifdef CHAISCRIPT_USE_STD_MAKE_SHARED
return std::make_unique<D>(std::forward<Arg>(arg)...);
#else
return std::unique_ptr<B>(static_cast<B *>(new D(std::forward<Arg>(arg)...)));
#endif
}
struct Build_Info {
static int version_major()
{
return chaiscript::version_major;
}
[[nodiscard]] constexpr static int version_major() noexcept { return chaiscript::version_major; }
static int version_minor()
{
return chaiscript::version_minor;
}
[[nodiscard]] constexpr static int version_minor() noexcept { return chaiscript::version_minor; }
static int version_patch()
{
return chaiscript::version_patch;
}
[[nodiscard]] constexpr static int version_patch() noexcept { return chaiscript::version_patch; }
static std::string version()
{
[[nodiscard]] 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();
}
[[nodiscard]] static std::string compiler_id() { return compiler_name() + '-' + compiler_version(); }
static std::string build_id()
{
return compiler_id() + (debug_build()?"-Debug":"-Release");
}
[[nodiscard]] static std::string build_id() { return compiler_id() + (debug_build() ? "-Debug" : "-Release"); }
static std::string compiler_version()
{
return chaiscript::compiler_version;
}
[[nodiscard]] static std::string compiler_version() { return chaiscript::compiler_version; }
static std::string compiler_name()
{
return chaiscript::compiler_name;
}
[[nodiscard]] static std::string compiler_name() { return chaiscript::compiler_name; }
static bool debug_build()
{
return chaiscript::debug_build;
}
[[nodiscard]] constexpr static bool debug_build() noexcept { 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';
[[nodiscard]] constexpr auto parse_num(const std::string_view t_str) noexcept -> typename std::enable_if<std::is_integral<T>::value, T>::type {
T t = 0;
for (const auto c : t_str) {
if (c < '0' || c > '9') {
return t;
}
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;
[[nodiscard]] auto parse_num(const std::string_view t_str) -> typename std::enable_if<!std::is_integral<T>::value, T>::type {
T t = 0;
T base{};
T decimal_place = 0;
int exponent = 0;
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 == '.') {
for (const auto c : t_str) {
switch (c) {
case '.':
decimal_place = 10;
} else if (c == 'e' || c == 'E') {
exponent = true;
break;
case 'e':
case 'E':
exponent = 1;
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;
}
break;
case '-':
exponent = -1;
break;
case '+':
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
if (decimal_place < 10) {
t *= 10;
t += static_cast<T>(c - '0');
} else {
t += static_cast<T>(c - '0') / decimal_place;
decimal_place *= 10;
}
break;
default:
break;
}
return final_value(t, base, exponent, neg_exponent);
}
return exponent ? base * std::pow(T(10), t * static_cast<T>(exponent)) : t;
}
template<typename T>
T parse_num(const std::string &t_str)
{
return parse_num<T>(t_str.c_str());
struct str_equal {
[[nodiscard]] bool operator()(const std::string &t_lhs, const std::string &t_rhs) const noexcept { return t_lhs == t_rhs; }
template<typename LHS, typename RHS>
[[nodiscard]] constexpr bool operator()(const LHS &t_lhs, const RHS &t_rhs) const noexcept {
return std::equal(t_lhs.begin(), t_lhs.end(), t_rhs.begin(), t_rhs.end());
}
struct is_transparent {
};
};
enum class Options
{
struct str_less {
[[nodiscard]] bool operator()(const std::string &t_lhs, const std::string &t_rhs) const noexcept { return t_lhs < t_rhs; }
template<typename LHS, typename RHS>
[[nodiscard]] constexpr bool operator()(const LHS &t_lhs, const RHS &t_rhs) const noexcept {
return std::lexicographical_compare(t_lhs.begin(), t_lhs.end(), t_rhs.begin(), t_rhs.end());
}
struct is_transparent {
};
};
enum class Options {
No_Load_Modules,
Load_Modules,
No_External_Scripts,
External_Scripts
};
static inline std::vector<Options> default_options()
{
return {Options::Load_Modules, Options::External_Scripts};
}
}
#endif
template<typename From, typename To>
struct is_nothrow_forward_constructible : std::bool_constant<noexcept(To{std::declval<From>()})> {
};
template<class From, class To>
static inline constexpr bool is_nothrow_forward_constructible_v = is_nothrow_forward_constructible<From, To>::value;
template<typename Container, typename... T>
[[nodiscard]] constexpr auto make_container(T &&...t) {
Container c;
c.reserve(sizeof...(t));
(c.push_back(std::forward<T>(t)), ...);
return c;
}
template<typename... T>
[[nodiscard]] auto make_vector(T &&...t) -> std::vector<std::common_type_t<std::decay_t<T>...>> {
using container_type = std::vector<std::common_type_t<std::decay_t<T>...>>;
return make_container<container_type>(std::forward<T>(t)...);
}
[[nodiscard]] 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
}
} // namespace chaiscript
#endif

View File

@ -19,53 +19,48 @@
#include "dispatchkit/function_call.hpp"
//#include "dispatchkit/dispatchkit.hpp"
#include "dispatchkit/operators.hpp"
#include "dispatchkit/bootstrap.hpp"
#include "dispatchkit/bootstrap_stl.hpp"
#include "dispatchkit/operators.hpp"
//#include "dispatchkit/boxed_value.hpp"
#include "language/chaiscript_prelude.hpp"
#include "dispatchkit/register_function.hpp"
#include "language/chaiscript_prelude.hpp"
#include "utility/json_wrap.hpp"
#ifndef CHAISCRIPT_NO_THREADS
#include <future>
#endif
/// @file
///
/// This file generates the standard library that normal ChaiScript usage requires.
namespace chaiscript
{
class Std_Lib
{
public:
namespace chaiscript {
class Std_Lib {
public:
[[nodiscard]] static ModulePtr library() {
auto lib = std::make_shared<Module>();
bootstrap::Bootstrap::bootstrap(*lib);
static ModulePtr library()
{
auto lib = std::make_shared<Module>();
bootstrap::Bootstrap::bootstrap(*lib);
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);
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);
#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");
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);
json_wrap::library(*lib);
lib->eval(ChaiScript_Prelude::chaiscript_prelude() /*, "standard prelude"*/ );
return lib;
}
lib->eval(ChaiScript_Prelude::chaiscript_prelude() /*, "standard prelude"*/);
return lib;
}
};
}
} // namespace chaiscript
#endif

View File

@ -1,25 +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-2017, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2018, 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>
#include <shared_mutex>
#include <thread>
#else
#ifndef CHAISCRIPT_NO_THREADS_WARNING
#pragma message ("ChaiScript is compiling without thread safety.")
#pragma message("ChaiScript is compiling without thread safety.")
#endif
#endif
@ -33,141 +32,102 @@
/// It also has the side effect that the chaiscript::ChaiScript object may not be accessed from more than
/// one thread simultaneously.
namespace chaiscript
{
namespace detail
{
/// If threading is enabled, then this namespace contains std thread classes.
/// If threading is not enabled, then stubbed in wrappers that do nothing are provided.
/// This allows us to avoid \#ifdef code in the sections that need thread safety.
namespace threading
{
/// If threading is enabled, then this namespace contains std thread classes.
/// If threading is not enabled, then stubbed in wrappers that do nothing are provided.
/// This allows us to avoid \#ifdef code in the sections that need thread safety.
namespace chaiscript::detail::threading {
#ifndef CHAISCRIPT_NO_THREADS
template<typename T>
using unique_lock = std::unique_lock<T>;
template<typename T>
using unique_lock = std::unique_lock<T>;
template<typename T>
using shared_lock = std::unique_lock<T>;
template<typename T>
using shared_lock = std::shared_lock<T>;
template<typename T>
using lock_guard = std::lock_guard<T>;
template<typename T>
using lock_guard = std::lock_guard<T>;
using std::shared_mutex;
using shared_mutex = std::mutex;
using std::mutex;
using std::mutex;
using std::recursive_mutex;
using std::recursive_mutex;
/// 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() = 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;
/// 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() { t().erase(this); }
explicit Thread_Storage(void *t_key)
: m_key(t_key)
{
}
inline const T *operator->() const noexcept { return &(t()[this]); }
~Thread_Storage()
{
t().erase(m_key);
}
inline const T &operator*() const noexcept { return t()[this]; }
inline const T *operator->() const
{
return &(t()[m_key]);
}
inline T *operator->() noexcept { return &(t()[this]); }
inline const T &operator*() const
{
return t()[m_key];
}
inline T &operator*() noexcept { return t()[this]; }
inline T *operator->()
{
return &(t()[m_key]);
}
void *m_key;
inline T &operator*()
{
return t()[m_key];
}
void *m_key;
private:
static std::unordered_map<void*, T> &t()
{
thread_local static std::unordered_map<void *, T> my_t;
return my_t;
}
};
private:
/// todo: is it valid to make this noexcept? The allocation could fail, but if it
/// does there is no possible way to recover
static std::unordered_map<const void *, T> &t() noexcept {
static thread_local std::unordered_map<const void *, T> my_t;
return my_t;
}
};
#else // threading disabled
template<typename T>
class unique_lock
{
public:
explicit unique_lock(T &) {}
void lock() {}
void unlock() {}
};
template<typename T>
class unique_lock {
public:
constexpr explicit unique_lock(T &) noexcept {}
constexpr void lock() noexcept {}
constexpr void unlock() noexcept {}
};
template<typename T>
class shared_lock
{
public:
explicit shared_lock(T &) {}
void lock() {}
void unlock() {}
};
template<typename T>
class shared_lock {
public:
constexpr explicit shared_lock(T &) noexcept {}
constexpr void lock() noexcept {}
constexpr void unlock() noexcept {}
};
template<typename T>
class lock_guard
{
public:
explicit lock_guard(T &) {}
};
template<typename T>
class lock_guard {
public:
constexpr explicit lock_guard(T &) noexcept {}
};
class shared_mutex { };
class shared_mutex {
};
class recursive_mutex {};
class recursive_mutex {
};
template<typename T>
class Thread_Storage {
public:
constexpr explicit Thread_Storage() noexcept {}
template<typename T>
class Thread_Storage
{
public:
explicit Thread_Storage(void *)
{
}
constexpr inline T *operator->() const noexcept { return &obj; }
inline T *operator->() const
{
return &obj;
}
constexpr inline T &operator*() const noexcept { return obj; }
inline T &operator*() const
{
return obj;
}
private:
mutable T obj;
};
private:
mutable T obj;
};
#endif
}
}
}
} // namespace chaiscript::detail::threading
#endif

View File

@ -11,154 +11,105 @@
namespace chaiscript {
namespace detail {
namespace exception
{
namespace exception {
/// \brief Thrown in the event that an Any cannot be cast to the desired type
///
/// It is used internally during function dispatch.
///
/// \sa chaiscript::detail::Any
class bad_any_cast : public std::bad_cast
{
public:
bad_any_cast() = default;
bad_any_cast(const bad_any_cast &) = default;
~bad_any_cast() noexcept override = default;
/// \brief Description of what error occurred
const char * what() const noexcept override
{
return m_what.c_str();
}
private:
std::string m_what = "bad any cast";
class bad_any_cast : public std::bad_cast {
public:
/// \brief Description of what error occurred
const char *what() const noexcept override { return "bad any cast"; }
};
}
} // namespace exception
class Any {
private:
struct Data
{
explicit Data(const std::type_info &t_type)
: m_type(t_type)
{
}
Data &operator=(const Data &) = delete;
virtual ~Data() = default;
virtual void *data() = 0;
const std::type_info &type() const
{
return m_type;
}
virtual std::unique_ptr<Data> clone() const = 0;
const std::type_info &m_type;
};
template<typename T>
struct Data_Impl : Data
{
explicit Data_Impl(T t_type)
: Data(typeid(T)),
m_data(std::move(t_type))
{
}
void *data() override
{
return &m_data;
}
std::unique_ptr<Data> clone() const override
{
return std::unique_ptr<Data>(new Data_Impl<T>(m_data));
}
Data_Impl &operator=(const Data_Impl&) = delete;
T m_data;
};
std::unique_ptr<Data> m_data;
public:
// construct/copy/destruct
Any() = default;
Any(Any &&) = default;
Any &operator=(Any &&t_any) = default;
Any(const Any &t_any)
{
if (!t_any.empty())
{
m_data = t_any.m_data->clone();
} else {
m_data.reset();
}
private:
struct Data {
constexpr explicit Data(const std::type_info &t_type) noexcept
: m_type(t_type) {
}
Data &operator=(const Data &) = delete;
template<typename ValueType,
typename = typename std::enable_if<!std::is_same<Any, typename std::decay<ValueType>::type>::value>::type>
explicit Any(ValueType &&t_value)
: m_data(std::unique_ptr<Data>(new Data_Impl<typename std::decay<ValueType>::type>(std::forward<ValueType>(t_value))))
{
virtual ~Data() noexcept = default;
virtual void *data() noexcept = 0;
const std::type_info &type() const noexcept { return m_type; }
virtual std::unique_ptr<Data> clone() const = 0;
const std::type_info &m_type;
};
template<typename T>
struct Data_Impl : Data {
explicit Data_Impl(T t_type)
: Data(typeid(T))
, m_data(std::move(t_type)) {
}
void *data() noexcept override { return &m_data; }
Any & operator=(const Any &t_any)
{
Any copy(t_any);
swap(copy);
return *this;
std::unique_ptr<Data> clone() const override { return std::make_unique<Data_Impl<T>>(m_data); }
Data_Impl &operator=(const Data_Impl &) = delete;
T m_data;
};
std::unique_ptr<Data> m_data;
public:
// construct/copy/destruct
constexpr Any() noexcept = default;
Any(Any &&) noexcept = default;
Any &operator=(Any &&t_any) = default;
Any(const Any &t_any)
: m_data(t_any.empty() ? nullptr : t_any.m_data->clone()) {
}
template<typename ValueType, typename = std::enable_if_t<!std::is_same_v<Any, std::decay_t<ValueType>>>>
explicit Any(ValueType &&t_value)
: m_data(std::make_unique<Data_Impl<std::decay_t<ValueType>>>(std::forward<ValueType>(t_value))) {
}
Any &operator=(const Any &t_any) {
Any copy(t_any);
swap(copy);
return *this;
}
template<typename ToType>
ToType &cast() const {
if (m_data && typeid(ToType) == m_data->type()) {
return *static_cast<ToType *>(m_data->data());
} else {
throw chaiscript::detail::exception::bad_any_cast();
}
}
template<typename ToType>
ToType &cast() const
{
if (m_data && typeid(ToType) == m_data->type())
{
return *static_cast<ToType *>(m_data->data());
} else {
throw chaiscript::detail::exception::bad_any_cast();
}
}
// modifiers
Any &swap(Any &t_other) {
std::swap(t_other.m_data, m_data);
return *this;
}
// queries
bool empty() const noexcept { return !static_cast<bool>(m_data); }
// modifiers
Any & swap(Any &t_other)
{
std::swap(t_other.m_data, m_data);
return *this;
}
// queries
bool empty() const
{
return !bool(m_data);
}
const std::type_info & type() const
{
if (m_data) {
return m_data->type();
} else {
return typeid(void);
}
const std::type_info &type() const noexcept {
if (m_data) {
return m_data->type();
} else {
return typeid(void);
}
}
};
}
}
} // namespace detail
} // namespace chaiscript
#endif

View File

@ -1,13 +1,12 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2018, 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_
@ -15,59 +14,51 @@
#include <typeinfo>
#include "../chaiscript_defines.hpp"
#include "../utility/static_string.hpp"
#include "type_info.hpp"
namespace chaiscript {
class Type_Info;
} // namespace chaiscript
class Type_Info;
} // namespace chaiscript
namespace chaiscript
{
namespace exception
{
namespace chaiscript {
namespace exception {
/// \brief Thrown in the event that a Boxed_Value cannot be cast to the desired type
///
/// It is used internally during function dispatch and may be used by the end user.
///
/// \sa chaiscript::boxed_cast
class bad_boxed_cast : public std::bad_cast
{
public:
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))
{
}
class bad_boxed_cast : public std::bad_cast {
public:
bad_boxed_cast(Type_Info t_from, const std::type_info &t_to, utility::Static_String t_what) noexcept
: from(t_from)
, to(&t_to)
, m_what(std::move(t_what)) {
}
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(Type_Info t_from, const std::type_info &t_to) noexcept
: from(t_from)
, to(&t_to)
, m_what("Cannot perform boxed_cast") {
}
explicit bad_boxed_cast(std::string t_what) noexcept
: m_what(std::move(t_what))
{
}
explicit bad_boxed_cast(utility::Static_String t_what) noexcept
: m_what(std::move(t_what)) {
}
bad_boxed_cast(const bad_boxed_cast &) = default;
~bad_boxed_cast() noexcept override = default;
bad_boxed_cast(const bad_boxed_cast &) noexcept = default;
~bad_boxed_cast() noexcept override = default;
/// \brief Description of what error occurred
const char * what() const noexcept override
{
return m_what.c_str();
}
/// \brief Description of what error occurred
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 = nullptr; ///< std::type_info of the desired (but failed) result type
Type_Info from; ///< Type_Info contained in the Boxed_Value
const std::type_info *to = nullptr; ///< std::type_info of the desired (but failed) result type
private:
std::string m_what;
private:
utility::Static_String m_what;
};
}
}
} // namespace exception
} // namespace chaiscript
#endif

View File

@ -1,85 +1,60 @@
// 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)
// Copyright 2009-2018, 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_
#include <functional>
namespace chaiscript
{
namespace detail
{
namespace chaiscript {
namespace detail {
template<typename T>
constexpr T *get_pointer(T *t) noexcept {
return t;
}
template<typename T>
T* get_pointer(T *t)
{
return t;
}
T *get_pointer(const std::reference_wrapper<T> &t) noexcept {
return &t.get();
}
template<typename T>
T* get_pointer(const std::reference_wrapper<T> &t)
{
return &t.get();
}
template<typename O, typename Ret, typename P1, typename... Param>
constexpr auto bind_first(Ret (*f)(P1, Param...), O &&o) {
return [f, o = std::forward<O>(o)](Param... param) -> Ret { return f(o, std::forward<Param>(param)...); };
}
template<typename O, typename Ret, typename P1, typename ... Param>
auto bind_first(Ret (*f)(P1, Param...), O&& 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>
constexpr auto bind_first(Ret (Class::*f)(Param...), O &&o) {
return [f, o = std::forward<O>(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...), 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>
constexpr auto bind_first(Ret (Class::*f)(Param...) const, O &&o) {
return [f, o = std::forward<O>(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 = std::forward<O>(o)](Param... param) -> Ret { return f(o, 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, typename Ret, typename Class, typename P1, typename... Param>
constexpr auto bind_first(const F &fo, O &&o, Ret (Class::*f)(P1, Param...) const) {
return [fo, o = std::forward<O>(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());
}
}
}
constexpr auto bind_first(const F &f, O &&o) {
return bind_first(f, std::forward<O>(o), &F::operator());
}
} // namespace detail
} // namespace chaiscript
#endif

View File

@ -1,395 +1,333 @@
// 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)
// Copyright 2009-2018, 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 "../utility/utility.hpp"
#include "register_function.hpp"
namespace chaiscript
{
/// \brief Classes and functions useful for bootstrapping of ChaiScript and adding of new types
namespace bootstrap
{
template<typename T, typename = typename std::enable_if<std::is_array<T>::value>::type >
void array(const std::string &type, Module& m)
{
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];
}
}
), "[]"
);
/// \brief Classes and functions useful for bootstrapping of ChaiScript and adding of new types
namespace chaiscript::bootstrap {
template<typename T, typename = typename std::enable_if<std::is_array<T>::value>::type>
void array(const std::string &type, Module &m) {
using ReturnType = typename std::remove_extent<T>::type;
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(user_type<T>(), type);
m.add(fun([](T &t, size_t index) -> ReturnType & {
constexpr const auto extent = std::extent<T>::value;
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");
}
m.add(fun([](const T &t, size_t index) -> const ReturnType & {
constexpr const auto extent = std::extent<T>::value;
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];
}
}),
"[]");
/// \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 Module
template<typename T>
void copy_constructor(const std::string &type, Module& m)
{
m.add(constructor<T (const T &)>(), type);
}
m.add(fun([](const T &) { return std::extent<T>::value; }), "size");
}
/// \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 Module.
template<typename T>
void opers_comparison(Module& m)
{
operators::equal<T>(m);
operators::greater_than<T>(m);
operators::greater_than_equal<T>(m);
operators::less_than<T>(m);
operators::less_than_equal<T>(m);
operators::not_equal<T>(m);
}
/// \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 Module
template<typename T>
void copy_constructor(const std::string &type, Module &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 Module.
template<typename T>
void opers_comparison(Module &m) {
operators::equal<T>(m);
operators::greater_than<T>(m);
operators::greater_than_equal<T>(m);
operators::less_than<T>(m);
operators::less_than_equal<T>(m);
operators::not_equal<T>(m);
}
/// \brief Adds default and copy constructors for the given type
/// \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 Module
/// \sa copy_constructor
/// \sa constructor
template<typename T>
void basic_constructors(const std::string &type, Module &m) {
m.add(constructor<T()>(), type);
copy_constructor<T>(type, m);
}
/// \brief Adds default and copy constructors for the given type
/// \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 Module
/// \sa copy_constructor
/// \sa constructor
template<typename T>
void basic_constructors(const std::string &type, Module& m)
{
m.add(constructor<T ()>(), type);
copy_constructor<T>(type, m);
}
/// \brief Adds a constructor for a POD type
/// \tparam T The type to add the constructor for
/// \param[in] type The name of the type
/// \param[in,out] m The Module to add the constructor to
template<typename T>
void construct_pod(const std::string &type, Module &m) {
m.add(fun([](const Boxed_Number &bn) { return bn.get_as<T>(); }), type);
}
/// \brief Adds a constructor for a POD type
/// \tparam T The type to add the constructor for
/// \param[in] type The name of the type
/// \param[in,out] m The Module to add the constructor to
template<typename T>
void construct_pod(const std::string &type, Module& m)
{
m.add(fun([](const Boxed_Number &bn){ return bn.get_as<T>(); }), type);
}
/// Internal function for converting from a string to a value
/// uses ostream operator >> to perform the conversion
template<typename Input>
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
{
/// 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) {
if constexpr (!std::is_same<Input, wchar_t>::value && !std::is_same<Input, char16_t>::value && !std::is_same<Input, char32_t>::value) {
std::stringstream ss(i);
Input t;
ss >> t;
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
{
} else {
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>
void bootstrap_pod_type(const std::string &name, Module &m) {
m.add(user_type<T>(), name);
m.add(constructor<T()>(), name);
construct_pod<T>(name, m);
/// Add all common functions for a POD type. All operators, and
/// common conversions
template<typename T>
void bootstrap_pod_type(const std::string &name, Module& m)
{
m.add(user_type<T>(), name);
m.add(constructor<T()>(), name);
construct_pod<T>(name, m);
m.add(fun(&parse_string<T>), "to_" + name);
m.add(fun([](const T t) { return t; }), "to_" + name);
}
m.add(fun(&parse_string<T>), "to_" + name);
/// "clone" function for a shared_ptr type. This is used in the case
/// where you do not want to make a deep copy of an object during cloning
/// but want to instead maintain the shared_ptr. It is needed internally
/// for handling of Proxy_Function object (that is,
/// function variables.
template<typename Type>
auto shared_ptr_clone(const std::shared_ptr<Type> &p) {
return p;
}
/// Specific version of shared_ptr_clone just for Proxy_Functions
template<typename Type>
std::shared_ptr<std::remove_const_t<Type>> shared_ptr_unconst_clone(const std::shared_ptr<std::add_const_t<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.
template<typename Type>
Boxed_Value ptr_assign(Boxed_Value lhs, const std::shared_ptr<Type> &rhs) {
if (lhs.is_undef() || (!lhs.get_type_info().is_const() && lhs.get_type_info().bare_equal(chaiscript::detail::Get_Type_Info<Type>::get()))) {
lhs.assign(Boxed_Value(rhs));
return lhs;
} else {
throw exception::bad_boxed_cast("type mismatch in pointer assignment");
}
}
/// "clone" function for a shared_ptr type. This is used in the case
/// where you do not want to make a deep copy of an object during cloning
/// but want to instead maintain the shared_ptr. It is needed internally
/// for handling of Proxy_Function object (that is,
/// function variables.
template<typename Type>
auto shared_ptr_clone(const std::shared_ptr<Type> &p)
{
return p;
}
/// 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)
{
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.
template<typename Type>
Boxed_Value ptr_assign(Boxed_Value lhs, const std::shared_ptr<Type> &rhs)
{
if (lhs.is_undef()
|| (!lhs.get_type_info().is_const() && lhs.get_type_info().bare_equal(chaiscript::detail::Get_Type_Info<Type>::get())))
{
lhs.assign(Boxed_Value(rhs));
return lhs;
/// 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
static Boxed_Value unknown_assign(Boxed_Value lhs, Boxed_Value rhs) {
if (lhs.is_undef()) {
return (lhs.assign(rhs));
} else {
throw exception::bad_boxed_cast("type mismatch in pointer assignment");
throw exception::bad_boxed_cast("boxed_value has a set type already");
}
}
/// 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
static Boxed_Value unknown_assign(Boxed_Value lhs, Boxed_Value rhs)
{
if (lhs.is_undef())
{
return (lhs.assign(rhs));
} else {
throw exception::bad_boxed_cast("boxed_value has a set type already");
}
static void print(const std::string &s) noexcept { fwrite(s.c_str(), 1, s.size(), stdout); }
static void println(const std::string &s) noexcept { puts(s.c_str()); }
/// 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), ">>");
}
/// 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 Function_Params &params) {
if (params.empty()) {
throw exception::arity_error(0, 1);
}
static void print(const std::string &s)
{
fwrite(s.c_str(), 1, s.size(), stdout);
Const_Proxy_Function f = boxed_cast<Const_Proxy_Function>(params[0]);
if (f->get_arity() != -1 && size_t(f->get_arity()) != params.size() - 1) {
throw exception::arity_error(static_cast<int>(params.size()), f->get_arity());
}
static void println(const std::string &s)
{
puts(s.c_str());
return Boxed_Value(Const_Proxy_Function(
std::make_shared<dispatch::Bound_Function>(std::move(f), std::vector<Boxed_Value>(params.begin() + 1, params.end()))));
}
static bool has_guard(const Const_Proxy_Function &t_pf) noexcept {
auto pf = std::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(t_pf);
return pf && pf->has_guard();
}
static Const_Proxy_Function get_guard(const Const_Proxy_Function &t_pf) {
const auto pf = std::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(t_pf);
if (pf && pf->get_guard()) {
return pf->get_guard();
} else {
throw std::runtime_error("Function does not have a guard");
}
}
template<typename FunctionType>
static std::vector<Boxed_Value> do_return_boxed_value_vector(FunctionType f, const dispatch::Proxy_Function_Base *b) {
auto v = (b->*f)();
std::vector<Boxed_Value> vbv;
for (const auto &o : v) {
vbv.push_back(const_var(o));
}
return vbv;
}
/// 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), "!=");
static bool has_parse_tree(const chaiscript::Const_Proxy_Function &t_pf) noexcept {
const auto pf = std::dynamic_pointer_cast<const chaiscript::dispatch::Dynamic_Proxy_Function>(t_pf);
return bool(pf);
}
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
static Boxed_Value bind_function(const std::vector<Boxed_Value> &params)
{
if (params.empty()) {
throw exception::arity_error(0, 1);
}
Const_Proxy_Function f = boxed_cast<Const_Proxy_Function>(params[0]);
if (f->get_arity() != -1 && size_t(f->get_arity()) != params.size() - 1)
{
throw exception::arity_error(static_cast<int>(params.size()), f->get_arity());
}
return Boxed_Value(Const_Proxy_Function(std::make_shared<dispatch::Bound_Function>(std::move(f),
std::vector<Boxed_Value>(params.begin() + 1, params.end()))));
static const chaiscript::AST_Node &get_parse_tree(const chaiscript::Const_Proxy_Function &t_pf) {
const auto pf = std::dynamic_pointer_cast<const chaiscript::dispatch::Dynamic_Proxy_Function>(t_pf);
if (pf) {
return pf->get_parse_tree();
} else {
throw std::runtime_error("Function does not have a parse tree");
}
}
template<typename Function>
static auto return_boxed_value_vector(const Function &f) {
return [f](const dispatch::Proxy_Function_Base *b) { return do_return_boxed_value_vector(f, b); };
}
static bool has_guard(const Const_Proxy_Function &t_pf)
{
auto pf = std::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(t_pf);
return pf && pf->get_guard();
}
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 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<dispatch::Assignable_Proxy_Function>(), "Assignable_Function");
m.add(user_type<std::exception>(), "exception");
static Const_Proxy_Function get_guard(const Const_Proxy_Function &t_pf)
{
const auto pf = std::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(t_pf);
if (pf && pf->get_guard())
{
return pf->get_guard();
} else {
throw std::runtime_error("Function does not have a guard");
}
}
m.add(fun(&dispatch::Proxy_Function_Base::get_arity), "get_arity");
m.add(fun(&dispatch::Proxy_Function_Base::operator==), "==");
template<typename FunctionType>
static std::vector<Boxed_Value> do_return_boxed_value_vector(FunctionType f,
const dispatch::Proxy_Function_Base *b)
{
auto v = (b->*f)();
std::vector<Boxed_Value> vbv;
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");
for (const auto &o: v)
{
vbv.push_back(const_var(o));
}
m.add(fun([](const std::exception &e) { return std::string(e.what()); }), "what");
return vbv;
}
m.add(user_type<std::out_of_range>(), "out_of_range");
m.add(user_type<std::logic_error>(), "logic_error");
m.add(chaiscript::base_class<std::exception, std::logic_error>());
m.add(chaiscript::base_class<std::logic_error, std::out_of_range>());
m.add(chaiscript::base_class<std::exception, std::out_of_range>());
m.add(user_type<std::runtime_error>(), "runtime_error");
m.add(chaiscript::base_class<std::exception, std::runtime_error>());
static bool has_parse_tree(const chaiscript::Const_Proxy_Function &t_pf)
{
const auto pf = std::dynamic_pointer_cast<const chaiscript::dispatch::Dynamic_Proxy_Function>(t_pf);
return pf && pf->get_parse_tree();
}
m.add(constructor<std::runtime_error(const std::string &)>(), "runtime_error");
static chaiscript::AST_NodePtr get_parse_tree(const chaiscript::Const_Proxy_Function &t_pf)
{
const auto pf = std::dynamic_pointer_cast<const chaiscript::dispatch::Dynamic_Proxy_Function>(t_pf);
if (pf && pf->get_parse_tree())
{
return pf->get_parse_tree();
} else {
throw std::runtime_error("Function does not have a parse tree");
}
}
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");
template<typename Function>
static auto return_boxed_value_vector(const Function &f)
{
return [f](const dispatch::Proxy_Function_Base *b) {
return do_return_boxed_value_vector(f, b);
};
}
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(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");
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 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<dispatch::Assignable_Proxy_Function>(), "Assignable_Function");
m.add(user_type<std::exception>(), "exception");
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.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([](const std::exception &e){ return std::string(e.what()); }), "what");
m.add(user_type<std::out_of_range>(), "out_of_range");
m.add(user_type<std::logic_error>(), "logic_error");
m.add(chaiscript::base_class<std::exception, std::logic_error>());
m.add(chaiscript::base_class<std::logic_error, std::out_of_range>());
m.add(chaiscript::base_class<std::exception, std::out_of_range>());
m.add(user_type<std::runtime_error>(), "runtime_error");
m.add(chaiscript::base_class<std::exception, std::runtime_error>());
m.add(constructor<std::runtime_error (const std::string &)>(), "runtime_error");
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(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(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(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;
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); } );
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()
@ -417,173 +355,157 @@ namespace chaiscript
}
)chaiscript");
m.add(fun(&has_guard), "has_guard");
m.add(fun(&get_guard), "get_guard");
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::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");
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);
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([](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");
basic_constructors<bool>("bool", m);
operators::assign<bool>(m);
operators::equal<bool>(m);
operators::not_equal<bool>(m);
m.add(fun([](const char c) { return std::string(1, c); }), "to_string");
m.add(fun(&Boxed_Number::to_string), "to_string");
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");
bootstrap_pod_type<double>("double", m);
bootstrap_pod_type<long double>("long_double", m);
bootstrap_pod_type<float>("float", m);
bootstrap_pod_type<int>("int", m);
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);
bootstrap_pod_type<std::int64_t>("int64_t", m);
bootstrap_pod_type<std::uint8_t>("uint8_t", m);
bootstrap_pod_type<std::uint16_t>("uint16_t", m);
bootstrap_pod_type<std::uint32_t>("uint32_t", m);
bootstrap_pod_type<std::uint64_t>("uint64_t", m);
m.add(fun([](const char c) { return std::string(1, c); }), "to_string");
m.add(fun(&Boxed_Number::to_string), "to_string");
operators::logical_compliment<bool>(m);
bootstrap_pod_type<double>("double", m);
bootstrap_pod_type<long double>("long_double", m);
bootstrap_pod_type<float>("float", m);
bootstrap_pod_type<int>("int", m);
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);
bootstrap_pod_type<std::int64_t>("int64_t", m);
bootstrap_pod_type<std::uint8_t>("uint8_t", m);
bootstrap_pod_type<std::uint16_t>("uint16_t", m);
bootstrap_pod_type<std::uint32_t>("uint32_t", m);
bootstrap_pod_type<std::uint64_t>("uint64_t", m);
opers_arithmetic_pod(m);
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");
operators::logical_compliment<bool>(m);
m.add(fun(&print), "print_string");
m.add(fun(&println), "println_string");
opers_arithmetic_pod(m);
m.add(dispatch::make_dynamic_proxy_function(&bind_function), "bind");
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(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(fun(&print), "print_string");
m.add(fun(&println), "println_string");
m.add(chaiscript::fun(&has_parse_tree), "has_parse_tree");
m.add(chaiscript::fun(&get_parse_tree), "get_parse_tree");
m.add(dispatch::make_dynamic_proxy_function(&bind_function), "bind");
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(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(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(fun(&Boxed_Value::type_match), "type_match");
// chaiscript::bootstrap::standard_library::vector_type<std::vector<std::shared_ptr<chaiscript::AST_Node> >
// >("AST_NodeVector", m);
chaiscript::utility::add_class<chaiscript::exception::eval_error>(m,
"eval_error",
{},
{{fun(&chaiscript::exception::eval_error::reason), "reason"},
{fun(&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 chaiscript::AST_Node_Trace &>);
return retval;
}),
"call_stack"}});
m.add(chaiscript::fun(&has_parse_tree), "has_parse_tree");
m.add(chaiscript::fun(&get_parse_tree), "get_parse_tree");
chaiscript::utility::add_class<chaiscript::File_Position>(m,
"File_Position",
{constructor<File_Position()>(), constructor<File_Position(int, int)>()},
{{fun(&File_Position::line), "line"},
{fun(&File_Position::column), "column"}});
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>());
// chaiscript::bootstrap::standard_library::vector_type<std::vector<std::shared_ptr<chaiscript::AST_Node> > >("AST_NodeVector", m);
chaiscript::utility::add_class<chaiscript::exception::eval_error>(m,
"eval_error",
{ },
{ {fun(&chaiscript::exception::eval_error::reason), "reason"},
{fun(&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,
"File_Position",
{ constructor<File_Position()>(),
constructor<File_Position(int, int)>() },
{ {fun(&File_Position::line), "line"},
{fun(&File_Position::column), "column"} }
);
chaiscript::utility::add_class<AST_Node>(m,
"AST_Node",
{ },
{ {fun(&AST_Node::text), "text"},
{fun(&AST_Node::identifier), "identifier"},
{fun(&AST_Node::filename), "filename"},
{fun(&AST_Node::start), "start"},
{fun(&AST_Node::end), "end"},
{fun(&AST_Node::to_string), "to_string"},
{fun([](const chaiscript::AST_Node &t_node) -> std::vector<Boxed_Value> {
std::vector<Boxed_Value> retval;
const auto children = t_node.get_children();
std::transform(children.begin(), children.end(),
std::back_inserter(retval),
&chaiscript::var<const std::shared_ptr<chaiscript::AST_Node> &>);
return retval;
}), "children"}
}
);
}
};
}
}
chaiscript::utility::add_class<AST_Node>(m,
"AST_Node",
{},
{{fun(&AST_Node::text), "text"},
{fun(&AST_Node::identifier), "identifier"},
{fun(&AST_Node::filename), "filename"},
{fun(&AST_Node::start), "start"},
{fun(&AST_Node::end), "end"},
{fun(&AST_Node::to_string), "to_string"},
{fun([](const chaiscript::AST_Node &t_node) -> std::vector<Boxed_Value> {
std::vector<Boxed_Value> retval;
const auto children = t_node.get_children();
std::transform(children.begin(),
children.end(),
std::back_inserter(retval),
&chaiscript::var<const std::reference_wrapper<chaiscript::AST_Node> &>);
return retval;
}),
"children"}});
}
};
} // namespace chaiscript::bootstrap
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,13 +1,12 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2018, 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_
@ -19,23 +18,19 @@
#include "type_info.hpp"
namespace chaiscript {
class Type_Conversions;
namespace detail {
namespace exception {
class bad_any_cast;
} // namespace exception
} // namespace detail
} // namespace chaiscript
class Type_Conversions;
}
namespace chaiscript::detail::exception {
class bad_any_cast;
} // namespace chaiscript::detail::exception
namespace chaiscript
{
namespace chaiscript {
/// \brief Function for extracting a value stored in a Boxed_Value object
/// \tparam Type The type to extract from the Boxed_Value
/// \param[in] bv The Boxed_Value to extract a typed value from
/// \returns Type equivalent to the requested type
/// \returns Type equivalent to the requested type
/// \throws exception::bad_boxed_cast If the requested conversion is not possible
///
///
/// boxed_cast will attempt to make conversions between value, &, *, std::shared_ptr, std::reference_wrapper,
/// and std::function (const and non-const) where possible. boxed_cast is used internally during function
/// dispatch. This means that all of these conversions will be attempted automatically for you during
@ -67,47 +62,41 @@ namespace chaiscript
/// std::function conversion example
/// \code
/// chaiscript::ChaiScript chai;
/// Boxed_Value bv = chai.eval("`+`"); // Get the functor for the + operator which is built in
/// Boxed_Value bv = chai.eval("`+`"); // Get the functor for the + operator which is built in
/// std::function<int (int, int)> f = chaiscript::boxed_cast<std::function<int (int, int)> >(bv);
/// int i = f(2,3);
/// assert(i == 5);
/// \endcode
template<typename Type>
decltype(auto) boxed_cast(const Boxed_Value &bv, const Type_Conversions_State *t_conversions = nullptr)
{
decltype(auto) boxed_cast(const Boxed_Value &bv, const Type_Conversions_State *t_conversions = nullptr) {
if (!t_conversions || bv.get_type_info().bare_equal(user_type<Type>()) || (t_conversions && !(*t_conversions)->convertable_type<Type>())) {
try {
return(detail::Cast_Helper<Type>::cast(bv, t_conversions));
return detail::Cast_Helper<Type>::cast(bv, t_conversions);
} catch (const chaiscript::detail::exception::bad_any_cast &) {
}
}
if (t_conversions && (*t_conversions)->convertable_type<Type>())
{
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));
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));
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
// 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));
}
}
}
} // namespace chaiscript
#endif

View File

@ -1,13 +1,12 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2018, 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_
@ -17,21 +16,19 @@
#include "boxed_value.hpp"
#include "type_info.hpp"
namespace chaiscript
{
namespace chaiscript {
class Type_Conversions_State;
namespace detail
{
namespace detail {
// Cast_Helper_Inner helper classes
template<typename T>
T* throw_if_null(T *t)
{
if (t) { return t; }
throw std::runtime_error("Attempted to dereference null Boxed_Value");
constexpr T *throw_if_null(T *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) {
@ -51,7 +48,6 @@ namespace chaiscript
}
}
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)) {
@ -72,252 +68,193 @@ namespace chaiscript
/// Generic Cast_Helper_Inner, for casting to any type
template<typename Result>
struct Cast_Helper_Inner
{
static Result cast(const Boxed_Value &ob, const Type_Conversions_State *)
{
return *static_cast<const Result *>(verify_type(ob, typeid(Result), ob.get_const_ptr()));
}
};
struct Cast_Helper_Inner {
static Result cast(const Boxed_Value &ob, const Type_Conversions_State *) {
return *static_cast<const Result *>(verify_type(ob, typeid(Result), ob.get_const_ptr()));
}
};
template<typename Result>
struct Cast_Helper_Inner<const Result> : Cast_Helper_Inner<Result>
{
};
struct Cast_Helper_Inner<const Result> : Cast_Helper_Inner<Result> {
};
/// Cast_Helper_Inner for casting to a const * type
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_no_throw(ob, typeid(Result), ob.get_const_ptr()));
}
};
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_no_throw(ob, typeid(Result), ob.get_const_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 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 *>
{
struct Cast_Helper_Inner<Result *> {
static Result *cast(const Boxed_Value &ob, const Type_Conversions_State *) {
return static_cast<Result *>(verify_type_no_throw(ob, typeid(Result), ob.get_ptr()));
}
};
template<typename Result>
struct Cast_Helper_Inner<const Result * const &> : public Cast_Helper_Inner<const 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()));
}
};
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 &>
{
static Result& cast(const Boxed_Value &ob, const Type_Conversions_State *)
{
return *static_cast<Result *>(verify_type(ob, typeid(Result), ob.get_ptr()));
}
};
struct Cast_Helper_Inner<Result &> {
static Result &cast(const Boxed_Value &ob, const Type_Conversions_State *) {
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())));
}
};
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>>>()));
}
};
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>>>());
}
};
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>>>());
}
};
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<std::shared_ptr<Result> >
{
static auto cast(const Boxed_Value &ob, const Type_Conversions_State *)
{
return ob.get().cast<std::shared_ptr<Result> >();
}
};
struct Cast_Helper_Inner<std::shared_ptr<Result>> {
static auto cast(const Boxed_Value &ob, const Type_Conversions_State *) { return ob.get().cast<std::shared_ptr<Result>>(); }
};
/// Cast_Helper_Inner for casting to a std::shared_ptr<const> type
template<typename Result>
struct Cast_Helper_Inner<std::shared_ptr<const Result> >
{
static auto cast(const Boxed_Value &ob, const Type_Conversions_State *)
{
if (!ob.get_type_info().is_const())
{
return std::const_pointer_cast<const Result>(ob.get().cast<std::shared_ptr<Result> >());
} else {
return ob.get().cast<std::shared_ptr<const Result> >();
}
struct Cast_Helper_Inner<std::shared_ptr<const Result>> {
static auto cast(const Boxed_Value &ob, const Type_Conversions_State *) {
if (!ob.get_type_info().is_const()) {
return std::const_pointer_cast<const Result>(ob.get().cast<std::shared_ptr<Result>>());
} else {
return ob.get().cast<std::shared_ptr<const Result>>();
}
};
}
};
/// Cast_Helper_Inner for casting to a const std::shared_ptr<> & type
template<typename Result>
struct Cast_Helper_Inner<const std::shared_ptr<Result> > : Cast_Helper_Inner<std::shared_ptr<Result> >
{
};
struct Cast_Helper_Inner<const std::shared_ptr<Result>> : Cast_Helper_Inner<std::shared_ptr<Result>> {
};
template<typename Result>
struct Cast_Helper_Inner<const std::shared_ptr<Result> &> : Cast_Helper_Inner<std::shared_ptr<Result> >
{
};
struct Cast_Helper_Inner<const std::shared_ptr<Result> &> : Cast_Helper_Inner<std::shared_ptr<Result>> {
};
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);
}
};
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>
struct Cast_Helper_Inner<const std::shared_ptr<const Result> > : Cast_Helper_Inner<std::shared_ptr<const Result> >
{
};
struct Cast_Helper_Inner<const std::shared_ptr<const Result>> : Cast_Helper_Inner<std::shared_ptr<const Result>> {
};
template<typename Result>
struct Cast_Helper_Inner<const std::shared_ptr<const Result> &> : Cast_Helper_Inner<std::shared_ptr<const Result> >
{
};
struct Cast_Helper_Inner<const std::shared_ptr<const Result> &> : Cast_Helper_Inner<std::shared_ptr<const Result>> {
};
/// Cast_Helper_Inner for casting to a Boxed_Value type
template<>
struct Cast_Helper_Inner<Boxed_Value>
{
static Boxed_Value cast(const Boxed_Value &ob, const Type_Conversions_State *)
{
return ob;
}
};
struct Cast_Helper_Inner<Boxed_Value> {
static Boxed_Value cast(const Boxed_Value &ob, const Type_Conversions_State *) { return ob; }
};
/// Cast_Helper_Inner for casting to a Boxed_Value & type
template<>
struct Cast_Helper_Inner<Boxed_Value &>
{
static std::reference_wrapper<Boxed_Value> cast(const Boxed_Value &ob, const Type_Conversions_State *)
{
return std::ref(const_cast<Boxed_Value &>(ob));
}
};
struct Cast_Helper_Inner<Boxed_Value &> {
static std::reference_wrapper<Boxed_Value> cast(const Boxed_Value &ob, const Type_Conversions_State *) {
return std::ref(const_cast<Boxed_Value &>(ob));
}
};
/// Cast_Helper_Inner for casting to a const Boxed_Value & type
template<>
struct Cast_Helper_Inner<const Boxed_Value> : Cast_Helper_Inner<Boxed_Value>
{
};
struct Cast_Helper_Inner<const Boxed_Value> : Cast_Helper_Inner<Boxed_Value> {
};
template<>
struct Cast_Helper_Inner<const Boxed_Value &> : Cast_Helper_Inner<Boxed_Value>
{
};
struct Cast_Helper_Inner<const Boxed_Value &> : Cast_Helper_Inner<Boxed_Value> {
};
/// Cast_Helper_Inner for casting to a std::reference_wrapper type
template<typename Result>
struct Cast_Helper_Inner<std::reference_wrapper<Result> > : Cast_Helper_Inner<Result &>
{
};
struct Cast_Helper_Inner<std::reference_wrapper<Result>> : Cast_Helper_Inner<Result &> {
};
template<typename Result>
struct Cast_Helper_Inner<const std::reference_wrapper<Result> > : Cast_Helper_Inner<Result &>
{
};
struct Cast_Helper_Inner<const std::reference_wrapper<Result>> : Cast_Helper_Inner<Result &> {
};
template<typename Result>
struct Cast_Helper_Inner<const std::reference_wrapper<Result> &> : Cast_Helper_Inner<Result &>
{
};
struct Cast_Helper_Inner<const std::reference_wrapper<Result> &> : Cast_Helper_Inner<Result &> {
};
template<typename Result>
struct Cast_Helper_Inner<std::reference_wrapper<const Result> > : Cast_Helper_Inner<const Result &>
{
};
struct Cast_Helper_Inner<std::reference_wrapper<const Result>> : Cast_Helper_Inner<const Result &> {
};
template<typename Result>
struct Cast_Helper_Inner<const std::reference_wrapper<const Result> > : Cast_Helper_Inner<const Result &>
{
};
struct Cast_Helper_Inner<const std::reference_wrapper<const Result>> : Cast_Helper_Inner<const Result &> {
};
template<typename Result>
struct Cast_Helper_Inner<const std::reference_wrapper<const Result> & > : Cast_Helper_Inner<const Result &>
{
};
struct Cast_Helper_Inner<const std::reference_wrapper<const Result> &> : Cast_Helper_Inner<const Result &> {
};
/// The exposed Cast_Helper object that by default just calls the Cast_Helper_Inner
template<typename T>
struct Cast_Helper
{
static decltype(auto) cast(const Boxed_Value &ob, const Type_Conversions_State *t_conversions)
{
return(Cast_Helper_Inner<T>::cast(ob, t_conversions));
}
};
}
}
struct Cast_Helper {
static decltype(auto) cast(const Boxed_Value &ob, const Type_Conversions_State *t_conversions) {
return (Cast_Helper_Inner<T>::cast(ob, t_conversions));
}
};
} // namespace detail
} // namespace chaiscript
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,13 +1,12 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2018, 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_
@ -19,357 +18,238 @@
#include "any.hpp"
#include "type_info.hpp"
namespace chaiscript
{
namespace chaiscript {
/// \brief A wrapper for holding any valid C++ type. All types in ChaiScript are Boxed_Value objects
/// \sa chaiscript::boxed_cast
class Boxed_Value
{
public:
/// used for explicitly creating a "void" object
struct Void_Type
{
};
class Boxed_Value {
public:
/// used for explicitly creating a "void" object
struct Void_Type {
};
private:
/// structure which holds the internal state of a Boxed_Value
/// \todo Get rid of Any and merge it with this, reducing an allocation in the process
struct Data
{
Data(const Type_Info &ti,
chaiscript::detail::Any to,
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(is_ref), m_return_value(t_return_value)
{
}
Data &operator=(const Data &rhs)
{
m_type_info = rhs.m_type_info;
m_obj = rhs.m_obj;
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::make_unique<std::map<std::string, std::shared_ptr<Data>>>(*rhs.m_attrs);
}
return *this;
}
Data(const Data &) = delete;
Data(Data &&) = default;
Data &operator=(Data &&rhs) = default;
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;
bool m_return_value;
};
struct Object_Data
{
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,
t_return_value)
;
}
template<typename T>
static auto get(const std::shared_ptr<T> *obj, bool t_return_value)
{
return get(*obj, t_return_value);
}
template<typename T>
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(),
t_return_value
);
}
template<typename T>
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,
t_return_value
);
}
template<typename T>
static auto get(T *t, bool t_return_value)
{
return get(std::ref(*t), t_return_value);
}
template<typename T>
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,
t_return_value
);
}
template<typename 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();
return std::make_shared<Data>(
detail::Get_Type_Info<T>::get(),
chaiscript::detail::Any(std::move(p)),
false,
ptr,
t_return_value
);
}
static std::shared_ptr<Data> get()
{
return std::make_shared<Data>(
Type_Info(),
chaiscript::detail::Any(),
false,
nullptr,
false
);
}
};
public:
/// 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, bool t_return_value = false)
: m_data(Object_Data::get(std::forward<T>(t), t_return_value))
{
}
/// Unknown-type constructor
Boxed_Value() = default;
Boxed_Value(Boxed_Value&&) = default;
Boxed_Value& operator=(Boxed_Value&&) = default;
Boxed_Value(const Boxed_Value&) = default;
Boxed_Value& operator=(const Boxed_Value&) = default;
void swap(Boxed_Value &rhs)
{
std::swap(m_data, rhs.m_data);
private:
/// structure which holds the internal state of a Boxed_Value
/// \todo Get rid of Any and merge it with this, reducing an allocation in the process
struct Data {
Data(const Type_Info &ti, chaiscript::detail::Any to, bool is_ref, const void *t_void_ptr, bool t_return_value) noexcept
: 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(is_ref)
, m_return_value(t_return_value) {
}
/// Copy the values stored in rhs.m_data to m_data.
/// m_data pointers are not shared in this case
Boxed_Value assign(const Boxed_Value &rhs)
{
(*m_data) = (*rhs.m_data);
Data &operator=(const Data &rhs) {
m_type_info = rhs.m_type_info;
m_obj = rhs.m_obj;
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::make_unique<std::map<std::string, std::shared_ptr<Data>>>(*rhs.m_attrs);
}
return *this;
}
const Type_Info &get_type_info() const noexcept
{
return m_data->m_type_info;
}
Data(const Data &) = delete;
/// return true if the object is uninitialized
bool is_undef() const noexcept
{
return m_data->m_type_info.is_undef();
}
Data(Data &&) = default;
Data &operator=(Data &&rhs) = default;
bool is_const() const noexcept
{
return m_data->m_type_info.is_const();
}
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;
bool m_return_value;
};
bool is_type(const Type_Info &ti) const noexcept
{
return m_data->m_type_info.bare_equal(ti);
struct Object_Data {
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, t_return_value);
}
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()));
static auto get(const std::shared_ptr<T> *obj, bool t_return_value) {
return get(*obj, t_return_value);
}
bool is_null() const noexcept
{
return (m_data->m_data_ptr == nullptr && m_data->m_const_data_ptr == nullptr);
template<typename T>
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(), t_return_value);
}
const chaiscript::detail::Any & get() const noexcept
{
return m_data->m_obj;
template<typename T>
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, t_return_value);
}
bool is_ref() const noexcept
{
return m_data->m_is_ref;
template<typename T>
static auto get(T *t, bool t_return_value) {
return get(std::ref(*t), t_return_value);
}
bool is_return_value() const noexcept
{
return m_data->m_return_value;
template<typename T>
static auto get(const T *t, bool t_return_value) {
return get(std::cref(*t), t_return_value);
}
void reset_return_value() const noexcept
{
m_data->m_return_value = false;
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, t_return_value);
}
bool is_pointer() const noexcept
{
return !is_ref();
template<typename 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);
}
void *get_ptr() const noexcept
{
return m_data->m_data_ptr;
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();
return std::make_shared<Data>(detail::Get_Type_Info<T>::get(), chaiscript::detail::Any(std::move(p)), false, ptr, t_return_value);
}
const void *get_const_ptr() const noexcept
{
return m_data->m_const_data_ptr;
}
static std::shared_ptr<Data> get() { return std::make_shared<Data>(Type_Info(), chaiscript::detail::Any(), false, nullptr, false); }
};
Boxed_Value get_attr(const std::string &t_name)
{
if (!m_data->m_attrs)
{
m_data->m_attrs = std::make_unique<std::map<std::string, std::shared_ptr<Data>>>();
public:
/// Basic Boxed_Value constructor
template<typename T, typename = std::enable_if_t<!std::is_same_v<Boxed_Value, std::decay_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() = default;
Boxed_Value(Boxed_Value &&) = default;
Boxed_Value &operator=(Boxed_Value &&) = default;
Boxed_Value(const Boxed_Value &) = default;
Boxed_Value &operator=(const Boxed_Value &) = default;
void swap(Boxed_Value &rhs) noexcept { std::swap(m_data, rhs.m_data); }
/// Copy the values stored in rhs.m_data to m_data.
/// m_data pointers are not shared in this case
Boxed_Value assign(const Boxed_Value &rhs) noexcept {
(*m_data) = (*rhs.m_data);
return *this;
}
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 noexcept { return m_data->m_type_info.is_undef(); }
bool is_const() const noexcept { return m_data->m_type_info.is_const(); }
bool is_type(const Type_Info &ti) const noexcept { return m_data->m_type_info.bare_equal(ti); }
template<typename T>
auto pointer_sentinel(std::shared_ptr<T> &ptr) const noexcept {
struct Sentinel {
Sentinel(std::shared_ptr<T> &t_ptr, Data &data)
: m_ptr(t_ptr)
, m_data(data) {
}
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;
~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 noexcept { 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 noexcept { return m_data->m_obj; }
bool is_ref() const noexcept { return m_data->m_is_ref; }
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 noexcept { return m_data->m_data_ptr; }
const void *get_const_ptr() const noexcept { return m_data->m_const_data_ptr; }
Boxed_Value get_attr(const std::string &t_name) {
if (!m_data->m_attrs) {
m_data->m_attrs = std::make_unique<std::map<std::string, std::shared_ptr<Data>>>();
}
Boxed_Value &copy_attrs(const Boxed_Value &t_obj)
{
if (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;
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 &clone_attrs(const Boxed_Value &t_obj)
{
copy_attrs(t_obj);
reset_return_value();
return *this;
Boxed_Value &copy_attrs(const Boxed_Value &t_obj) {
if (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) noexcept
{
return l.get_type_info() == r.get_type_info();
}
/// \returns true if the two Boxed_Values share the same internal type
static bool type_match(const Boxed_Value &l, const Boxed_Value &r) noexcept { return l.get_type_info() == r.get_type_info(); }
private:
// necessary to avoid hitting the templated && constructor of Boxed_Value
struct Internal_Construction{};
private:
// necessary to avoid hitting the templated && constructor of Boxed_Value
struct Internal_Construction {
};
Boxed_Value(std::shared_ptr<Data> t_data, 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();
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
/// @brief Creates a Boxed_Value. If the object passed in is a value type, it is copied. If it is a pointer, std::shared_ptr, or
/// std::reference_type
/// a copy is not made.
/// @param t The value to box
///
@ -384,21 +264,19 @@ namespace chaiscript
///
/// @sa @ref adding_objects
template<typename T>
Boxed_Value var(T &&t)
{
return Boxed_Value(std::forward<T>(t));
}
Boxed_Value var(T &&t) {
return Boxed_Value(std::forward<T>(t));
}
namespace detail {
/// \brief Takes a value, copies it and returns a Boxed_Value object that is immutable
/// \param[in] t Value to copy and make const
/// \returns Immutable Boxed_Value
/// \returns Immutable Boxed_Value
/// \sa Boxed_Value::is_const
template<typename T>
Boxed_Value const_var_impl(const T &t)
{
return Boxed_Value(std::make_shared<typename std::add_const<T>::type >(t));
}
Boxed_Value const_var_impl(const T &t) {
return Boxed_Value(std::make_shared<typename std::add_const<T>::type>(t));
}
/// \brief Takes a pointer to a value, adds const to the pointed to type and returns an immutable Boxed_Value.
/// Does not copy the pointed to value.
@ -406,10 +284,9 @@ namespace chaiscript
/// \returns Immutable Boxed_Value
/// \sa Boxed_Value::is_const
template<typename T>
Boxed_Value const_var_impl(T *t)
{
return Boxed_Value( const_cast<typename std::add_const<T>::type *>(t) );
}
Boxed_Value const_var_impl(T *t) {
return Boxed_Value(const_cast<typename std::add_const<T>::type *>(t));
}
/// \brief Takes a std::shared_ptr to a value, adds const to the pointed to type and returns an immutable Boxed_Value.
/// Does not copy the pointed to value.
@ -417,10 +294,9 @@ namespace chaiscript
/// \returns Immutable Boxed_Value
/// \sa Boxed_Value::is_const
template<typename T>
Boxed_Value const_var_impl(const std::shared_ptr<T> &t)
{
return Boxed_Value( std::const_pointer_cast<typename std::add_const<T>::type>(t) );
}
Boxed_Value const_var_impl(const std::shared_ptr<T> &t) {
return Boxed_Value(std::const_pointer_cast<typename std::add_const<T>::type>(t));
}
/// \brief Takes a std::reference_wrapper value, adds const to the referenced type and returns an immutable Boxed_Value.
/// Does not copy the referenced value.
@ -428,11 +304,10 @@ namespace chaiscript
/// \returns Immutable Boxed_Value
/// \sa Boxed_Value::is_const
template<typename T>
Boxed_Value const_var_impl(const std::reference_wrapper<T> &t)
{
return Boxed_Value( std::cref(t.get()) );
}
}
Boxed_Value const_var_impl(const std::reference_wrapper<T> &t) {
return Boxed_Value(std::cref(t.get()));
}
} // namespace detail
/// \brief Takes an object and returns an immutable Boxed_Value. If the object is a std::reference or pointer type
/// the value is not copied. If it is an object type, it is copied.
@ -454,14 +329,13 @@ namespace chaiscript
/// chai.add(chaiscript::const_var(Red), "Red");
/// chai.add(chaiscript::const_var(Green), "Green");
/// \endcode
///
///
/// \todo support C++11 strongly typed enums
/// \sa \ref adding_objects
template<typename T>
Boxed_Value const_var(const T &t)
{
return detail::const_var_impl(t);
}
Boxed_Value const_var(const T &t) {
return detail::const_var_impl(t);
}
inline Boxed_Value void_var() {
static const auto v = Boxed_Value(Boxed_Value::Void_Type());
@ -479,7 +353,6 @@ namespace chaiscript
}
}
}
} // namespace chaiscript
#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)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_CALLABLE_TRAITS_HPP_
@ -12,49 +12,50 @@
namespace chaiscript {
namespace dispatch {
namespace detail {
template<typename Class, typename ... Param>
struct Constructor
{
template<typename ... Inner>
std::shared_ptr<Class> operator()(Inner&& ... inner) const {
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 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 {
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 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 {
template<typename... Inner>
Ret operator()(Inner &&...inner) const {
return (m_func)(std::forward<Inner>(inner)...);
}
Ret(*m_func)(Param...);
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 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 {
template<typename... Inner>
Ret operator()(Class &o, Inner &&...inner) const {
return (o.*m_func)(std::forward<Inner>(inner)...);
}
@ -62,46 +63,37 @@ namespace chaiscript {
};
template<typename T>
struct Arity
{
};
template<typename Ret, typename ... Params>
struct Arity<Ret (Params...)>
{
static const size_t arity = sizeof...(Params);
};
struct Arity {
};
template<typename Ret, typename... Params>
struct Arity<Ret(Params...)> {
static const size_t arity = sizeof...(Params);
};
template<typename T>
struct Function_Signature
{
};
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 Ret, typename... Params>
struct Function_Signature<Ret(Params...)> {
using Return_Type = Ret;
using Signature = Ret()(Params...);
};
template<typename Ret, typename T, typename... Params>
struct Function_Signature<Ret (T::*)(Params...) const> {
using Return_Type = Ret;
using Signature = Ret()(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;
};
}
}
}
struct Callable_Traits {
using Signature = typename Function_Signature<decltype(&T::operator())>::Signature;
using Return_Type = typename Function_Signature<decltype(&T::operator())>::Return_Type;
};
} // namespace detail
} // namespace dispatch
} // namespace chaiscript
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,13 +1,12 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2018, 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_
@ -18,21 +17,17 @@
#include "boxed_value.hpp"
namespace chaiscript {
class Type_Conversions;
namespace dispatch {
class Proxy_Function_Base;
} // namespace dispatch
} // namespace chaiscript
class Type_Conversions;
namespace dispatch {
class Proxy_Function_Base;
} // namespace dispatch
} // namespace chaiscript
namespace chaiscript
{
namespace dispatch
{
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")
{
: std::runtime_error("option explicit set and parameter '" + t_param_name + "' does not exist") {
}
option_explicit_set(const option_explicit_set &) = default;
@ -40,92 +35,64 @@ namespace chaiscript
~option_explicit_set() noexcept override = default;
};
class Dynamic_Object
{
public:
explicit Dynamic_Object(std::string t_type_name)
: m_type_name(std::move(t_type_name)), m_option_explicit(false)
{
class Dynamic_Object {
public:
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 noexcept { return m_option_explicit; }
void set_explicit(const bool t_explicit) noexcept { m_option_explicit = t_explicit; }
const std::string &get_type_name() const noexcept { return m_type_name; }
const Boxed_Value &operator[](const std::string &t_attr_name) const { return get_attr(t_attr_name); }
Boxed_Value &operator[](const std::string &t_attr_name) { return get_attr(t_attr_name); }
const Boxed_Value &get_attr(const std::string &t_attr_name) const {
auto a = m_attrs.find(t_attr_name);
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);
}
Dynamic_Object() = default;
return get_attr(t_method_name);
}
bool is_explicit() const
{
return m_option_explicit;
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);
}
void set_explicit(const bool t_explicit)
{
m_option_explicit = t_explicit;
}
return get_attr(t_method_name);
}
std::string get_type_name() const
{
return m_type_name;
}
std::map<std::string, Boxed_Value> get_attrs() const { return m_attrs; }
const Boxed_Value &operator[](const std::string &t_attr_name) const
{
return get_attr(t_attr_name);
}
private:
const std::string m_type_name = "";
bool m_option_explicit = false;
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:
const std::string m_type_name = "";
bool m_option_explicit = false;
std::map<std::string, Boxed_Value> m_attrs;
std::map<std::string, Boxed_Value> m_attrs;
};
}
}
} // namespace dispatch
} // namespace chaiscript
#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)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_DYNAMIC_OBJECT_DETAIL_HPP_
@ -19,219 +19,185 @@
#include "boxed_cast.hpp"
#include "boxed_cast_helper.hpp"
#include "boxed_value.hpp"
#include "dynamic_object.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
class Type_Conversions;
namespace dispatch {
class Proxy_Function_Base;
} // namespace dispatch
} // namespace chaiscript
namespace chaiscript
{
namespace dispatch
{
namespace detail
{
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)");
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 noexcept 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;
}
}
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)");
bool is_attribute_function() const noexcept override { return m_is_attribute; }
bool call_match(const chaiscript::Function_Params &vals, const Type_Conversions_State &t_conversions) const noexcept 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}; }
Dynamic_Object_Function &operator=(const Dynamic_Object_Function) = delete;
Dynamic_Object_Function(Dynamic_Object_Function &) = delete;
protected:
Boxed_Value do_call(const chaiscript::Function_Params &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 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);
bool compare_first_type(const Boxed_Value &bv, const Type_Conversions_State &t_conversions) const noexcept 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 noexcept {
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 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;
}
bool dynamic_object_typename_match(const chaiscript::Function_Params &bvs,
const std::string &name,
const std::unique_ptr<Type_Info> &ti,
const Type_Conversions_State &t_conversions) const noexcept {
if (!bvs.empty()) {
return dynamic_object_typename_match(bvs[0], name, ti, 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;
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)");
* 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;
}
static std::vector<Type_Info> build_type_list(const std::vector<Type_Info> &tl)
{
auto begin = tl.begin();
auto end = tl.end();
return std::vector<Type_Info>(begin, end);
}
if (begin != end)
{
++begin;
}
bool operator==(const Proxy_Function_Base &f) const noexcept 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);
}
return std::vector<Type_Info>(begin, end);
}
bool call_match(const chaiscript::Function_Params &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());
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);
}
return m_func->call_match(chaiscript::Function_Params{new_vals}, t_conversions);
}
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());
protected:
Boxed_Value do_call(const chaiscript::Function_Params &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());
return m_func->call_match(new_vals, t_conversions);
}
(*m_func)(chaiscript::Function_Params{new_params}, 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;
return bv;
}
private:
const std::string m_type_name;
const Proxy_Function m_func;
};
}
}
}
} // namespace detail
} // namespace dispatch
} // namespace chaiscript
#endif

View File

@ -1,13 +1,12 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2018, 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_
@ -17,39 +16,28 @@
#include "boxed_cast.hpp"
namespace chaiscript {
class Boxed_Value;
namespace exception {
class bad_boxed_cast;
} // namespace exception
} // namespace chaiscript
namespace chaiscript
{
namespace detail
{
struct Exception_Handler_Base
{
namespace detail {
struct Exception_Handler_Base {
virtual void handle(const Boxed_Value &bv, const Dispatch_Engine &t_engine) = 0;
virtual ~Exception_Handler_Base() = default;
protected:
template<typename T>
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 &) {}
protected:
template<typename T>
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 ... T>
struct Exception_Handler_Impl : Exception_Handler_Base
{
void handle(const Boxed_Value &bv, const Dispatch_Engine &t_engine) override
{
(void)std::initializer_list<int>{(throw_type<T>(bv, t_engine), 0)...};
}
};
}
template<typename... T>
struct Exception_Handler_Impl : Exception_Handler_Base {
void handle(const Boxed_Value &bv, const Dispatch_Engine &t_engine) override { (throw_type<T>(bv, t_engine), ...); }
};
} // namespace detail
/// \brief Used in the automatic unboxing of exceptions thrown during script evaluation
///
@ -61,7 +49,8 @@ namespace chaiscript
/// chaiscript::ChaiScript chai;
///
/// try {
/// chai.eval("throw(runtime_error(\"error\"))", chaiscript::exception_specification<int, double, float, const std::string &, const std::exception &>());
/// chai.eval("throw(runtime_error(\"error\"))", chaiscript::exception_specification<int, double, float, const std::string &, const
/// std::exception &>());
/// } catch (const double e) {
/// } catch (int) {
/// } catch (float) {
@ -86,7 +75,7 @@ namespace chaiscript
///
/// Similarly, if you are using the ChaiScript::eval form that unboxes the return value, then chaiscript::exception::bad_boxed_cast
/// should be handled as well.
///
///
/// \code
/// try {
/// chai.eval<int>("1.0", chaiscript::exception_specification<const std::exception &>());
@ -101,17 +90,14 @@ namespace chaiscript
///
/// \sa chaiscript::exception_specification for creation of chaiscript::Exception_Handler objects
/// \sa \ref exceptions
typedef std::shared_ptr<detail::Exception_Handler_Base> Exception_Handler;
using Exception_Handler = std::shared_ptr<detail::Exception_Handler_Base>;
/// \brief creates a chaiscript::Exception_Handler which handles one type of exception unboxing
/// \sa \ref exceptions
template<typename ... T>
Exception_Handler exception_specification()
{
template<typename... T>
Exception_Handler exception_specification() {
return std::make_shared<detail::Exception_Handler_Impl<T...>>();
}
}
} // namespace chaiscript
#endif

View File

@ -1,13 +1,12 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2018, 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_
@ -18,20 +17,25 @@
#include "boxed_cast.hpp"
#include "function_call_detail.hpp"
#include "proxy_functions.hpp"
#include "callable_traits.hpp"
namespace chaiscript {
class Boxed_Value;
class Type_Conversions_State;
namespace detail {
template <typename T> struct Cast_Helper;
} // namespace detail
} // namespace chaiscript
class Boxed_Value;
class Type_Conversions_State;
namespace detail {
template<typename T>
struct Cast_Helper;
} // namespace detail
} // namespace chaiscript
namespace chaiscript {
namespace dispatch {
namespace detail {
template<typename Ret, typename... Param>
constexpr auto arity(Ret (*)(Param...)) noexcept {
return sizeof...(Param);
}
} // namespace detail
namespace chaiscript
{
namespace dispatch
{
/// Build a function caller that knows how to dispatch on a set of functions
/// example:
/// std::function<void (int)> f =
@ -39,21 +43,19 @@ namespace chaiscript
/// \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 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;
});
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()) == detail::arity(static_cast<FunctionType *>(nullptr));
});
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);
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
@ -66,67 +68,55 @@ namespace chaiscript
/// \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 Type_Conversions_State *t_conversions)
{
return functor<FunctionType>(std::vector<Const_Proxy_Function>({std::move(func)}), t_conversions);
}
std::function<FunctionType> functor(Const_Proxy_Function func, const Type_Conversions_State *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.
template<typename FunctionType>
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);
}
}
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 dispatch
namespace detail{
namespace detail {
/// Cast helper to handle automatic casting to const std::function &
template<typename Signature>
struct Cast_Helper<const std::function<Signature> &>
{
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>()))
{
return dispatch::functor<Signature>(ob, t_conversions);
} else {
return Cast_Helper_Inner<const std::function<Signature> &>::cast(ob, t_conversions);
}
struct Cast_Helper<const std::function<Signature> &> {
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>())) {
return dispatch::functor<Signature>(ob, t_conversions);
} else {
return Cast_Helper_Inner<const std::function<Signature> &>::cast(ob, t_conversions);
}
};
}
};
/// Cast helper to handle automatic casting to std::function
template<typename Signature>
struct Cast_Helper<std::function<Signature> >
{
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>()))
{
return dispatch::functor<Signature>(ob, t_conversions);
} else {
return Cast_Helper_Inner<std::function<Signature> >::cast(ob, t_conversions);
}
struct Cast_Helper<std::function<Signature>> {
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>())) {
return dispatch::functor<Signature>(ob, t_conversions);
} else {
return Cast_Helper_Inner<std::function<Signature>>::cast(ob, t_conversions);
}
};
}
};
/// Cast helper to handle automatic casting to const std::function
template<typename Signature>
struct Cast_Helper<const std::function<Signature> >
{
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>()))
{
return dispatch::functor<Signature>(ob, t_conversions);
} else {
return Cast_Helper_Inner<const std::function<Signature> >::cast(ob, t_conversions);
}
struct Cast_Helper<const std::function<Signature>> {
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>())) {
return dispatch::functor<Signature>(ob, t_conversions);
} else {
return Cast_Helper_Inner<const std::function<Signature>>::cast(ob, t_conversions);
}
};
}
}
}
};
} // namespace detail
} // namespace chaiscript
#endif

View File

@ -1,13 +1,12 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2018, 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_
@ -20,152 +19,79 @@
#include "boxed_cast.hpp"
#include "boxed_number.hpp"
#include "boxed_value.hpp"
#include "type_conversions.hpp"
#include "proxy_functions.hpp"
#include "type_conversions.hpp"
namespace chaiscript
{
namespace dispatch
{
namespace detail
{
/// 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 Type_Conversions_State *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);
}
}
};
/**
* Specialization for arithmetic return types
*/
template<typename Ret>
struct Function_Caller_Ret<Ret, true>
{
static Ret call(const std::vector<Const_Proxy_Function> &t_funcs,
const std::vector<Boxed_Value> &params, const Type_Conversions_State *t_conversions)
{
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>();
}
}
};
/**
* Specialization for void return types
*/
template<>
struct Function_Caller_Ret<void, false>
{
static void call(const std::vector<Const_Proxy_Function> &t_funcs,
const std::vector<Boxed_Value> &params, const Type_Conversions_State *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);
}
}
};
/**
* used internally for unwrapping a function call's types
*/
template<typename Ret, typename ... Param>
struct Build_Function_Caller_Helper
{
Build_Function_Caller_Helper(std::vector<Const_Proxy_Function> t_funcs, const Type_Conversions *t_conversions)
: m_funcs(std::move(t_funcs)),
m_conversions(t_conversions)
{
}
template<typename ... P>
Ret operator()(P&& ... param)
{
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;
const Type_Conversions *m_conversions;
};
/// \todo what happens if t_conversions is deleted out from under us?!
template<typename Ret, typename ... Params>
std::function<Ret (Params...)> build_function_caller_helper(Ret (Params...), const std::vector<Const_Proxy_Function> &funcs, const Type_Conversions_State *t_conversions)
{
/*
if (funcs.size() == 1)
{
std::shared_ptr<const Proxy_Function_Impl<Ret (Params...)>> pfi =
std::dynamic_pointer_cast<const Proxy_Function_Impl<Ret (Params...)> >
(funcs[0]);
if (pfi)
{
return pfi->internal_function();
}
// 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->get():nullptr));
}
namespace chaiscript::dispatch::detail {
/// used internally for unwrapping a function call's types
template<typename Ret, typename... Param>
struct Build_Function_Caller_Helper {
Build_Function_Caller_Helper(std::vector<Const_Proxy_Function> t_funcs, const Type_Conversions *t_conversions)
: m_funcs(std::move(t_funcs))
, m_conversions(t_conversions) {
}
Ret call(const chaiscript::Function_Params &params, const Type_Conversions_State &t_state) {
if constexpr (std::is_arithmetic_v<Ret> && !std::is_same_v<std::remove_cv_t<std::remove_reference_t<Ret>>, bool>) {
return Boxed_Number(dispatch::dispatch(m_funcs, params, t_state)).get_as<Ret>();
} else if constexpr (std::is_same_v<void, Ret>) {
dispatch::dispatch(m_funcs, params, t_state);
} else {
return boxed_cast<Ret>(dispatch::dispatch(m_funcs, params, t_state), &t_state);
}
}
template<typename... P>
Ret operator()(P &&...param) {
std::array<Boxed_Value, sizeof...(P)> params{box<P>(std::forward<P>(param))...};
if (m_conversions) {
Type_Conversions_State state(*m_conversions, m_conversions->conversion_saves());
return call(chaiscript::Function_Params{params}, state);
} else {
Type_Conversions conv;
Type_Conversions_State state(conv, conv.conversion_saves());
return call(chaiscript::Function_Params{params}, state);
}
}
template<typename P, typename Q>
static Boxed_Value box(Q &&q) {
if constexpr (std::is_same_v<chaiscript::Boxed_Value, std::decay_t<Q>>) {
return std::forward<Q>(q);
} else if constexpr (std::is_reference_v<P>) {
return Boxed_Value(std::ref(std::forward<Q>(q)));
} else {
return Boxed_Value(std::forward<Q>(q));
}
}
std::vector<Const_Proxy_Function> m_funcs;
const Type_Conversions *m_conversions;
};
/// \todo what happens if t_conversions is deleted out from under us?!
template<typename Ret, typename... Params>
std::function<Ret(Params...)>
build_function_caller_helper(Ret(Params...), const std::vector<Const_Proxy_Function> &funcs, const Type_Conversions_State *t_conversions) {
/*
if (funcs.size() == 1)
{
std::shared_ptr<const Proxy_Function_Impl<Ret (Params...)>> pfi =
std::dynamic_pointer_cast<const Proxy_Function_Impl<Ret (Params...)> >
(funcs[0]);
if (pfi)
{
return pfi->internal_function();
}
// 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->get() : nullptr));
}
}
} // namespace chaiscript::dispatch::detail
#endif

View File

@ -0,0 +1,67 @@
// 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_FUNCTION_PARAMS_HPP
#define CHAISCRIPT_FUNCTION_PARAMS_HPP
#include "boxed_value.hpp"
namespace chaiscript {
class Function_Params {
public:
constexpr Function_Params(const Boxed_Value *const t_begin, const Boxed_Value *const t_end)
: m_begin(t_begin)
, m_end(t_end) {
}
explicit Function_Params(const Boxed_Value &bv)
: m_begin(&bv)
, m_end(m_begin + 1) {
}
explicit Function_Params(const std::vector<Boxed_Value> &vec)
: m_begin(vec.empty() ? nullptr : &vec.front())
, m_end(vec.empty() ? nullptr : &vec.front() + vec.size()) {
}
template<size_t Size>
constexpr explicit Function_Params(const std::array<Boxed_Value, Size> &a)
: m_begin(&a.front())
, m_end(&a.front() + Size) {
}
[[nodiscard]] constexpr const Boxed_Value &operator[](const std::size_t t_i) const noexcept { return m_begin[t_i]; }
[[nodiscard]] constexpr const Boxed_Value *begin() const noexcept { return m_begin; }
[[nodiscard]] constexpr const Boxed_Value &front() const noexcept { return *m_begin; }
[[nodiscard]] constexpr const Boxed_Value *end() const noexcept { return m_end; }
[[nodiscard]] constexpr std::size_t size() const noexcept { return std::size_t(m_end - m_begin); }
[[nodiscard]] std::vector<Boxed_Value> to_vector() const { return std::vector<Boxed_Value>{m_begin, m_end}; }
[[nodiscard]] constexpr bool empty() const noexcept { return m_begin == m_end; }
private:
const Boxed_Value *m_begin = nullptr;
const Boxed_Value *m_end = nullptr;
};
// Constructor specialization for array of size 0
template<>
constexpr Function_Params::Function_Params(const std::array<Boxed_Value, size_t{0}> & /* a */)
: m_begin(nullptr)
, m_end(nullptr) {
}
} // namespace chaiscript
#endif

View File

@ -0,0 +1,149 @@
#ifndef CHAISCRIPT_FUNCTION_SIGNATURE_HPP
#define CHAISCRIPT_FUNCTION_SIGNATURE_HPP
#include <type_traits>
namespace chaiscript::dispatch::detail {
template<typename... Param>
struct Function_Params {
};
template<typename Ret, typename Params, bool IsNoExcept = false, bool IsMember = false, bool IsMemberObject = false, bool IsObject = false>
struct Function_Signature {
using Param_Types = Params;
using Return_Type = Ret;
constexpr static const bool is_object = IsObject;
constexpr static const bool is_member_object = IsMemberObject;
constexpr static const bool is_noexcept = IsNoExcept;
template<typename T>
constexpr Function_Signature(T &&) noexcept {
}
constexpr Function_Signature() noexcept = default;
};
// Free functions
template<typename Ret, typename... Param>
Function_Signature(Ret (*f)(Param...)) -> Function_Signature<Ret, Function_Params<Param...>>;
template<typename Ret, typename... Param>
Function_Signature(Ret (*f)(Param...) noexcept) -> Function_Signature<Ret, Function_Params<Param...>, true>;
// no reference specifier
template<typename Ret, typename Class, typename... Param>
Function_Signature(Ret (Class::*f)(Param...) volatile) -> Function_Signature<Ret, Function_Params<volatile Class &, Param...>, false, true>;
template<typename Ret, typename Class, typename... Param>
Function_Signature(Ret (Class::*f)(Param...) volatile noexcept)
-> Function_Signature<Ret, Function_Params<volatile Class &, Param...>, true, true>;
template<typename Ret, typename Class, typename... Param>
Function_Signature(Ret (Class::*f)(Param...) volatile const)
-> Function_Signature<Ret, Function_Params<volatile const Class &, Param...>, false, true>;
template<typename Ret, typename Class, typename... Param>
Function_Signature(Ret (Class::*f)(Param...) volatile const noexcept)
-> Function_Signature<Ret, Function_Params<volatile const Class &, Param...>, true, true>;
template<typename Ret, typename Class, typename... Param>
Function_Signature(Ret (Class::*f)(Param...)) -> Function_Signature<Ret, Function_Params<Class &, Param...>, false, true>;
template<typename Ret, typename Class, typename... Param>
Function_Signature(Ret (Class::*f)(Param...) noexcept) -> Function_Signature<Ret, Function_Params<Class &, Param...>, true, true>;
template<typename Ret, typename Class, typename... Param>
Function_Signature(Ret (Class::*f)(Param...) const) -> Function_Signature<Ret, Function_Params<const Class &, Param...>, false, true>;
template<typename Ret, typename Class, typename... Param>
Function_Signature(Ret (Class::*f)(Param...) const noexcept) -> Function_Signature<Ret, Function_Params<const Class &, Param...>, true, true>;
// & reference specifier
template<typename Ret, typename Class, typename... Param>
Function_Signature(Ret (Class::*f)(Param...) volatile &) -> Function_Signature<Ret, Function_Params<volatile Class &, Param...>, false, true>;
template<typename Ret, typename Class, typename... Param>
Function_Signature(Ret (Class::*f)(Param...) volatile &noexcept)
-> Function_Signature<Ret, Function_Params<volatile Class &, Param...>, true, true>;
template<typename Ret, typename Class, typename... Param>
Function_Signature(Ret (Class::*f)(Param...) volatile const &)
-> Function_Signature<Ret, Function_Params<volatile const Class &, Param...>, false, true>;
template<typename Ret, typename Class, typename... Param>
Function_Signature(Ret (Class::*f)(Param...) volatile const &noexcept)
-> Function_Signature<Ret, Function_Params<volatile const Class &, Param...>, true, true>;
template<typename Ret, typename Class, typename... Param>
Function_Signature(Ret (Class::*f)(Param...) &) -> Function_Signature<Ret, Function_Params<Class &, Param...>, false, true>;
template<typename Ret, typename Class, typename... Param>
Function_Signature(Ret (Class::*f)(Param...) &noexcept) -> Function_Signature<Ret, Function_Params<Class &, Param...>, true, true>;
template<typename Ret, typename Class, typename... Param>
Function_Signature(Ret (Class::*f)(Param...) const &) -> Function_Signature<Ret, Function_Params<const Class &, Param...>, false, true>;
template<typename Ret, typename Class, typename... Param>
Function_Signature(Ret (Class::*f)(Param...) const &noexcept) -> Function_Signature<Ret, Function_Params<const Class &, Param...>, true, true>;
// && reference specifier
template<typename Ret, typename Class, typename... Param>
Function_Signature(Ret (Class::*f)(Param...) volatile &&) -> Function_Signature<Ret, Function_Params<volatile Class &&, Param...>, false, true>;
template<typename Ret, typename Class, typename... Param>
Function_Signature(Ret (Class::*f)(Param...) volatile &&noexcept)
-> Function_Signature<Ret, Function_Params<volatile Class &&, Param...>, true, true>;
template<typename Ret, typename Class, typename... Param>
Function_Signature(Ret (Class::*f)(Param...) volatile const &&)
-> Function_Signature<Ret, Function_Params<volatile const Class &&, Param...>, false, true>;
template<typename Ret, typename Class, typename... Param>
Function_Signature(Ret (Class::*f)(Param...) volatile const &&noexcept)
-> Function_Signature<Ret, Function_Params<volatile const Class &&, Param...>, true, true>;
template<typename Ret, typename Class, typename... Param>
Function_Signature(Ret (Class::*f)(Param...) &&) -> Function_Signature<Ret, Function_Params<Class &&, Param...>, false, true>;
template<typename Ret, typename Class, typename... Param>
Function_Signature(Ret (Class::*f)(Param...) &&noexcept) -> Function_Signature<Ret, Function_Params<Class &&, Param...>, true, true>;
template<typename Ret, typename Class, typename... Param>
Function_Signature(Ret (Class::*f)(Param...) const &&) -> Function_Signature<Ret, Function_Params<const Class &&, Param...>, false, true>;
template<typename Ret, typename Class, typename... Param>
Function_Signature(Ret (Class::*f)(Param...) const &&noexcept)
-> Function_Signature<Ret, Function_Params<const Class &&, Param...>, true, true>;
template<typename Ret, typename Class>
Function_Signature(Ret Class::*f) -> Function_Signature<Ret, Function_Params<Class &>, true, true, true>;
// primary template handles types that have no nested ::type member:
template<class, class = std::void_t<>>
struct has_call_operator : std::false_type {
};
// specialization recognizes types that do have a nested ::type member:
template<class T>
struct has_call_operator<T, std::void_t<decltype(&T::operator())>> : std::true_type {
};
template<typename Func>
auto function_signature(const Func &f) {
if constexpr (has_call_operator<Func>::value) {
return Function_Signature<typename decltype(Function_Signature{&std::decay_t<Func>::operator()})::Return_Type,
typename decltype(Function_Signature{&std::decay_t<Func>::operator()})::Param_Types,
decltype(Function_Signature{&std::decay_t<Func>::operator()})::is_noexcept,
false,
false,
true>{};
} else {
return Function_Signature{f};
}
}
} // namespace chaiscript::dispatch::detail
#endif

View File

@ -1,13 +1,12 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2018, 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_
@ -19,238 +18,178 @@
#include "boxed_value.hpp"
namespace chaiscript {
class Boxed_Number;
} // namespace chaiscript
class Boxed_Number;
} // namespace chaiscript
namespace chaiscript
{
namespace dispatch
{
template<class T, class U> class Proxy_Function_Callable_Impl;
template<class T> class Assignable_Proxy_Function_Impl;
namespace chaiscript {
namespace dispatch {
template<class T, class U>
class Proxy_Function_Callable_Impl;
template<class T>
class Assignable_Proxy_Function_Impl;
namespace detail
{
namespace detail {
/// Used internally for handling a return value from a Proxy_Function call
template<typename Ret>
struct Handle_Return
{
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::move(r), true);
}
struct Handle_Return {
template<typename T, typename = typename std::enable_if_t<std::is_trivial_v<typename std::decay_t<T>>>>
static Boxed_Value handle(T 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 T, typename = typename std::enable_if_t<!(std::is_trivial_v<typename std::decay_t<T>>)>>
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)
);
}
};
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> &>
{
};
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)
);
}
};
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>>>
{
};
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>>>
{
};
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>>())
);
}
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)
);
}
};
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);
}
};
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);
}
};
struct Handle_Return<const Ret *&> {
static Boxed_Value handle(const Ret *p) { return Boxed_Value(p, true); }
};
template<typename Ret>
struct Handle_Return<Ret *>
{
static Boxed_Value handle(Ret *p)
{
return Boxed_Value(p, true);
}
};
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);
}
};
struct Handle_Return<const Ret *> {
static Boxed_Value handle(const Ret *p) { return Boxed_Value(p, true); }
};
template<typename Ret>
struct Handle_Return<std::shared_ptr<Ret> &>
{
static Boxed_Value handle(const std::shared_ptr<Ret> &r)
{
return Boxed_Value(r, true);
}
};
struct Handle_Return<std::shared_ptr<Ret> &> {
static Boxed_Value handle(const std::shared_ptr<Ret> &r) { return Boxed_Value(r, true); }
};
template<typename Ret>
struct Handle_Return<std::shared_ptr<Ret>> : Handle_Return<std::shared_ptr<Ret> &>
{
};
struct Handle_Return<std::shared_ptr<Ret>> : Handle_Return<std::shared_ptr<Ret> &> {
};
template<typename Ret>
struct Handle_Return<const std::shared_ptr<Ret> &> : Handle_Return<std::shared_ptr<Ret> &>
{
};
struct Handle_Return<const std::shared_ptr<Ret> &> : Handle_Return<std::shared_ptr<Ret> &> {
};
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(std::move(r), true);
}
};
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(std::move(r), true); }
};
template<typename Ret, bool Ptr>
struct Handle_Return_Ref {
template<typename T>
static Boxed_Value handle(T &&r) {
return Boxed_Value(std::cref(r), true);
}
};
template<typename Ret>
struct Handle_Return<const Ret &>
{
static Boxed_Value handle(const Ret &r)
{
return Boxed_Value(std::cref(r), true);
}
};
struct Handle_Return_Ref<Ret, true> {
template<typename T>
static Boxed_Value handle(T &&r) {
return Boxed_Value(typename std::remove_reference<decltype(r)>::type{r}, true);
}
};
template<typename Ret>
struct Handle_Return<const Ret>
{
static Boxed_Value handle(const Ret &r)
{
return Boxed_Value(std::cref(r));
}
};
struct Handle_Return<const Ret &> : Handle_Return_Ref<const Ret &, std::is_pointer<typename std::remove_reference<const Ret &>::type>::value> {
};
template<typename Ret>
struct Handle_Return<Ret &>
{
static Boxed_Value handle(Ret &r)
{
return Boxed_Value(std::ref(r));
}
};
struct Handle_Return<const Ret> {
static Boxed_Value handle(Ret r) { return Boxed_Value(std::move(r)); }
};
template<typename Ret>
struct Handle_Return<Ret &> {
static Boxed_Value handle(Ret &r) { return Boxed_Value(std::ref(r)); }
};
template<>
struct Handle_Return<Boxed_Value>
{
static Boxed_Value handle(const Boxed_Value &r)
{
return r;
}
};
struct Handle_Return<Boxed_Value> {
static Boxed_Value handle(const Boxed_Value &r) noexcept { return r; }
};
template<>
struct Handle_Return<const Boxed_Value> : Handle_Return<Boxed_Value>
{
};
struct Handle_Return<const Boxed_Value> : Handle_Return<Boxed_Value> {
};
template<>
struct Handle_Return<Boxed_Value &> : Handle_Return<Boxed_Value>
{
};
struct Handle_Return<Boxed_Value &> : Handle_Return<Boxed_Value> {
};
template<>
struct Handle_Return<const Boxed_Value &> : Handle_Return<Boxed_Value>
{
};
struct Handle_Return<const Boxed_Value &> : Handle_Return<Boxed_Value> {
};
/**
* 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<>
struct Handle_Return<Boxed_Number>
{
static Boxed_Value handle(const Boxed_Number &r)
{
return r.bv;
}
};
struct Handle_Return<Boxed_Number> {
static Boxed_Value handle(const Boxed_Number &r) noexcept { return r.bv; }
};
template<>
struct Handle_Return<const Boxed_Number> : Handle_Return<Boxed_Number>
{
};
struct Handle_Return<const Boxed_Number> : Handle_Return<Boxed_Number> {
};
/**
* 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<>
struct Handle_Return<void>
{
static Boxed_Value handle()
{
return void_var();
}
};
}
}
}
struct Handle_Return<void> {
static Boxed_Value handle() { return void_var(); }
};
} // namespace detail
} // namespace dispatch
} // namespace chaiscript
#endif

View File

@ -1,224 +1,184 @@
// 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)
// Copyright 2009-2018, 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_
#include "../chaiscript_defines.hpp"
#include "../dispatchkit/dispatchkit.hpp"
#include "register_function.hpp"
namespace chaiscript
{
namespace bootstrap
{
namespace operators
{
template<typename T>
void assign(Module& m)
{
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs = rhs;}), "=");
}
template<typename T>
void assign_bitwise_and(Module& m)
{
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs &= rhs;}), "&=");
}
template<typename T>
void assign_xor(Module& m)
{
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs ^= rhs;}), "^=");
}
template<typename T>
void assign_bitwise_or(Module& m)
{
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs |= rhs;}), "|=");
}
template<typename T>
void assign_difference(Module& m)
{
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs -= rhs;}), "-=");
}
template<typename T>
void assign_left_shift(Module& m)
{
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs <<= rhs;}), "<<=");
}
template<typename T>
void assign_product(Module& m)
{
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs <<= rhs;}), "*=");
}
template<typename T>
void assign_quotient(Module& m)
{
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs /= rhs;}), "/=");
}
template<typename T>
void assign_remainder(Module& m)
{
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs %= rhs;}), "%=");
}
template<typename T>
void assign_right_shift(Module& m)
{
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs >>= rhs;}), ">>=");
}
template<typename T>
void assign_sum(Module& m)
{
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs += rhs;}), "+=");
}
template<typename T>
void prefix_decrement(Module& m)
{
m.add(chaiscript::fun([](T &lhs)->T&{return --lhs;}), "--");
}
template<typename T>
void prefix_increment(Module& m)
{
m.add(chaiscript::fun([](T &lhs)->T&{return ++lhs;}), "++");
}
template<typename T>
void equal(Module& m)
{
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs==rhs;}), "==");
}
template<typename T>
void greater_than(Module& m)
{
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs>rhs;}), ">");
}
template<typename T>
void greater_than_equal(Module& m)
{
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs>=rhs;}), ">=");
}
template<typename T>
void less_than(Module& m)
{
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs<rhs;}), "<");
}
template<typename T>
void less_than_equal(Module& m)
{
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs<=rhs;}), "<=");
}
template<typename T>
void logical_compliment(Module& m)
{
m.add(chaiscript::fun([](const T &lhs){return !lhs;}), "!");
}
template<typename T>
void not_equal(Module& m)
{
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs!=rhs;}), "!=");
}
template<typename T>
void addition(Module& m)
{
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs+rhs;}), "+");
}
template<typename T>
void unary_plus(Module& m)
{
m.add(chaiscript::fun([](const T &lhs){return +lhs;}), "+");
}
template<typename T>
void subtraction(Module& m)
{
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs-rhs;}), "-");
}
template<typename T>
void unary_minus(Module& m)
{
m.add(chaiscript::fun([](const T &lhs){return -lhs;}), "-");
}
template<typename T>
void bitwise_and(Module& m)
{
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs&rhs;}), "&");
}
template<typename T>
void bitwise_compliment(Module& m)
{
m.add(chaiscript::fun([](const T &lhs){return ~lhs;}), "~");
}
template<typename T>
void bitwise_xor(Module& m)
{
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs^rhs;}), "^");
}
template<typename T>
void bitwise_or(Module& m)
{
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs|rhs;}), "|");
}
template<typename T>
void division(Module& m)
{
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs/rhs;}), "/");
}
template<typename T>
void left_shift(Module& m)
{
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs<<rhs;}), "<<");
}
template<typename T>
void multiplication(Module& m)
{
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs*rhs;}), "*");
}
template<typename T>
void remainder(Module& m)
{
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs%rhs;}), "%");
}
template<typename T>
void right_shift(Module& m)
{
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs>>rhs;}), ">>");
}
}
namespace chaiscript::bootstrap::operators {
template<typename T>
void assign(Module &m) {
m.add(chaiscript::fun([](T &lhs, const T &rhs) -> T & { return lhs = rhs; }), "=");
}
}
template<typename T>
void assign_bitwise_and(Module &m) {
m.add(chaiscript::fun([](T &lhs, const T &rhs) -> T & { return lhs &= rhs; }), "&=");
}
template<typename T>
void assign_xor(Module &m) {
m.add(chaiscript::fun([](T &lhs, const T &rhs) -> T & { return lhs ^= rhs; }), "^=");
}
template<typename T>
void assign_bitwise_or(Module &m) {
m.add(chaiscript::fun([](T &lhs, const T &rhs) -> T & { return lhs |= rhs; }), "|=");
}
template<typename T>
void assign_difference(Module &m) {
m.add(chaiscript::fun([](T &lhs, const T &rhs) -> T & { return lhs -= rhs; }), "-=");
}
template<typename T>
void assign_left_shift(Module &m) {
m.add(chaiscript::fun([](T &lhs, const T &rhs) -> T & { return lhs <<= rhs; }), "<<=");
}
template<typename T>
void assign_product(Module &m) {
m.add(chaiscript::fun([](T &lhs, const T &rhs) -> T & { return lhs <<= rhs; }), "*=");
}
template<typename T>
void assign_quotient(Module &m) {
m.add(chaiscript::fun([](T &lhs, const T &rhs) -> T & { return lhs /= rhs; }), "/=");
}
template<typename T>
void assign_remainder(Module &m) {
m.add(chaiscript::fun([](T &lhs, const T &rhs) -> T & { return lhs %= rhs; }), "%=");
}
template<typename T>
void assign_right_shift(Module &m) {
m.add(chaiscript::fun([](T &lhs, const T &rhs) -> T & { return lhs >>= rhs; }), ">>=");
}
template<typename T>
void assign_sum(Module &m) {
m.add(chaiscript::fun([](T &lhs, const T &rhs) -> T & { return lhs += rhs; }), "+=");
}
template<typename T>
void prefix_decrement(Module &m) {
m.add(chaiscript::fun([](T &lhs) -> T & { return --lhs; }), "--");
}
template<typename T>
void prefix_increment(Module &m) {
m.add(chaiscript::fun([](T &lhs) -> T & { return ++lhs; }), "++");
}
template<typename T>
void equal(Module &m) {
m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs == rhs; }), "==");
}
template<typename T>
void greater_than(Module &m) {
m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs > rhs; }), ">");
}
template<typename T>
void greater_than_equal(Module &m) {
m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs >= rhs; }), ">=");
}
template<typename T>
void less_than(Module &m) {
m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs < rhs; }), "<");
}
template<typename T>
void less_than_equal(Module &m) {
m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs <= rhs; }), "<=");
}
template<typename T>
void logical_compliment(Module &m) {
m.add(chaiscript::fun([](const T &lhs) { return !lhs; }), "!");
}
template<typename T>
void not_equal(Module &m) {
m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs != rhs; }), "!=");
}
template<typename T>
void addition(Module &m) {
m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs + rhs; }), "+");
}
template<typename T>
void unary_plus(Module &m) {
m.add(chaiscript::fun([](const T &lhs) { return +lhs; }), "+");
}
template<typename T>
void subtraction(Module &m) {
m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs - rhs; }), "-");
}
template<typename T>
void unary_minus(Module &m) {
m.add(chaiscript::fun([](const T &lhs) { return -lhs; }), "-");
}
template<typename T>
void bitwise_and(Module &m) {
m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs & rhs; }), "&");
}
template<typename T>
void bitwise_compliment(Module &m) {
m.add(chaiscript::fun([](const T &lhs) { return ~lhs; }), "~");
}
template<typename T>
void bitwise_xor(Module &m) {
m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs ^ rhs; }), "^");
}
template<typename T>
void bitwise_or(Module &m) {
m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs | rhs; }), "|");
}
template<typename T>
void division(Module &m) {
m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs / rhs; }), "/");
}
template<typename T>
void left_shift(Module &m) {
m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs << rhs; }), "<<");
}
template<typename T>
void multiplication(Module &m) {
m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs * rhs; }), "*");
}
template<typename T>
void remainder(Module &m) {
m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs % rhs; }), "%");
}
template<typename T>
void right_shift(Module &m) {
m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs >> rhs; }), ">>");
}
} // namespace chaiscript::bootstrap::operators
#endif

View File

@ -1,41 +1,41 @@
// 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)
// Copyright 2009-2018, 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
{
namespace chaiscript::dispatch::detail {
template<typename Class, typename... Params>
Proxy_Function build_constructor_(Class (*)(Params...)) {
if constexpr (!std::is_copy_constructible_v<Class>) {
auto call = [](auto &&...param) { return std::make_shared<Class>(std::forward<decltype(param)>(param)...); };
template<typename Class, typename ... Params >
Proxy_Function build_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));
} else if constexpr (true) {
auto call = [](auto &&...param) { return Class(std::forward<decltype(param)>(param)...); };
return Proxy_Function(
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<std::shared_ptr<Class> (Params...), decltype(call)>>(call));
}
return Proxy_Function(
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Class(Params...), decltype(call)>>(
call));
}
}
} // namespace chaiscript::dispatch::detail
namespace chaiscript {
/// \brief Generates a constructor function for use with ChaiScript
///
///
/// \tparam T The signature of the constructor to generate. In the form of: ClassType (ParamType1, ParamType2, ...)
///
///
/// Example:
/// \code
/// chaiscript::ChaiScript chai;
@ -44,13 +44,10 @@ namespace chaiscript
/// chai.add(constructor<MyClass (int, float)>(), "MyClass");
/// \endcode
template<typename T>
Proxy_Function constructor()
{
T *f = nullptr;
return (dispatch::detail::build_constructor_(f));
}
}
Proxy_Function constructor() {
T *f = nullptr;
return (dispatch::detail::build_constructor_(f));
}
} // namespace chaiscript
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,49 +1,45 @@
// 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)
// Copyright 2009-2018, 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 <array>
#include <functional>
#include <stdexcept>
#include <vector>
#include <array>
#include "../chaiscript_defines.hpp"
#include "boxed_cast.hpp"
#include "boxed_value.hpp"
#include "function_params.hpp"
#include "handle_return.hpp"
#include "type_info.hpp"
#include "callable_traits.hpp"
namespace chaiscript {
class Type_Conversions_State;
namespace exception {
class bad_boxed_cast;
} // namespace exception
} // namespace chaiscript
class Type_Conversions_State;
namespace exception {
class bad_boxed_cast;
} // namespace exception
} // namespace chaiscript
namespace chaiscript
{
namespace exception
{
namespace chaiscript {
namespace exception {
/**
* Exception thrown when there is a mismatch in number of
* parameters during Proxy_Function execution
*/
struct arity_error : std::range_error
{
* Exception thrown when there is a mismatch in number of
* parameters during Proxy_Function execution
*/
struct arity_error : std::range_error {
arity_error(int t_got, int t_expected)
: std::range_error("Function dispatch arity mismatch"),
got(t_got), expected(t_expected)
{
: std::range_error("Function dispatch arity mismatch")
, got(t_got)
, expected(t_expected) {
}
arity_error(const arity_error &) = default;
@ -53,87 +49,63 @@ namespace chaiscript
int got;
int expected;
};
}
} // namespace exception
namespace dispatch
{
namespace detail
{
namespace dispatch {
namespace detail {
/**
* Used by Proxy_Function_Impl to return a list of all param types
* it contains.
*/
template<typename Ret, typename ... Params>
std::vector<Type_Info> build_param_type_list(Ret (*)(Params...))
{
/// \note somehow this is responsible for a large part of the code generation
return { user_type<Ret>(), user_type<Params>()... };
}
* Used by Proxy_Function_Impl to return a list of all param types
* it contains.
*/
template<typename Ret, typename... Params>
std::vector<Type_Info> build_param_type_list(Ret (*)(Params...)) {
/// \note somehow this is responsible for a large part of the code generation
return {user_type<Ret>(), user_type<Params>()...};
}
/**
* Used by Proxy_Function_Impl to determine if it is equivalent to another
* Proxy_Function_Impl object. This function is primarily used to prevent
* registration of two functions with the exact same signatures
*/
template<typename Ret, typename ... Params>
bool compare_types_cast(Ret (*)(Params...),
const std::vector<Boxed_Value> &params, const Type_Conversions_State &t_conversions)
{
try {
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;
}
}
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 determine if it is equivalent to another
* Proxy_Function_Impl object. This function is primarily used to prevent
* registration of two functions with the exact same signatures
*/
template<typename Ret, typename... Params>
bool compare_types_cast(Ret (*)(Params...), const chaiscript::Function_Params &params, const Type_Conversions_State &t_conversions) noexcept {
try {
std::vector<Boxed_Value>::size_type i = 0;
(boxed_cast<Params>(params[i++], &t_conversions), ...);
return true;
} catch (const exception::bad_boxed_cast &) {
return false;
}
}
template<typename Callable, typename Ret, typename... Params, size_t... I>
Ret call_func(Ret (*)(Params...),
std::index_sequence<I...>,
const Callable &f,
[[maybe_unused]] const chaiscript::Function_Params &params,
[[maybe_unused]] const Type_Conversions_State &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)
{
template<typename Callable, typename Ret, typename... Params>
Boxed_Value
call_func(Ret (*sig)(Params...), const Callable &f, const chaiscript::Function_Params &params, const Type_Conversions_State &t_conversions) {
if constexpr (std::is_same_v<Ret, void>) {
call_func(sig, std::index_sequence_for<Params...>{}, f, params, t_conversions);
return Handle_Return<void>::handle();
} else {
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 : 4702)
#endif
// MSVC is reporting that this is unreachable code - and it's wrong.
return Handle_Return<void>::handle();
#ifdef CHAISCRIPT_MSVC
#pragma warning(pop)
#endif
}
}
}
}
} // namespace detail
} // namespace dispatch
} // namespace chaiscript
#endif

View File

@ -1,23 +1,61 @@
// 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)
// Copyright 2009-2018, 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 <type_traits>
#include "bind_first.hpp"
#include "function_signature.hpp"
#include "proxy_functions.hpp"
namespace chaiscript
{
namespace chaiscript {
namespace dispatch::detail {
template<typename Obj, typename Param1, typename... Rest>
Param1 get_first_param(Function_Params<Param1, Rest...>, Obj &&obj) {
return static_cast<Param1>(std::forward<Obj>(obj));
}
template<typename Func, bool Is_Noexcept, bool Is_Member, bool Is_MemberObject, bool Is_Object, typename Ret, typename... Param>
auto make_callable_impl(Func &&func, Function_Signature<Ret, Function_Params<Param...>, Is_Noexcept, Is_Member, Is_MemberObject, Is_Object>) {
if constexpr (Is_MemberObject) {
// we now that the Param pack will have only one element, so we are safe expanding it here
return Proxy_Function(chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Attribute_Access<Ret, std::decay_t<Param>...>>(
std::forward<Func>(func)));
} else if constexpr (Is_Member) {
// TODO some kind of bug is preventing forwarding of this noexcept for the lambda
auto call = [func = std::forward<Func>(func)](auto &&obj, auto &&...param) /* noexcept(Is_Noexcept) */ -> decltype(auto) {
return ((get_first_param(Function_Params<Param...>{}, obj).*func)(std::forward<decltype(param)>(param)...));
};
return Proxy_Function(
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Ret(Param...), decltype(call)>>(
std::move(call)));
} else {
return Proxy_Function(
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Ret(Param...), std::decay_t<Func>>>(
std::forward<Func>(func)));
}
}
// this version peels off the function object itself from the function signature, when used
// on a callable object
template<typename Func, typename Ret, typename Object, typename... Param, bool Is_Noexcept>
auto make_callable(Func &&func, Function_Signature<Ret, Function_Params<Object, Param...>, Is_Noexcept, false, false, true>) {
return make_callable_impl(std::forward<Func>(func), Function_Signature<Ret, Function_Params<Param...>, Is_Noexcept, false, false, true>{});
}
template<typename Func, typename Ret, typename... Param, bool Is_Noexcept, bool Is_Member, bool Is_MemberObject>
auto make_callable(Func &&func, Function_Signature<Ret, Function_Params<Param...>, Is_Noexcept, Is_Member, Is_MemberObject, false> fs) {
return make_callable_impl(std::forward<Func>(func), fs);
}
} // namespace dispatch::detail
/// \brief Creates a new Proxy_Function object from a free function, member function or data member
/// \param[in] t Function / member to expose
@ -31,62 +69,19 @@ namespace chaiscript
/// void memberfunction();
/// int memberdata;
/// };
///
///
/// chaiscript::ChaiScript chai;
/// chai.add(fun(&myfunction), "myfunction");
/// chai.add(fun(&MyClass::memberfunction), "memberfunction");
/// chai.add(fun(&MyClass::memberdata), "memberdata");
/// \endcode
///
///
/// \sa \ref adding_functions
template<typename T>
Proxy_Function fun(const T &t)
{
typedef typename dispatch::detail::Callable_Traits<T>::Signature Signature;
Proxy_Function fun(T &&t) {
return dispatch::detail::make_callable(std::forward<T>(t), dispatch::detail::function_signature(t));
}
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));
}
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(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
/// \param[in] q Value to bind to first parameter
@ -97,23 +92,19 @@ namespace chaiscript
/// {
/// void memberfunction(int);
/// };
///
///
/// MyClass obj;
/// chaiscript::ChaiScript chai;
/// // Add function taking only one argument, an int, and permanently bound to "obj"
/// chai.add(fun(&MyClass::memberfunction, std::ref(obj)), "memberfunction");
/// chai.add(fun(&MyClass::memberfunction, std::ref(obj)), "memberfunction");
/// \endcode
///
///
/// \sa \ref adding_functions
template<typename T, typename Q>
Proxy_Function fun(T &&t, const Q &q)
{
return fun(detail::bind_first(std::forward<T>(t), q));
}
}
Proxy_Function fun(T &&t, const Q &q) {
return fun(detail::bind_first(std::forward<T>(t), q));
}
} // namespace chaiscript
#endif

View File

@ -2,19 +2,19 @@
#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
@ -23,137 +23,115 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#include <cstddef>
#include <cassert>
#include <cstddef>
template <std::size_t N, std::size_t alignment = alignof(std::max_align_t)>
class arena
{
alignas(alignment) char buf_[N];
char* ptr_;
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;
~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;
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_;}
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);}
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;}
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;
}
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));
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<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
{
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>;
using value_type = T;
static auto constexpr alignment = Align;
static auto constexpr size = N;
using arena_type = arena<size, alignment>;
private:
arena_type& a_;
arena_type &a_;
public:
short_alloc(const short_alloc&) = default;
short_alloc& operator=(const short_alloc&) = delete;
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_) {}
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>;};
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));
}
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 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 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 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);
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
#endif // SHORT_ALLOC_HPP

File diff suppressed because it is too large Load Diff

View File

@ -1,244 +1,210 @@
// 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)
// Copyright 2009-2018, 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 <memory>
#include <string>
#include <type_traits>
#include <typeinfo>
#include <string>
namespace chaiscript
{
namespace detail
{
namespace chaiscript {
namespace detail {
template<typename T>
struct Bare_Type
{
typedef typename std::remove_cv<typename std::remove_pointer<typename std::remove_reference<T>::type>::type>::type type;
};
}
struct Bare_Type {
using type = typename std::remove_cv<typename std::remove_pointer<typename std::remove_reference<T>::type>::type>::type;
};
} // namespace detail
/// \brief Compile time deduced information about a type
class Type_Info
{
public:
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))
{
class Type_Info {
public:
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) noexcept
: 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)) {
}
constexpr Type_Info() noexcept = default;
bool operator<(const Type_Info &ti) const noexcept { return m_type_info->before(*ti.m_type_info); }
constexpr bool operator!=(const Type_Info &ti) const noexcept { return !(operator==(ti)); }
constexpr bool operator!=(const std::type_info &ti) const noexcept { return !(operator==(ti)); }
constexpr bool operator==(const Type_Info &ti) const noexcept {
return ti.m_type_info == m_type_info || *ti.m_type_info == *m_type_info;
}
constexpr bool operator==(const std::type_info &ti) const noexcept { return !is_undef() && (*m_type_info) == ti; }
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; }
const char *name() const noexcept {
if (!is_undef()) {
return m_type_info->name();
} else {
return "";
}
}
constexpr Type_Info() = default;
constexpr bool operator<(const Type_Info &ti) const noexcept
{
return m_type_info < ti.m_type_info;
const char *bare_name() const noexcept {
if (!is_undef()) {
return m_bare_type_info->name();
} else {
return "";
}
}
constexpr bool operator!=(const Type_Info &ti) const noexcept
{
return !(operator==(ti));
}
constexpr const std::type_info *bare_type_info() const noexcept { return m_bare_type_info; }
constexpr bool operator!=(const std::type_info &ti) const noexcept
{
return !(operator==(ti));
}
private:
struct Unknown_Type {
};
constexpr bool operator==(const Type_Info &ti) const noexcept
{
return ti.m_type_info == m_type_info
|| *ti.m_type_info == *m_type_info;
}
constexpr bool operator==(const std::type_info &ti) const noexcept
{
return !is_undef() && (*m_type_info) == ti;
}
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 (!is_undef())
{
return m_type_info->name();
} else {
return "";
}
}
std::string bare_name() const
{
if (!is_undef())
{
return m_bare_type_info->name();
} else {
return "";
}
}
constexpr const std::type_info *bare_type_info() const
{
return m_bare_type_info;
}
private:
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);
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
{
namespace detail {
/// Helper used to create a Type_Info object
template<typename T>
struct Get_Type_Info
{
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,
std::is_void<T>::value,
(std::is_arithmetic<T>::value || std::is_arithmetic<typename std::remove_reference<T>::type>::value)
&& !std::is_same<typename std::remove_const<typename std::remove_reference<T>::type>::type, bool>::value,
&typeid(T),
&typeid(typename Bare_Type<T>::type));
}
};
struct Get_Type_Info {
constexpr static Type_Info get() noexcept {
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_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));
}
};
template<typename T>
struct Get_Type_Info<std::shared_ptr<T> >
{
// typedef T type;
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<typename std::remove_reference<T>::type>::type, bool>::value,
&typeid(std::shared_ptr<T> ),
&typeid(typename Bare_Type<T>::type));
}
};
struct Get_Type_Info<std::shared_ptr<T>> {
constexpr static Type_Info get() noexcept {
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<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>>
{
};
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> &>
{
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<typename std::remove_reference<T>::type>::type, bool>::value,
&typeid(const std::shared_ptr<T> &),
&typeid(typename Bare_Type<T>::type));
}
};
struct Get_Type_Info<const std::shared_ptr<T> &> {
constexpr static Type_Info get() noexcept {
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<typename std::remove_reference<T>::type>::type, bool>::value,
&typeid(const std::shared_ptr<T> &),
&typeid(typename Bare_Type<T>::type));
}
};
template<typename T>
struct Get_Type_Info<std::reference_wrapper<T> >
{
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<typename std::remove_reference<T>::type>::type, bool>::value,
&typeid(std::reference_wrapper<T> ),
&typeid(typename Bare_Type<T>::type));
}
};
struct Get_Type_Info<std::reference_wrapper<T>> {
constexpr static Type_Info get() noexcept {
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<typename std::remove_reference<T>::type>::type, bool>::value,
&typeid(std::reference_wrapper<T>),
&typeid(typename Bare_Type<T>::type));
}
};
template<typename T>
struct Get_Type_Info<const std::reference_wrapper<T> &>
{
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<typename std::remove_reference<T>::type>::type, bool>::value,
&typeid(const std::reference_wrapper<T> &),
&typeid(typename Bare_Type<T>::type));
}
};
struct Get_Type_Info<const std::reference_wrapper<T> &> {
constexpr static Type_Info get() noexcept {
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<typename std::remove_reference<T>::type>::type, bool>::value,
&typeid(const std::reference_wrapper<T> &),
&typeid(typename Bare_Type<T>::type));
}
};
}
} // namespace detail
/// \brief Creates a Type_Info object representing the type passed in
/// \tparam T Type of object to get a Type_Info for, derived from the passed in parameter
/// \return Type_Info for T
///
///
/// \b Example:
/// \code
/// int i;
/// chaiscript::Type_Info ti = chaiscript::user_type(i);
/// \endcode
template<typename T>
constexpr Type_Info user_type(const T &/*t*/)
{
constexpr Type_Info user_type(const T & /*t*/) noexcept {
return detail::Get_Type_Info<T>::get();
}
/// \brief Creates a Type_Info object representing the templated type
/// \tparam T Type of object to get a Type_Info for
/// \return Type_Info for T
///
///
/// \b Example:
/// \code
/// chaiscript::Type_Info ti = chaiscript::user_type<int>();
/// \endcode
template<typename T>
constexpr Type_Info user_type()
{
constexpr Type_Info user_type() noexcept {
return detail::Get_Type_Info<T>::get();
}
}
} // namespace chaiscript
#endif

View File

@ -1,108 +1,167 @@
// 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)
// Copyright 2009-2018, 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 "../utility/fnv1a.hpp"
#include "../utility/hash.hpp"
#include <string>
namespace chaiscript
{
namespace chaiscript {
struct Operators {
enum class Opers
{
boolean_flag,
equals, less_than, greater_than, less_than_equal, greater_than_equal, not_equal,
non_const_flag,
assign, pre_increment, pre_decrement, assign_product, assign_sum,
assign_quotient, assign_difference,
non_const_int_flag,
assign_bitwise_and, assign_bitwise_or, assign_shift_left, assign_shift_right,
assign_remainder, assign_bitwise_xor,
const_int_flag,
shift_left, shift_right, remainder, bitwise_and, bitwise_or, bitwise_xor, bitwise_complement,
const_flag,
sum, quotient, product, difference, unary_plus, unary_minus,
enum class Opers {
equals,
less_than,
greater_than,
less_than_equal,
greater_than_equal,
not_equal,
assign,
pre_increment,
pre_decrement,
assign_product,
assign_sum,
assign_quotient,
assign_difference,
assign_bitwise_and,
assign_bitwise_or,
assign_shift_left,
assign_shift_right,
assign_remainder,
assign_bitwise_xor,
shift_left,
shift_right,
remainder,
bitwise_and,
bitwise_or,
bitwise_xor,
bitwise_complement,
sum,
quotient,
product,
difference,
unary_plus,
unary_minus,
invalid
};
static const char *to_string(Opers t_oper) {
static const char *opers[] = {
"",
"==", "<", ">", "<=", ">=", "!=",
"",
"=", "++", "--", "*=", "+=",
"/=", "-=",
"",
"&=", "|=", "<<=", ">>=",
"%=", "^=",
"",
"<<", ">>", "%", "&", "|", "^", "~",
"",
"+", "/", "*", "-", "+", "-",
""
};
constexpr static const char *to_string(Opers t_oper) noexcept {
constexpr const char *opers[]
= {"", "==", "<", ">", "<=", ">=", "!=", "", "=", "++", "--", "*=", "+=", "/=", "-=", "", "&=", "|=", "<<=", ">>=", "%=", "^=", "", "<<", ">>", "%", "&", "|", "^", "~", "", "+", "/", "*", "-", "+", "-", ""};
return opers[static_cast<int>(t_oper)];
}
static Opers to_operator(const std::string &t_str, bool t_is_unary = false)
{
constexpr static Opers to_operator(std::string_view t_str, bool t_is_unary = false) noexcept {
#ifdef CHAISCRIPT_MSVC
#pragma warning(push)
#pragma warning(disable : 4307)
#endif
const auto op_hash = utility::fnv1a_32(t_str.c_str());
const auto op_hash = utility::hash(t_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; }
case utility::hash("=="): {
return Opers::equals;
}
case utility::hash("<"): {
return Opers::less_than;
}
case utility::hash(">"): {
return Opers::greater_than;
}
case utility::hash("<="): {
return Opers::less_than_equal;
}
case utility::hash(">="): {
return Opers::greater_than_equal;
}
case utility::hash("!="): {
return Opers::not_equal;
}
case utility::hash("="): {
return Opers::assign;
}
case utility::hash("++"): {
return Opers::pre_increment;
}
case utility::hash("--"): {
return Opers::pre_decrement;
}
case utility::hash("*="): {
return Opers::assign_product;
}
case utility::hash("+="): {
return Opers::assign_sum;
}
case utility::hash("-="): {
return Opers::assign_difference;
}
case utility::hash("&="): {
return Opers::assign_bitwise_and;
}
case utility::hash("|="): {
return Opers::assign_bitwise_or;
}
case utility::hash("<<="): {
return Opers::assign_shift_left;
}
case utility::hash(">>="): {
return Opers::assign_shift_right;
}
case utility::hash("%="): {
return Opers::assign_remainder;
}
case utility::hash("^="): {
return Opers::assign_bitwise_xor;
}
case utility::hash("<<"): {
return Opers::shift_left;
}
case utility::hash(">>"): {
return Opers::shift_right;
}
case utility::hash("%"): {
return Opers::remainder;
}
case utility::hash("&"): {
return Opers::bitwise_and;
}
case utility::hash("|"): {
return Opers::bitwise_or;
}
case utility::hash("^"): {
return Opers::bitwise_xor;
}
case utility::hash("~"): {
return Opers::bitwise_complement;
}
case utility::hash("+"): {
return t_is_unary ? Opers::unary_plus : Opers::sum;
}
case utility::hash("-"): {
return t_is_unary ? Opers::unary_minus : Opers::difference;
}
case utility::hash("/"): {
return Opers::quotient;
}
case utility::hash("*"): {
return Opers::product;
}
default: {
return Opers::invalid;
}
}
#ifdef CHAISCRIPT_MSVC
#pragma warning(pop)
#endif
}
};
}
} // namespace chaiscript
#endif /* _CHAISCRIPT_ALGEBRAIC_HPP */

File diff suppressed because it is too large Load Diff

View File

@ -1,17 +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-2017, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2018, 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 <exception>
#include <fstream>
#include <functional>
@ -21,27 +21,28 @@
#include <set>
#include <stdexcept>
#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/type_conversions.hpp"
#include "../dispatchkit/proxy_functions.hpp"
#include "../dispatchkit/register_function.hpp"
#include "../dispatchkit/type_conversions.hpp"
#include "chaiscript_common.hpp"
#if defined(__linux__) || defined(__unix__) || defined(__APPLE__) || defined(__HAIKU__)
#include <unistd.h>
#endif
#if defined(_POSIX_VERSION) && !defined(__CYGWIN__)
#if !defined(CHAISCRIPT_NO_DYNLOAD) && defined(_POSIX_VERSION) && !defined(__CYGWIN__)
#include <dlfcn.h>
#endif
#ifdef CHAISCRIPT_WINDOWS
#if defined(CHAISCRIPT_NO_DYNLOAD)
#include "chaiscript_unknown.hpp"
#elif defined(CHAISCRIPT_WINDOWS)
#include "chaiscript_windows.hpp"
#elif _POSIX_VERSION
#include "chaiscript_posix.hpp"
@ -49,21 +50,18 @@
#include "chaiscript_unknown.hpp"
#endif
#include "../dispatchkit/exception_specification.hpp"
namespace chaiscript
{
namespace chaiscript {
/// Namespace alias to provide cleaner and more explicit syntax to users.
using Namespace = dispatch::Dynamic_Object;
namespace detail
{
typedef std::shared_ptr<Loadable_Module> Loadable_Module_Ptr;
namespace detail {
using Loadable_Module_Ptr = std::shared_ptr<Loadable_Module>;
}
/// \brief The main object that the ChaiScript user will use.
class ChaiScript_Basic {
mutable chaiscript::detail::threading::shared_mutex m_mutex;
mutable chaiscript::detail::threading::recursive_mutex m_use_mutex;
@ -78,24 +76,21 @@ namespace chaiscript
chaiscript::detail::Dispatch_Engine m_engine;
std::map<std::string, std::function<Namespace &()>> m_namespace_generators;
/// Evaluates the given string in by parsing it and running the results through the evaluator
Boxed_Value do_eval(const std::string &t_input, const std::string &t_filename = "__EVAL__", bool /* t_internal*/ = false)
{
Boxed_Value do_eval(const std::string &t_input, const std::string &t_filename = "__EVAL__", bool /* t_internal*/ = false) {
try {
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) {
} catch (chaiscript::eval::detail::Return_Value &rv) {
return rv.retval;
}
}
/// 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)
{
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);
@ -108,13 +103,10 @@ namespace chaiscript
// failed to load by any name
throw exception::file_not_found_error(t_filename);
}
/// Evaluates the given string, used during eval() inside of a script
const Boxed_Value internal_eval(const std::string &t_e) {
Boxed_Value internal_eval(const std::string &t_e) {
try {
return do_eval(t_e, "__EVAL__", true);
} catch (const exception::eval_error &t_ee) {
@ -123,111 +115,131 @@ namespace chaiscript
}
/// Returns the current evaluation m_engine
chaiscript::detail::Dispatch_Engine &get_eval_engine() {
return m_engine;
}
chaiscript::detail::Dispatch_Engine &get_eval_engine() noexcept { return m_engine; }
/// Builds all the requirements for ChaiScript, including its evaluator and a run of its prelude.
void build_eval_system(const ModulePtr &t_lib, const std::vector<Options> &t_opts) {
if (t_lib)
{
if (t_lib) {
add(t_lib);
}
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(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(dispatch::make_dynamic_proxy_function([this](const Function_Params &t_params) { return m_engine.call_exists(t_params); }),
"call_exists");
m_engine.add(fun([this](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(Function_Params{t_params}, s);
}),
"call");
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([this](const Type_Info &t_ti){ return m_engine.get_type_name(t_ti); }), "name");
m_engine.add(fun([this](const std::string &t_type_name, bool t_throw){ return m_engine.get_type(t_type_name, t_throw); }), "type");
m_engine.add(fun([this](const std::string &t_type_name){ return m_engine.get_type(t_type_name, true); }), "type");
m_engine.add(fun(
[=](const Type_Info &t_from, const Type_Info &t_to, const std::function<Boxed_Value (const Boxed_Value &)> &t_func) {
m_engine.add(chaiscript::type_conversion(t_from, t_to, t_func));
}
), "add_type_conversion");
m_engine.add(fun([this](const Type_Info &t_ti) { return m_engine.get_type_name(t_ti); }), "name");
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([this](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");
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");
&& 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) { 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");
&& 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) { return internal_eval(t_str); }), "eval");
m_engine.add(fun([this](const AST_Node &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 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");
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");
// why this unused parameter to Namespace?
m_engine.add(fun([this](const std::string &t_namespace_name) {
register_namespace([](Namespace & /*space*/) noexcept {}, t_namespace_name);
import(t_namespace_name);
}),
"namespace");
m_engine.add(fun([this](const std::string &t_namespace_name) { import(t_namespace_name); }), "import");
}
/// Skip BOM at the beginning of file
static bool skip_bom(std::ifstream &infile) {
size_t bytes_needed = 3;
char buffer[3];
memset(buffer, '\0', bytes_needed);
infile.read(buffer, static_cast<std::streamsize>(bytes_needed));
if ((buffer[0] == '\xef') && (buffer[1] == '\xbb') && (buffer[2] == '\xbf')) {
infile.seekg(3);
return true;
}
infile.seekg(0);
return false;
}
/// Helper function for loading a file
static std::string load_file(const std::string &t_filename) {
std::ifstream infile(t_filename.c_str(), std::ios::in | std::ios::ate | std::ios::binary );
std::ifstream infile(t_filename.c_str(), std::ios::in | std::ios::ate | std::ios::binary);
if (!infile.is_open()) {
throw chaiscript::exception::file_not_found_error(t_filename);
}
const auto size = infile.tellg();
auto size = infile.tellg();
infile.seekg(0, std::ios::beg);
assert(size >= 0);
if (size == std::streampos(0))
{
if (skip_bom(infile)) {
size -= 3; // decrement the BOM size from file size, otherwise we'll get parsing errors
assert(size >= 0); // and check if there's more text
}
if (size == std::streampos(0)) {
return std::string();
} else {
std::vector<char> v(static_cast<size_t>(size));
infile.read(&v[0], size);
infile.read(&v[0], static_cast<std::streamsize>(size));
return std::string(v.begin(), v.end());
}
}
std::vector<std::string> ensure_minimum_path_vec(std::vector<std::string> paths)
{
if (paths.empty()) { return {""}; }
else { return paths; }
std::vector<std::string> ensure_minimum_path_vec(std::vector<std::string> paths) {
if (paths.empty()) {
return {""};
} else {
return paths;
}
}
public:
/// \brief Virtual destructor for ChaiScript
virtual ~ChaiScript_Basic() = default;
/// \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
@ -237,132 +249,121 @@ namespace chaiscript
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 defined(_POSIX_VERSION) && !defined(__CYGWIN__)
: 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 !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
{
Boxed_Value (ChaiScript_Basic::*in_ptr)(const std::string&);
union cast_union {
Boxed_Value (ChaiScript_Basic::*in_ptr)(const std::string &);
void *out_ptr;
};
Dl_info rInfo;
memset( &rInfo, 0, sizeof(rInfo) );
Dl_info rInfo;
memset(&rInfo, 0, sizeof(rInfo));
cast_union u;
u.in_ptr = &ChaiScript_Basic::use;
if ( (dladdr(static_cast<void*>(u.out_ptr), &rInfo) != 0) && (rInfo.dli_fname != nullptr) ) {
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)
{
if (lastslash != std::string::npos) {
dllpath.erase(lastslash);
}
// Let's see if this is a link that we should expand
std::vector<char> buf(2048);
const auto pathlen = readlink(dllpath.c_str(), &buf.front(), buf.size());
if (pathlen > 0 && static_cast<size_t>(pathlen) < buf.size())
{
if (pathlen > 0 && static_cast<size_t>(pathlen) < buf.size()) {
dllpath = std::string(&buf.front(), static_cast<size_t>(pathlen));
}
m_module_paths.insert(m_module_paths.begin(), dllpath+"/");
m_module_paths.insert(m_module_paths.begin(), dllpath + "/");
}
#endif
build_eval_system(t_lib, t_opts);
}
#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)
{
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) {
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"
std::cout << "An error occurred 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()
{
parser::ChaiScript_Parser_Base &get_parser() noexcept {
return *m_parser;
}
const Boxed_Value eval(const AST_NodePtr &t_ast)
{
const Boxed_Value eval(const AST_Node &t_ast) {
try {
return t_ast->eval(chaiscript::detail::Dispatch_State(m_engine));
return t_ast.eval(chaiscript::detail::Dispatch_State(m_engine));
} catch (const exception::eval_error &t_ee) {
throw Boxed_Value(t_ee);
}
}
AST_NodePtr parse(const std::string &t_input, const bool t_debug_print = false)
{
const auto ast = m_parser->parse(t_input, "PARSE");
AST_NodePtr parse(const std::string &t_input, const bool t_debug_print = false) {
auto ast = m_parser->parse(t_input, "PARSE");
if (t_debug_print) {
m_parser->debug_print(ast);
m_parser->debug_print(*ast);
}
return ast;
}
std::string get_type_name(const Type_Info &ti) const
{
return m_engine.get_type_name(ti);
}
std::string get_type_name(const Type_Info &ti) const { return m_engine.get_type_name(ti); }
template<typename T>
std::string get_type_name() const
{
std::string get_type_name() const {
return get_type_name(user_type<T>());
}
/// \brief Loads and parses a file. If the file is already, it is not reloaded
/// The use paths specified at ChaiScript construction time are searched for the
/// requested file.
/// \brief Loads and parses a file. If the file is already open, it is not
/// reloaded. The use paths specified at ChaiScript construction time are
/// searched for the requested file.
///
/// \param[in] t_filename Filename to load and evaluate
Boxed_Value use(const std::string &t_filename)
{
for (const auto &path : m_use_paths)
{
Boxed_Value use(const std::string &t_filename) {
for (const auto &path : m_use_paths) {
const auto appendedpath = path + t_filename;
try {
const auto appendedpath = path + t_filename;
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::recursive_mutex> l(m_use_mutex);
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l2(m_mutex);
Boxed_Value retval;
if (m_used_files.count(appendedpath) == 0)
{
if (m_used_files.count(appendedpath) == 0) {
l2.unlock();
retval = eval_file(appendedpath);
l2.lock();
@ -370,7 +371,11 @@ namespace chaiscript
}
return retval; // return, we loaded it, or it was already loaded
} catch (const exception::file_not_found_error &) {
} catch (const exception::file_not_found_error &e) {
if (e.filename != appendedpath) {
// a nested file include failed
throw;
}
// failed to load, try the next path
}
}
@ -384,8 +389,7 @@ 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_Basic &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;
@ -396,15 +400,13 @@ 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_Basic &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)
{
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;
@ -415,8 +417,7 @@ namespace chaiscript
/// are left out due to performance considerations involved in tracking the state
/// \sa ChaiScript::get_state
/// \sa ChaiScript::set_state
struct State
{
struct State {
std::set<std::string> used_files;
chaiscript::detail::Dispatch_Engine::State engine_state;
std::set<std::string> active_loaded_modules;
@ -435,8 +436,7 @@ namespace chaiscript
/// chaiscript::ChaiScript chai;
/// chaiscript::ChaiScript::State s = chai.get_state(); // represents bootstrapped initial state
/// \endcode
State get_state() const
{
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);
@ -461,8 +461,7 @@ namespace chaiscript
/// chai.add(chaiscript::fun(&somefunction), "somefunction");
/// chai.set_state(s); // restore initial state, which does not have the recently added "somefunction"
/// \endcode
void set_state(const State &t_state)
{
void set_state(const State &t_state) {
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);
@ -472,26 +471,20 @@ namespace chaiscript
}
/// \returns All values in the local thread state, added through the add() function
std::map<std::string, Boxed_Value> get_locals() const
{
return m_engine.get_locals();
}
std::map<std::string, Boxed_Value> get_locals() const { return m_engine.get_locals(); }
/// \brief Sets all of the locals for the current thread state.
///
/// \param[in] t_locals The map<name, value> set of variables to replace the current state with
///
/// Any existing locals are removed and the given set of variables is added
void set_locals(const std::map<std::string, Boxed_Value> &t_locals)
{
m_engine.set_locals(t_locals);
}
void set_locals(const std::map<std::string, Boxed_Value> &t_locals) { m_engine.set_locals(t_locals); }
/// \brief Adds a type, function or object to ChaiScript. Objects are added to the local thread state.
/// \param[in] t_t Item to add
/// \param[in] t_name Name of item to add
/// \returns Reference to current ChaiScript object
///
///
/// \b Examples:
/// \code
/// chaiscript::ChaiScript chai;
@ -503,8 +496,7 @@ namespace chaiscript
///
/// \sa \ref adding_items
template<typename T>
ChaiScript_Basic &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;
@ -512,15 +504,14 @@ namespace chaiscript
/// \brief Add a new conversion for upcasting to a base class
/// \sa chaiscript::base_class
/// \param[in] d Base class / parent class
/// \param[in] d Base class / parent class
///
/// \b Example:
/// \code
/// chaiscript::ChaiScript chai;
/// chai.add(chaiscript::base_class<std::runtime_error, chaiscript::dispatch_error>());
/// \endcode
ChaiScript_Basic &add(const Type_Conversion &d)
{
ChaiScript_Basic &add(const Type_Conversion &d) {
m_engine.add(d);
return *this;
}
@ -528,8 +519,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_Basic &add(const ModulePtr &t_p)
{
ChaiScript_Basic &add(const ModulePtr &t_p) {
t_p->apply(*this, this->get_eval_engine());
return *this;
}
@ -542,17 +532,18 @@ namespace chaiscript
/// 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
/// If no file can be found matching the search criteria and containing the appropriate entry point
/// (the symbol mentioned above), an exception is thrown.
///
/// \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)
{
std::string load_module(const std::string &t_module_name) {
#ifdef CHAISCRIPT_NO_DYNLOAD
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("-" + Build_Info::version());
if (version_pos != std::string::npos)
{
if (version_pos != std::string::npos) {
version_stripped_name.erase(version_pos);
}
@ -560,12 +551,9 @@ namespace chaiscript
std::vector<std::string> postfixes{".dll", ".so", ".bundle", ""};
for (auto & elem : m_module_paths)
{
for (auto & prefix : prefixes)
{
for (auto & postfix : postfixes)
{
for (auto &elem : m_module_paths) {
for (auto &prefix : prefixes) {
for (auto &postfix : postfixes) {
try {
const auto name = elem + prefix + t_module_name + postfix;
// std::cerr << "trying location: " << name << '\n';
@ -581,6 +569,7 @@ namespace chaiscript
}
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
@ -590,12 +579,10 @@ namespace chaiscript
/// \param[in] t_filename Ignore normal filename search process and use specific filename
///
/// \sa ChaiScript::load_module(const std::string &t_module_name)
void load_module(const std::string &t_module_name, const std::string &t_filename)
{
void load_module(const std::string &t_module_name, const std::string &t_filename) {
chaiscript::detail::threading::lock_guard<chaiscript::detail::threading::recursive_mutex> l(m_use_mutex);
if (m_loaded_modules.count(t_module_name) == 0)
{
if (m_loaded_modules.count(t_module_name) == 0) {
detail::Loadable_Module_Ptr lm(new detail::Loadable_Module(t_module_name, t_filename));
m_loaded_modules[t_module_name] = lm;
m_active_loaded_modules.insert(t_module_name);
@ -603,20 +590,18 @@ namespace chaiscript
} else if (m_active_loaded_modules.count(t_module_name) == 0) {
m_active_loaded_modules.insert(t_module_name);
add(m_loaded_modules[t_module_name]->m_moduleptr);
}
}
}
/// \brief Evaluates a string. Equivalent to ChaiScript::eval.
///
/// \param[in] t_script Script to execute
/// \param[in] t_handler Optional Exception_Handler used for automatic unboxing of script thrown exceptions
///
/// \return result of the script execution
///
///
/// \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())
{
Boxed_Value operator()(const std::string &t_script, const Exception_Handler &t_handler = Exception_Handler()) {
return eval(t_script, t_handler);
}
@ -629,23 +614,20 @@ namespace chaiscript
/// in special cases where you are loading a file internally instead of using eval_file
///
/// \return result of the script execution
///
///
/// \throw chaiscript::exception::eval_error In the case that evaluation fails.
/// \throw chaiscript::exception::bad_boxed_cast In the case that evaluation succeeds but the result value cannot be converted
/// to the requested type.
template<typename T>
T eval(const std::string &t_input, const Exception_Handler &t_handler = Exception_Handler(), const std::string &t_filename="__EVAL__")
{
T eval(const std::string &t_input, const Exception_Handler &t_handler = Exception_Handler(), const std::string &t_filename = "__EVAL__") {
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>
decltype(auto) boxed_cast(const Boxed_Value &bv) const
{
return(m_engine.boxed_cast<Type>(bv));
}
decltype(auto) boxed_cast(const Boxed_Value &bv) const {
return (m_engine.boxed_cast<Type>(bv));
}
/// \brief Evaluates a string.
///
@ -655,10 +637,10 @@ namespace chaiscript
/// in special cases where you are loading a file internally instead of using eval_file
///
/// \return result of the script execution
///
///
/// \throw exception::eval_error In the case that evaluation fails.
Boxed_Value eval(const std::string &t_input, const Exception_Handler &t_handler = Exception_Handler(), const std::string &t_filename="__EVAL__")
{
Boxed_Value
eval(const std::string &t_input, const Exception_Handler &t_handler = Exception_Handler(), const std::string &t_filename = "__EVAL__") {
try {
return do_eval(t_input, t_filename);
} catch (Boxed_Value &bv) {
@ -690,8 +672,39 @@ namespace chaiscript
T eval_file(const std::string &t_filename, const Exception_Handler &t_handler = Exception_Handler()) {
return m_engine.boxed_cast<T>(eval_file(t_filename, t_handler));
}
/// \brief Imports a namespace object into the global scope of this ChaiScript instance.
/// \param[in] t_namespace_name Name of the namespace to import.
/// \throw std::runtime_error In the case that the namespace name was never registered.
void import(const std::string &t_namespace_name) {
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::recursive_mutex> l(m_use_mutex);
if (m_engine.get_scripting_objects().count(t_namespace_name)) {
throw std::runtime_error("Namespace: " + t_namespace_name + " was already defined");
} else if (m_namespace_generators.count(t_namespace_name)) {
m_engine.add_global(var(std::ref(m_namespace_generators[t_namespace_name]())), t_namespace_name);
} else {
throw std::runtime_error("No registered namespace: " + t_namespace_name);
}
}
/// \brief Registers a namespace generator, which delays generation of the namespace until it is imported, saving memory if it is never
/// used. \param[in] t_namespace_generator Namespace generator function. \param[in] t_namespace_name Name of the Namespace function
/// being registered. \throw std::runtime_error In the case that the namespace name was already registered.
void register_namespace(const std::function<void(Namespace &)> &t_namespace_generator, const std::string &t_namespace_name) {
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::recursive_mutex> l(m_use_mutex);
if (!m_namespace_generators.count(t_namespace_name)) {
// contain the namespace object memory within the m_namespace_generators map
m_namespace_generators.emplace(std::make_pair(t_namespace_name, [=, space = Namespace()]() mutable -> Namespace & {
t_namespace_generator(space);
return space;
}));
} else {
throw std::runtime_error("Namespace: " + t_namespace_name + " was already registered.");
}
}
};
}
} // namespace chaiscript
#endif /* CHAISCRIPT_ENGINE_HPP_ */

File diff suppressed because it is too large Load Diff

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)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_OPTIMIZER_HPP_
@ -9,73 +9,74 @@
#include "chaiscript_eval.hpp"
namespace chaiscript {
namespace optimizer {
template<typename ... T>
struct Optimizer : T...
{
template<typename... T>
struct Optimizer : T... {
Optimizer() = default;
explicit Optimizer(T ... t)
: T(std::move(t))...
{
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)... };
((p = static_cast<T &>(*this).optimize(std::move(p))), ...);
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];
}
*/
eval::AST_Node_Impl<T> &child_at(eval::AST_Node_Impl<T> &node, const size_t offset) noexcept {
if (node.children[offset]->identifier == AST_Node_Type::Compiled) {
return *(dynamic_cast<eval::Compiled_AST_Node<T> &>(*node.children[offset]).m_original_node);
} 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();
}
const eval::AST_Node_Impl<T> &child_at(const eval::AST_Node_Impl<T> &node, const size_t offset) noexcept {
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<T> &node) noexcept {
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));
}
auto make_compiled_node(eval::AST_Node_Impl_Ptr<T> original_node, std::vector<eval::AST_Node_Impl_Ptr<T>> children, Callable callable) {
return chaiscript::make_unique<eval::AST_Node_Impl<T>, eval::Compiled_AST_Node<T>>(std::move(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 optimize(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];
last_child->children.back() = std::move(block_last_child->children[0]);
}
}
}
@ -86,9 +87,9 @@ namespace chaiscript {
};
template<typename T>
bool contains_var_decl_in_scope(const T &node)
{
if (node->identifier == AST_Node_Type::Var_Decl) {
bool contains_var_decl_in_scope(const eval::AST_Node_Impl<T> &node) noexcept {
if (node.identifier == AST_Node_Type::Var_Decl || node.identifier == AST_Node_Type::Assign_Decl
|| node.identifier == AST_Node_Type::Reference) {
return true;
}
@ -96,9 +97,8 @@ namespace chaiscript {
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)) {
if (child.identifier != AST_Node_Type::Block && child.identifier != AST_Node_Type::For
&& child.identifier != AST_Node_Type::Ranged_For && contains_var_decl_in_scope(child)) {
return true;
}
}
@ -108,15 +108,15 @@ namespace chaiscript {
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))
{
auto optimize(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];
return std::move(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 chaiscript::make_unique<eval::AST_Node_Impl<T>, eval::Scopeless_Block_AST_Node<T>>(node->text,
node->location,
std::move(node->children));
}
}
}
@ -127,85 +127,97 @@ namespace chaiscript {
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);
auto optimize(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);
}
for (size_t i = 0; i < num_children; ++i) {
const 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;
}
if (keepers.size() == num_children) {
return node;
} else {
const auto new_children = [&]() {
std::vector<eval::AST_Node_Impl_Ptr<T>> retval;
for (const auto x : keepers) {
retval.push_back(std::move(node->children[x]));
}
return retval;
};
return chaiscript::make_unique<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));
}
auto optimize(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].get();
if (child->identifier == AST_Node_Type::Fun_Call) {
node->children[i]
= chaiscript::make_unique<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));
}
}
} 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_unique<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;
}
return node;
}
};
struct Assign_Decl {
template<typename T>
auto optimize(eval::AST_Node_Impl_Ptr<T> node) {
if ((node->identifier == AST_Node_Type::Equation) && node->text == "=" && node->children.size() == 2
&& node->children[0]->identifier == AST_Node_Type::Var_Decl) {
std::vector<eval::AST_Node_Impl_Ptr<T>> new_children;
new_children.push_back(std::move(node->children[0]->children[0]));
new_children.push_back(std::move(node->children[1]));
return chaiscript::make_unique<eval::AST_Node_Impl<T>, eval::Assign_Decl_AST_Node<T>>(node->text,
node->location,
std::move(new_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;
auto optimize(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 = dynamic_cast<eval::Constant_AST_Node<T> *>(node->children[0].get())->m_value;
if (condition.get_type_info().bare_equal_type_info(typeid(bool))) {
if (boxed_cast<bool>(condition)) {
return node->children[1];
return std::move(node->children[1]);
} else if (node->children.size() == 3) {
return node->children[2];
return std::move(node->children[2]);
}
}
}
@ -216,25 +228,22 @@ namespace chaiscript {
struct Partial_Fold {
template<typename T>
auto optimize(const eval::AST_Node_Impl_Ptr<T> &node) {
auto optimize(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)
{
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;
const auto rhs = dynamic_cast<eval::Constant_AST_Node<T> *>(node->children[1].get())->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);
return chaiscript::make_unique<eval::AST_Node_Impl<T>, eval::Fold_Right_Binary_Operator_AST_Node<T>>(
node->text, node->location, std::move(node->children), rhs);
}
}
} catch (const std::exception &) {
//failure to fold, that's OK
// failure to fold, that's OK
}
}
@ -244,81 +253,81 @@ namespace chaiscript {
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)
{
auto optimize(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 lhs = dynamic_cast<const eval::Constant_AST_Node<T> *>(node->children[0].get())->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));
const auto val = Boxed_Number::do_oper(parsed, lhs);
return chaiscript::make_unique<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)));
return chaiscript::make_unique<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
// 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)
{
&& 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;
const auto lhs = dynamic_cast<const eval::Constant_AST_Node<T> &>(*node->children[0]).m_value;
const auto rhs = dynamic_cast<const 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); }
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));
return chaiscript::make_unique<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
// 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)
{
} 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;
const auto lhs = dynamic_cast<const eval::Constant_AST_Node<T> &>(*node->children[0]).m_value;
const auto rhs = dynamic_cast<const 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 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));
return chaiscript::make_unique<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
// 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;
} 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 = dynamic_cast<const 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 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));
return chaiscript::make_unique<eval::AST_Node_Impl<T>, eval::Constant_AST_Node<T>>(std::move(match),
node->location,
const_var(val));
};
if (fun_name == "double") {
@ -332,10 +341,7 @@ namespace chaiscript {
} else if (fun_name == "size_t") {
return make_constant(Boxed_Number(arg).get_as<size_t>());
}
}
}
return node;
@ -344,70 +350,64 @@ namespace chaiscript {
struct For_Loop {
template<typename T>
auto optimize(const eval::AST_Node_Impl_Ptr<T> &for_node) {
auto optimize(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);
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>())) {
if (child_count(*for_node) == 4 && eq_node.identifier == AST_Node_Type::Assign_Decl && child_count(eq_node) == 2
&& child_at(eq_node, 0).identifier == AST_Node_Type::Id && 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(eq_node, 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(eq_node, 0).text) {
const Boxed_Value &begin = dynamic_cast<const eval::Constant_AST_Node<T> &>(child_at(eq_node, 1)).m_value;
const Boxed_Value &end = dynamic_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);
// note that we are moving the last element out, then popping the empty shared_ptr
// from the vector
std::vector<eval::AST_Node_Impl_Ptr<T>> body_vector;
auto body_child = std::move(for_node->children[3]);
for_node->children.pop_back();
body_vector.emplace_back(std::move(body_child));
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);
return make_compiled_node(std::move(for_node),
std::move(body_vector),
[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));
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
}
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();
}
);
return void_var();
});
} else {
return for_node;
}
@ -417,11 +417,17 @@ namespace chaiscript {
}
};
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;
}
}
using Optimizer_Default = Optimizer<optimizer::Partial_Fold,
optimizer::Unused_Return,
optimizer::Constant_Fold,
optimizer::If,
optimizer::Return,
optimizer::Dead_Code,
optimizer::Block,
optimizer::For_Loop,
optimizer::Assign_Decl>;
} // namespace optimizer
} // namespace chaiscript
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,81 +1,53 @@
// 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)
// Copyright 2009-2018, 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());
}
namespace chaiscript::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
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(reinterpret_cast<T>(dlsym(t_mod.m_data, t_symbol.c_str()))) {
if (!m_symbol) {
throw chaiscript::exception::load_module_error(dlerror());
}
}
T m_symbol;
};
Loadable_Module(const std::string &t_module_name, const std::string &t_filename)
: m_dlmodule(t_filename)
, m_func(m_dlmodule, "create_chaiscript_module_" + t_module_name)
, m_moduleptr(m_func.m_symbol()) {
}
DLModule m_dlmodule;
DLSym<Create_Module_Func> m_func;
ModulePtr m_moduleptr;
};
} // namespace chaiscript::detail
#endif

View File

@ -1,43 +1,44 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// and 2009-2017, Jason Turner (jason@emptycrate.com)
// and 2009-2018, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_PRELUDE_HPP_
#define CHAISCRIPT_PRELUDE_HPP_
namespace chaiscript {
struct ChaiScript_Prelude {
static std::string chaiscript_prelude() { return R"chaiscript(
struct ChaiScript_Prelude {
static std::string chaiscript_prelude() {
return R"chaiscript(
def lt(l, r) {
if (call_exists(`<`, l, r)) {
l < r
} else {
type_name(l) < type_name(r)
}
def lt(l, r) {
if (call_exists(`<`, l, r)) {
l < r
} else {
type_name(l) < type_name(r)
}
}
def gt(l, r) {
if (call_exists(`>`, l, r)) {
l > r
} else {
type_name(l) > type_name(r)
}
def gt(l, r) {
if (call_exists(`>`, l, r)) {
l > r
} else {
type_name(l) > type_name(r)
}
}
def eq(l, r) {
if (call_exists(`==`, l, r)) {
l == r
} else {
false
}
def eq(l, r) {
if (call_exists(`==`, l, r)) {
l == r
} else {
false
}
}
def new(x) {
eval(type_name(x))();
def new(x) {
eval(type_name(x))();
}
def clone(double x) {
@ -64,85 +65,85 @@ def clone(x) : function_exists(type_name(x)) && call_exists(eval(type_name(x)),
# to_string for Pair()
def to_string(x) : call_exists(first, x) && call_exists(second, x) {
"<" + x.first.to_string() + ", " + x.second.to_string() + ">";
def to_string(x) : call_exists(first, x) && call_exists(second, x) {
"<" + x.first.to_string() + ", " + x.second.to_string() + ">";
}
# to_string for containers
def to_string(x) : call_exists(range, x) && !x.is_type("string"){
"[" + x.join(", ") + "]";
def to_string(x) : call_exists(range, x) && !x.is_type("string"){
"[" + x.join(", ") + "]";
}
# Prints to console with no carriage return
def puts(x) {
print_string(x.to_string());
def puts(x) {
print_string(x.to_string());
}
# Prints to console with carriage return
def print(x) {
println_string(x.to_string());
def print(x) {
println_string(x.to_string());
}
# Returns the maximum value of two numbers
def max(a, b) {
if (a>b) {
a
} else {
b
}
}
if (a>b) {
a
} else {
b
}
}
# Returns the minimum value of two numbers
def min(a, b)
{
if (a<b)
{
a
} else {
b
}
def min(a, b)
{
if (a<b)
{
a
} else {
b
}
}
# Returns true if the value is odd
def odd(x) {
if (x % 2 == 1)
{
true
} else {
false
}
def odd(x) {
if (x % 2 == 1)
{
true
} else {
false
}
}
# Returns true if the value is even
def even(x)
{
if (x % 2 == 0)
{
true
} else {
false
}
}
def even(x)
{
if (x % 2 == 0)
{
true
} else {
false
}
}
# 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)
{
container.insert_ref_at(pos, clone(x));
}
# while making a clone.
def insert_at(container, pos, x)
{
container.insert_ref_at(pos, clone(x));
}
# Returns the reverse of the given container
def reverse(container) {
auto retval := new(container);
auto r := range(container);
while (!r.empty()) {
retval.push_back(r.back());
r.pop_back();
}
retval;
auto retval := new(container);
auto r := range(container);
while (!r.empty()) {
retval.push_back(r.back());
r.pop_back();
}
retval;
}
@ -153,86 +154,86 @@ 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)
# 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;
# The retro attribute that contains the underlying range
attr retro::m_range;
# Creates a retro from a retro by returning the original range
def retro(r) : call_exists(get_type_name, r) && get_type_name(r) == "retro"
{
clone(r.m_range)
def retro(r) : call_exists(get_type_name, r) && get_type_name(r) == "retro"
{
clone(r.m_range)
}
# Creates a retro range from a range
def retro::retro(r) : call_exists(empty, r) && call_exists(pop_front, r) && call_exists(pop_back, r) && call_exists(back, r) && call_exists(front, r)
{
this.m_range = r;
def retro::retro(r) : call_exists(empty, r) && call_exists(pop_front, r) && call_exists(pop_back, r) && call_exists(back, r) && call_exists(front, r)
{
this.m_range = r;
}
# Returns the first value of a retro
def retro::front()
{
back(this.m_range)
def retro::front()
{
back(this.m_range)
}
# Returns the last value of a retro
def retro::back()
{
front(this.m_range)
}
# Moves the back iterator of a retro towards the front by one
def retro::pop_back()
def retro::back()
{
pop_front(this.m_range)
front(this.m_range)
}
# Moves the front iterator of a retro towards the back by one
def retro::pop_front()
{
pop_back(this.m_range)
}
# Moves the back iterator of a retro towards the front by one
def retro::pop_back()
{
pop_front(this.m_range)
}
# returns true if the retro is out of elements
def retro::empty()
{
empty(this.m_range);
}
# Moves the front iterator of a retro towards the back by one
def retro::pop_front()
{
pop_back(this.m_range)
}
# returns true if the retro is out of elements
def retro::empty()
{
empty(this.m_range);
}
# Performs the second value function over the container first value
def for_each(container, func) : call_exists(range, container) {
var t_range := range(container);
while (!t_range.empty()) {
func(t_range.front());
t_range.pop_front();
}
}
def for_each(container, func) : call_exists(range, container) {
var t_range := range(container);
while (!t_range.empty()) {
func(t_range.front());
t_range.pop_front();
}
}
def any_of(container, func) : call_exists(range, container) {
var t_range := range(container);
while (!t_range.empty()) {
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();
t_range.pop_front();
}
false;
}
def all_of(container, func) : call_exists(range, container) {
var t_range := range(container);
while (!t_range.empty()) {
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();
t_range.pop_front();
}
true;
@ -242,321 +243,320 @@ def back_inserter(container) {
bind(push_back, container, _);
}
def contains(container, item, compare_func) : call_exists(range, container) {
auto t_range := range(container);
while (!t_range.empty()) {
if ( compare_func(t_range.front(), item) ) {
return true;
}
def contains(container, item, compare_func) : call_exists(range, container) {
auto t_range := range(container);
while (!t_range.empty()) {
if ( compare_func(t_range.front(), item) ) {
return true;
}
t_range.pop_front();
}
false;
}
t_range.pop_front();
}
false;
}
def contains(container, item) {
contains(container, item, eq)
}
def contains(container, item) {
contains(container, item, eq)
}
def map(container, func, inserter) : call_exists(range, container) {
auto range := range(container);
while (!range.empty()) {
inserter(func(range.front()));
range.pop_front();
}
}
def map(container, func, inserter) : call_exists(range, container) {
auto range := range(container);
while (!range.empty()) {
inserter(func(range.front()));
range.pop_front();
}
}
# Performs the second value function over the container first value. Creates a new container with the results
def map(container, func) {
auto retval := new(container);
def map(container, func) {
auto retval := new(container);
map(container, func, back_inserter(retval));
retval;
}
# Performs the second value function over the container first value. Starts with initial and continues with each element.
def foldl(container, func, initial) : call_exists(range, container){
auto retval = initial;
auto range := range(container);
while (!range.empty()) {
retval = (func(range.front(), retval));
range.pop_front();
}
retval;
def foldl(container, func, initial) : call_exists(range, container){
auto retval = initial;
auto range := range(container);
while (!range.empty()) {
retval = (func(range.front(), retval));
range.pop_front();
}
retval;
}
# Returns the sum of the elements of the given value
def sum(container) {
foldl(container, `+`, 0.0)
}
def sum(container) {
foldl(container, `+`, 0.0)
}
# Returns the product of the elements of the given value
def product(container) {
foldl(container, `*`, 1.0)
}
def product(container) {
foldl(container, `*`, 1.0)
}
# Returns a new container with the elements of the first value concatenated with the elements of the second value
def concat(x, y) : call_exists(clone, x) {
auto retval = x;
auto inserter := back_inserter(retval);
auto range := range(y);
while (!range.empty()) {
inserter(range.front());
range.pop_front();
}
retval;
def concat(x, y) : call_exists(clone, x) {
auto retval = x;
auto inserter := back_inserter(retval);
auto range := range(y);
while (!range.empty()) {
inserter(range.front());
range.pop_front();
}
retval;
}
def take(container, num, inserter) : call_exists(range, container) {
auto r := range(container);
auto i = num;
while ((i > 0) && (!r.empty())) {
inserter(r.front());
r.pop_front();
--i;
}
def take(container, num, inserter) : call_exists(range, container) {
auto r := range(container);
auto i = num;
while ((i > 0) && (!r.empty())) {
inserter(r.front());
r.pop_front();
--i;
}
}
# Returns a new container with the given number of elements taken from the container
def take(container, num) {
auto retval := new(container);
take(container, num, back_inserter(retval));
retval;
}
def take_while(container, f, inserter) : call_exists(range, container) {
auto r := range(container);
while ((!r.empty()) && f(r.front())) {
inserter(r.front());
r.pop_front();
}
}
# Returns a new container with the given elements match the second value function
def take_while(container, f) {
auto retval := new(container);
take_while(container, f, back_inserter(retval));
auto retval := new(container);
take(container, num, back_inserter(retval));
retval;
}
def drop(container, num, inserter) : call_exists(range, container) {
auto r := range(container);
auto i = num;
while ((i > 0) && (!r.empty())) {
r.pop_front();
--i;
}
while (!r.empty()) {
inserter(r.front());
r.pop_front();
}
def take_while(container, f, inserter) : call_exists(range, container) {
auto r := range(container);
while ((!r.empty()) && f(r.front())) {
inserter(r.front());
r.pop_front();
}
}
# Returns a new container with the given number of elements dropped from the given container
# Returns a new container with the given elements match the second value function
def take_while(container, f) {
auto retval := new(container);
take_while(container, f, back_inserter(retval));
retval;
}
def drop(container, num, inserter) : call_exists(range, container) {
auto r := range(container);
auto i = num;
while ((i > 0) && (!r.empty())) {
r.pop_front();
--i;
}
while (!r.empty()) {
inserter(r.front());
r.pop_front();
}
}
# Returns a new container with the given number of elements dropped from the given container
def drop(container, num) {
auto retval := new(container);
drop(container, num, back_inserter(retval));
retval;
auto retval := new(container);
drop(container, num, back_inserter(retval));
retval;
}
def drop_while(container, f, inserter) : call_exists(range, container) {
auto r := range(container);
while ((!r.empty())&& f(r.front())) {
r.pop_front();
}
while (!r.empty()) {
inserter(r.front());
r.pop_front();
}
def drop_while(container, f, inserter) : call_exists(range, container) {
auto r := range(container);
while ((!r.empty())&& f(r.front())) {
r.pop_front();
}
while (!r.empty()) {
inserter(r.front());
r.pop_front();
}
}
# Returns a new container with the given elements dropped that match the second value function
def drop_while(container, f) {
auto retval := new(container);
drop_while(container, f, back_inserter(retval));
retval;
auto retval := new(container);
drop_while(container, f, back_inserter(retval));
retval;
}
# Applies the second value function to the container. Starts with the first two elements. Expects at least 2 elements.
def reduce(container, func) : container.size() >= 2 && call_exists(range, container) {
auto r := range(container);
auto retval = r.front();
r.pop_front();
retval = func(retval, r.front());
r.pop_front();
while (!r.empty()) {
retval = func(retval, r.front());
r.pop_front();
}
retval;
def reduce(container, func) : container.size() >= 2 && call_exists(range, container) {
auto r := range(container);
auto retval = r.front();
r.pop_front();
retval = func(retval, r.front());
r.pop_front();
while (!r.empty()) {
retval = func(retval, r.front());
r.pop_front();
}
retval;
}
# Returns a string of the elements in container delimited by the second value string
def join(container, delim) {
auto retval = "";
auto range := range(container);
if (!range.empty()) {
retval += to_string(range.front());
range.pop_front();
while (!range.empty()) {
retval += delim;
retval += to_string(range.front());
range.pop_front();
}
}
retval;
def join(container, delim) {
auto retval = "";
auto range := range(container);
if (!range.empty()) {
retval += to_string(range.front());
range.pop_front();
while (!range.empty()) {
retval += delim;
retval += to_string(range.front());
range.pop_front();
}
}
retval;
}
def filter(container, f, inserter) : call_exists(range, container) {
auto r := range(container);
while (!r.empty()) {
if (f(r.front())) {
inserter(r.front());
}
r.pop_front();
}
}
def filter(container, f, inserter) : call_exists(range, container) {
auto r := range(container);
while (!r.empty()) {
if (f(r.front())) {
inserter(r.front());
}
r.pop_front();
}
}
# Returns a new Vector which match the second value function
def filter(container, f) {
auto retval := new(container);
def filter(container, f) {
auto retval := new(container);
filter(container, f, back_inserter(retval));
retval;
}
def generate_range(x, y, inserter) {
auto i = x;
while (i <= y) {
inserter(i);
++i;
}
def generate_range(x, y, inserter) {
auto i = x;
while (i <= y) {
inserter(i);
++i;
}
}
# Returns a new Vector which represents the range from the first value to the second value
def generate_range(x, y) {
auto retval := Vector();
generate_range(x,y,back_inserter(retval));
retval;
def generate_range(x, y) {
auto retval := Vector();
generate_range(x,y,back_inserter(retval));
retval;
}
# Returns a new Vector with the first value to the second value as its elements
def collate(x, y) {
return [x, y];
def collate(x, y) {
return [x, y];
}
def zip_with(f, x, y, inserter) : call_exists(range, x) && call_exists(range, y) {
auto r_x := range(x);
auto r_y := range(y);
while (!r_x.empty() && !r_y.empty()) {
inserter(f(r_x.front(), r_y.front()));
r_x.pop_front();
r_y.pop_front();
}
def zip_with(f, x, y, inserter) : call_exists(range, x) && call_exists(range, y) {
auto r_x := range(x);
auto r_y := range(y);
while (!r_x.empty() && !r_y.empty()) {
inserter(f(r_x.front(), r_y.front()));
r_x.pop_front();
r_y.pop_front();
}
}
# Returns a new Vector which joins matching elements of the second and third value with the first value function
def zip_with(f, x, y) {
auto retval := Vector();
zip_with(f,x,y,back_inserter(retval));
def zip_with(f, x, y) {
auto retval := Vector();
zip_with(f,x,y,back_inserter(retval));
retval;
}
# Returns a new Vector which joins matching elements of the first and second
def zip(x, y) {
zip_with(collate, x, y);
def zip(x, y) {
zip_with(collate, x, y);
}
# Returns the position of the second value string in the first value string
def string::find(string substr) {
find(this, substr, size_t(0));
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(string substr) {
rfind(this, substr, size_t(-1));
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(string list) {
find_first_of(this, list, size_t(0));
}
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(string list) {
find_last_of(this, list, size_t(-1));
}
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(string list) {
find_first_not_of(this, list, size_t(0));
}
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(string list) {
find_last_not_of(this, list, size_t(-1));
}
def string::ltrim() {
drop_while(this, fun(x) { x == ' ' || x == '\t' || x == '\r' || x == '\n'});
}
def string::rtrim() {
reverse(drop_while(reverse(this), fun(x) { x == ' ' || x == '\t' || x == '\r' || x == '\n'}));
}
def string::trim() {
ltrim(rtrim(this));
def string::find_last_not_of(string list) {
find_last_not_of(this, list, size_t(-1));
}
def find(container, value, Function compare_func) : call_exists(range, container) {
auto range := range(container);
while (!range.empty()) {
if (compare_func(range.front(), value)) {
return range;
} else {
range.pop_front();
}
}
range;
}
def string::ltrim() {
drop_while(this, fun(x) { x == ' ' || x == '\t' || x == '\r' || x == '\n'});
}
def find(container, value) {
find(container, value, eq)
}
def string::rtrim() {
reverse(drop_while(reverse(this), fun(x) { x == ' ' || x == '\t' || x == '\r' || x == '\n'}));
}
def string::trim() {
ltrim(rtrim(this));
}
def find(container, value, Function compare_func) : call_exists(range, container) {
auto range := range(container);
while (!range.empty()) {
if (compare_func(range.front(), value)) {
return range;
} else {
range.pop_front();
}
}
range;
}
def find(container, value) {
find(container, value, eq)
}
)chaiscript";
}
};
}
}
};
} // namespace chaiscript
#endif /* CHAISCRIPT_PRELUDE_HPP_ */

File diff suppressed because it is too large Load Diff

View File

@ -1,46 +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)
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_TRACER_HPP_
#define CHAISCRIPT_TRACER_HPP_
namespace chaiscript {
namespace eval {
namespace chaiscript::eval {
struct Noop_Tracer_Detail {
template<typename T>
constexpr void trace(const chaiscript::detail::Dispatch_State &, const AST_Node_Impl<T> *) noexcept {
}
};
template<typename... T>
struct Tracer : T... {
Tracer() = default;
constexpr explicit Tracer(T... t)
: T(std::move(t))... {
}
struct Noop_Tracer_Detail
{
template<typename T>
void trace(const chaiscript::detail::Dispatch_State &, const AST_Node_Impl<T> *)
{
}
};
void do_trace(const chaiscript::detail::Dispatch_State &ds, const AST_Node_Impl<Tracer<T...>> *node) {
(static_cast<T &>(*this).trace(ds, node), ...);
}
template<typename ... T>
struct Tracer : T...
{
Tracer() = default;
explicit Tracer(T ... t)
: T(std::move(t))...
{
}
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);
}
};
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)... };
}
using Noop_Tracer = Tracer<Noop_Tracer_Detail>;
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;
}
}
} // namespace chaiscript::eval
#endif

View File

@ -1,27 +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-2017, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2018, 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 &)
{
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;
};
}
}
} // namespace detail
} // namespace chaiscript
#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)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_WINDOWS_HPP_
@ -17,42 +17,33 @@
#include <windows.h>
#endif
namespace chaiscript
{
namespace detail
{
struct Loadable_Module
{
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());
}
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());
}
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);
}
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);
}
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;
static std::string get_error_message(DWORD t_err) {
using StringType = LPTSTR;
#if defined(_UNICODE) || defined(UNICODE)
std::wstring retval = L"Unknown Error";
@ -61,16 +52,15 @@ namespace chaiscript
#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)
{
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);
}
@ -78,13 +68,10 @@ namespace chaiscript
return to_string(retval);
}
struct DLModule
{
struct DLModule {
explicit DLModule(const std::string &t_filename)
: m_data(LoadLibrary(to_proper_string(t_filename).c_str()))
{
if (!m_data)
{
: m_data(LoadLibrary(to_proper_string(t_filename).c_str())) {
if (!m_data) {
throw chaiscript::exception::load_module_error(get_error_message(GetLastError()));
}
}
@ -94,40 +81,33 @@ namespace chaiscript
DLModule(const DLModule &) = delete;
DLModule &operator=(const DLModule &) = delete;
~DLModule()
{
FreeLibrary(m_data);
}
~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()));
}
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;
};
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())
{
: 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
} // namespace detail
} // namespace chaiscript
#endif

View File

@ -1,25 +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-2017, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2018, 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"
#include <cstdint>
namespace chaiscript
{
namespace utility
{
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
@ -30,7 +22,7 @@ namespace chaiscript
#pragma warning(push)
#pragma warning(disable : 4307)
#endif
return (*s == 0) ? h : fnv1a_32(s+1, ((h ^ (*s)) * 0x01000193));
return (*s == 0) ? h : fnv1a_32(s + 1, ((h ^ (*s)) * 0x01000193));
#ifdef CHAISCRIPT_MSVC
#pragma warning(pop)
#endif
@ -38,13 +30,9 @@ namespace chaiscript
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
}
}
}
} // namespace utility
} // namespace chaiscript
#endif

View File

@ -0,0 +1,94 @@
// 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 "../chaiscript_defines.hpp"
#include <cstdint>
namespace chaiscript {
namespace utility {
namespace fnv1a {
template<typename Itr>
static constexpr std::uint32_t hash(Itr begin, Itr end) noexcept {
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wsign-conversion"
#endif
#ifdef CHAISCRIPT_MSVC
#pragma warning(push)
#pragma warning(disable : 4307)
#endif
std::uint32_t h = 0x811c9dc5;
while (begin != end) {
h = (h ^ (*begin)) * 0x01000193;
++begin;
}
return h;
#ifdef CHAISCRIPT_MSVC
#pragma warning(pop)
#endif
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
}
template<size_t N>
static constexpr std::uint32_t hash(const char (&str)[N]) noexcept {
return hash(std::begin(str), std::end(str) - 1);
}
static constexpr std::uint32_t hash(std::string_view sv) noexcept {
return hash(sv.begin(), sv.end());
}
static inline std::uint32_t hash(const std::string &s) noexcept {
return hash(s.begin(), s.end());
}
} // namespace fnv1a
namespace jenkins_one_at_a_time {
template<typename Itr>
static constexpr std::uint32_t hash(Itr begin, Itr end) noexcept {
std::uint32_t hash = 0;
while (begin != end) {
hash += std::uint32_t(*begin);
hash += hash << 10;
hash ^= hash >> 6;
++begin;
}
hash += hash << 3;
hash ^= hash >> 11;
hash += hash << 15;
return hash;
}
template<size_t N>
static constexpr std::uint32_t hash(const char (&str)[N]) noexcept {
return hash(std::begin(str), std::end(str) - 1);
}
static constexpr std::uint32_t hash(std::string_view sv) noexcept {
return hash(sv.begin(), sv.end());
}
static inline std::uint32_t hash(const std::string &s) noexcept {
return hash(s.begin(), s.end());
}
} // namespace jenkins_one_at_a_time
using fnv1a::hash;
} // namespace utility
} // namespace chaiscript
#endif

File diff suppressed because it is too large Load Diff

View File

@ -3,148 +3,129 @@
#include "json.hpp"
namespace chaiscript
{
class json_wrap
{
public:
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");
static Module& library(Module& m)
{
return 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");
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;
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);
for (const auto &p : t_json.object_range()) {
m.insert(std::make_pair(p.first, from_json(p.second)));
}
return obj;
} catch (const chaiscript::exception::bad_boxed_cast &) {
// not a map
return Boxed_Value(m);
}
case json::JSON::Class::Array: {
std::vector<Boxed_Value> vec;
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]);
for (const auto &p : t_json.array_range()) {
vec.emplace_back(from_json(p));
}
return obj;
} catch (const chaiscript::exception::bad_boxed_cast &) {
// not a vector
return Boxed_Value(vec);
}
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");
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) {
try {
return from_json(json::JSON::Load(t_json));
} catch (const std::out_of_range &) {
throw std::runtime_error("Unparsed JSON input");
}
}
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(json::JSON::Class::Object);
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(json::JSON::Class::Array);
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<std::int64_t>());
}
} 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(json::JSON::Class::Object);
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
}
if (t_bv.is_null())
return json::JSON(); // a null value
throw std::runtime_error("Unknown object type to convert to JSON");
}
};
}
} // namespace chaiscript
#endif

View File

@ -0,0 +1,133 @@
#ifndef CHAISCRIPT_UTILITY_QUICK_FLAT_MAP_HPP
#define CHAISCRIPT_UTILITY_QUICK_FLAT_MAP_HPP
namespace chaiscript::utility {
template<typename Key, typename Value, typename Comparator = std::equal_to<>>
struct QuickFlatMap {
Comparator comparator;
template<typename Lookup>
auto find(const Lookup &s) noexcept {
return std::find_if(std::begin(data), std::end(data), [&s, this](const auto &d) { return comparator(d.first, s); });
}
template<typename Lookup>
auto find(const Lookup &s) const noexcept {
return std::find_if(std::cbegin(data), std::cend(data), [&s, this](const auto &d) { return comparator(d.first, s); });
}
template<typename Lookup>
auto find(const Lookup &s, const std::size_t t_hint) const noexcept {
if (data.size() > t_hint && comparator(data[t_hint].first, s)) {
const auto begin = std::cbegin(data);
return std::next(begin, static_cast<typename std::iterator_traits<std::decay_t<decltype(begin)>>::difference_type>(t_hint));
} else {
return find(s);
}
}
auto size() const noexcept { return data.size(); }
auto begin() const noexcept { return data.begin(); }
auto end() const noexcept { return data.end(); }
auto begin() noexcept { return data.begin(); }
auto end() noexcept { return data.end(); }
auto &back() noexcept { return data.back(); }
const auto &back() const noexcept { return data.back(); }
Value &operator[](const Key &s) {
const auto itr = find(s);
if (itr != data.end()) {
return itr->second;
} else {
grow();
return data.emplace_back(s, Value()).second;
}
}
Value &at_index(const std::size_t idx) noexcept { return data[idx].second; }
const Value &at_index(const std::size_t idx) const noexcept { return data[idx].second; }
bool empty() const noexcept { return data.empty(); }
template<typename Itr>
void assign(Itr begin, Itr end) {
data.assign(begin, end);
}
Value &at(const Key &s) {
const auto itr = find(s);
if (itr != data.end()) {
return itr->second;
} else {
throw std::out_of_range("Unknown key: " + s);
}
}
template<typename M>
auto insert_or_assign(Key &&key, M &&m) {
if (auto itr = find(key); itr != data.end()) {
*itr = std::forward<M>(m);
return std::pair{itr, false};
} else {
grow();
return std::pair{data.emplace(data.end(), std::move(key), std::forward<M>(m)), true};
}
}
template<typename M>
auto insert_or_assign(const Key &key, M &&m) {
if (auto itr = find(key); itr != data.end()) {
itr->second = std::forward<M>(m);
return std::pair{itr, false};
} else {
grow();
return std::pair{data.emplace(data.end(), key, std::forward<M>(m)), true};
}
}
const Value &at(const Key &s) const {
const auto itr = find(s);
if (itr != data.end()) {
return itr->second;
} else {
throw std::out_of_range("Unknown key: " + s);
}
}
template<typename Lookup>
size_t count(const Lookup &s) const noexcept {
return (find(s) != data.end()) ? 1 : 0;
}
std::vector<std::pair<Key, Value>> data;
using value_type = std::pair<Key, Value>;
using iterator = typename decltype(data)::iterator;
using const_iterator = typename decltype(data)::const_iterator;
std::pair<iterator, bool> insert(value_type &&value) {
if (const auto itr = find(value.first); itr != data.end()) {
return std::pair{itr, false};
} else {
grow();
return std::pair{data.insert(data.end(), std::move(value)), true};
}
}
void grow() {
if ((data.capacity() - data.size()) == 0) {
data.reserve(data.size() + 2);
}
}
};
} // namespace chaiscript::utility
#endif

View File

@ -0,0 +1,49 @@
// 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_STACK_VECTOR_HPP_
#define CHAISCRIPT_STACK_VECTOR_HPP_
#include <cstdint>
#include <string>
#include <type_traits>
template<typename T, std::size_t MaxSize>
struct Stack_Vector {
constexpr static auto aligned_size = sizeof(T) + (sizeof(T) & std::alignment_of_v<T>) > 0 ? std::alignment_of_v<T> : 0;
alignas(std::alignment_of_v<T>) char data[aligned_size * MaxSize];
[[nodiscard]] T &operator[](const std::size_t idx) noexcept { return *reinterpret_cast<T *>(&data + aligned_size * idx); }
[[nodiscard]] const T &operator[](const std::size_t idx) const noexcept {
return *reinterpret_cast<const T *>(&data + aligned_size * idx);
}
template<typename... Param>
T &emplace_back(Param &&...param) {
auto *p = new (&(*this)[m_size++]) T(std::forward<Param>(param)...);
return *p;
};
auto size() const noexcept { return m_size; };
void pop_back() noexcept(std::is_nothrow_destructible_v<T>) { (*this)[--m_size].~T(); }
~Stack_Vector() noexcept(std::is_nothrow_destructible_v<T>) {
auto loc = m_size - 1;
for (std::size_t pos = 0; pos < m_size; ++pos) {
(*this)[loc--].~T();
}
}
std::size_t m_size{0};
};
#endif CHAISCRIPT_STACK_VECTOR_HPP_

View File

@ -1,37 +1,54 @@
// 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)
// Copyright 2009-2018, 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
{
namespace chaiscript::utility {
struct Static_String {
template<size_t N>
constexpr Static_String(const char (&str)[N]) noexcept
: m_size(N - 1)
, data(&str[0]) {
}
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 noexcept { return m_size; }
constexpr const char *c_str() const noexcept { return data; }
constexpr auto begin() const noexcept { return data; }
constexpr auto end() const noexcept { return data + m_size; }
constexpr bool operator==(std::string_view other) const noexcept {
// return std::string_view(data, m_size) == other;
auto b1 = begin();
const auto e1 = end();
auto b2 = other.begin();
const auto e2 = other.end();
if (e1 - b1 != e2 - b2) {
return false;
}
while (b1 != e1) {
if (*b1 != *b2) {
return false;
}
constexpr size_t size() const {
return m_size;
++b1;
++b2;
}
return true;
}
constexpr const char *c_str() const {
return data;
}
bool operator==(const std::string &t_str) const noexcept { return std::equal(begin(), end(), std::cbegin(t_str), std::cend(t_str)); }
const size_t m_size;
const char *data = nullptr;
};
}
}
const size_t m_size;
const char *data = nullptr;
};
} // namespace chaiscript::utility
#endif

View File

@ -1,13 +1,12 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2018, 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_
@ -16,108 +15,90 @@
#include <utility>
#include <vector>
#include "../language/chaiscript_common.hpp"
#include "../dispatchkit/register_function.hpp"
#include "../dispatchkit/operators.hpp"
#include "../dispatchkit/register_function.hpp"
#include "../language/chaiscript_common.hpp"
namespace chaiscript::utility {
/// Single step command for registering a class with ChaiScript
///
/// \param[in,out] t_module Model to add class to
/// \param[in] t_class_name Name of the class being registered
/// \param[in] t_constructors Vector of constructors to add
/// \param[in] t_funcs Vector of methods to add
///
/// \example Adding a basic class to ChaiScript in one step
///
/// \code
/// chaiscript::utility::add_class<test>(*m,
/// "test",
/// { constructor<test ()>(),
/// constructor<test (const test &)>() },
/// { {fun(&test::function), "function"},
/// {fun(&test::function2), "function2"},
/// {fun(&test::function3), "function3"},
/// {fun(static_cast<std::string(test::*)(double)>(&test::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=)), "=" }
/// }
/// );
///
template<typename Class, typename ModuleType>
void add_class(ModuleType &t_module,
const std::string &t_class_name,
const std::vector<chaiscript::Proxy_Function> &t_constructors,
const std::vector<std::pair<chaiscript::Proxy_Function, std::string>> &t_funcs) {
t_module.add(chaiscript::user_type<Class>(), t_class_name);
namespace chaiscript
{
namespace utility
{
for (const chaiscript::Proxy_Function &ctor : t_constructors) {
t_module.add(ctor, t_class_name);
}
/// Single step command for registering a class with ChaiScript
///
/// \param[in,out] t_module Model to add class to
/// \param[in] t_class_name Name of the class being registered
/// \param[in] t_constructors Vector of constructors to add
/// \param[in] t_funcs Vector of methods to add
///
/// \example Adding a basic class to ChaiScript in one step
///
/// \code
/// chaiscript::utility::add_class<test>(*m,
/// "test",
/// { constructor<test ()>(),
/// constructor<test (const test &)>() },
/// { {fun(&test::function), "function"},
/// {fun(&test::function2), "function2"},
/// {fun(&test::function3), "function3"},
/// {fun(static_cast<std::string(test::*)(double)>(&test::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=)), "=" }
/// }
/// );
///
template<typename Class, typename ModuleType>
void add_class(ModuleType &t_module,
const std::string &t_class_name,
const std::vector<chaiscript::Proxy_Function> &t_constructors,
const std::vector<std::pair<chaiscript::Proxy_Function, std::string>> &t_funcs)
{
t_module.add(chaiscript::user_type<Class>(), t_class_name);
for(const chaiscript::Proxy_Function &ctor: t_constructors)
{
t_module.add(ctor, t_class_name);
}
for(const auto &fun: t_funcs)
{
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);
}
}
for (const auto &fun : t_funcs) {
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);
}
}
} // namespace chaiscript::utility
#endif

View File

@ -1,5 +1,7 @@
Copyright 2009-2016 Jason Turner
Copyright 2009-2012 Jonathan Turner.
BSD-3-Clause License
Copyright 2009-2018 Jason Turner
Copyright 2009-2012 Jonathan Turner.
All Rights Reserved.
Redistribution and use in source and binary forms, with or without

View File

@ -0,0 +1,11 @@
def var_test(int n)
{
for (var i = 0; i < n; ++i) {
var j = 0
}
}
var n = 500000
var_test(n) // takes 2.6 s

View File

@ -5,9 +5,8 @@ double f(const std::string &, double, bool) noexcept {
return .0;
}
int main()
{
chaiscript::ChaiScript chai(chaiscript::Std_Lib::library());
int main() {
chaiscript::ChaiScript chai;
chai.add(chaiscript::fun(&f), "f");
@ -16,5 +15,4 @@ int main()
f("str", 1.2, false);
}
)");
}

View File

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

113
readme.md
View File

@ -7,11 +7,6 @@ Master Status: [![Linux Build Status](https://travis-ci.org/ChaiScript/ChaiScrip
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
@ -25,45 +20,56 @@ 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)
[![Gitter](https://badges.gitter.im/JoinChat.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
native C++ application, it has some advantages over existing embedded scripting
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 how they would expect it to work. Being a
native C++ application, it has some advantages over existing embedded scripting
languages:
1. It uses a header-only approach, which makes it easy to integrate with
1. It uses a header-only approach, which makes it easy to integrate with
existing projects.
2. It maintains type safety between your C++ application and the user scripts.
3. It supports a variety of C++ techniques including callbacks, overloaded
3. It supports a variety of C++ techniques including callbacks, overloaded
functions, class methods, and stl containers.
Requirements
============
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).
ChaiScript requires a C++17 compiler to build with support for variadic
templates. It has been tested with gcc 7 and clang 6 (with libcxx).
Installation using vcpkg
========================
You can download and install ChaiScript using the [vcpkg](https://github.com/Microsoft/vcpkg/) dependency manager:
git clone https://github.com/Microsoft/vcpkg.git
cd vcpkg
./bootstrap-vcpkg.sh
./vcpkg integrate install
vcpkg install chaiscript
The ChaiScript port in vcpkg is kept up to date by Microsoft team members and community contributors. If the version is out of date, please [create an issue or pull request](https://github.com/Microsoft/vcpkg) on the vcpkg repository.
Usage
=====
* Add the ChaiScript include directory to your project's header search path
* Add `#include <chaiscript/chaiscript.hpp>` to your source file
* Instantiate the ChaiScript engine in your application. For example, create a
* Instantiate the ChaiScript engine in your application. For example, create a
new engine with the name `chai` like so: `chaiscript::ChaiScript chai`
* The default behavior is to load the ChaiScript standard library from a
* The default behavior is to load the ChaiScript standard library from a
loadable module. A second option is to compile the library into your code,
see below for an example.
Once instantiated, the engine is ready to start running ChaiScript source. You
have two main options for processing ChaiScript source: a line at a time using
Once instantiated, the engine is ready to start running ChaiScript source. You
have two main options for processing ChaiScript source: a line at a time using
`chai.eval(string)` and a file at a time using `chai.eval_file(fname)`
To make functions in your C++ code visible to scripts, they must be registered
To make functions in your C++ code visible to scripts, they must be registered
with the scripting engine. To do so, call add:
chai.add(chaiscript::fun(&my_function), "my_function_name");
@ -73,58 +79,35 @@ Once registered the function will be visible to scripts as "my_function_name"
Examples
========
ChaiScript is similar to ECMAScript (aka JavaScript(tm)), but with some
modifications to make it easier to use. For usage examples see the "samples"
directory, and for more in-depth look at the language, the unit tests in the
ChaiScript is similar to ECMAScript (aka JavaScript(tm)), but with some
modifications to make it easier to use. For usage examples see the "samples"
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
possible way of working with the library. For further documentation generate
the doxygen documentation in the build folder or see the website
For examples of how to register parts of your C++ application, see
"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.
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,25 @@
Notes:
=======
Current Version: 6.0.0
Current Version: 6.1.1
### Changes since 6.1.0
* Handle the returning of `&` to `*` types. This specifically comes up with `std::vector<int *>` and similar containers
* Update CMake to use `LIBDIR` instead of `lib` #502 by @guoyunhe
* Add documentation for installing ChaiScript with vcpkg #500 by @grdowns
* Fix warning for implicit 'this' lambda capture in C++20 #495 by @Josh-Thompson
### Changes since 6.0.0
* Add namespacing support #290 @stephenberry
* Add utf parsing support
* cheatsheet.md updates
* `add_class` utility support for scoped enums #306 @StanEpp
* Parser optimizations #300 @niXman
* Various JSON fixes #377 #400 #409 #371 @totalgee @dinghram @arcoRocks
* Various cleanups, bugfixes and warning fixes and minor performance improvements
* Support for C++17 compilers!
* Support for UTF8 BOM #439 @AlekMosingiewicz @MarioLiebisch
### Changes since 5.8.6

12
samples/BUCK Normal file
View File

@ -0,0 +1,12 @@
cxx_binary(
name = 'example',
srcs = [
'example.cpp',
],
compiler_flags = [
'-std=c++14',
],
deps = [
'//:chaiscript',
],
)

View File

@ -1,61 +1,53 @@
#include <chaiscript/chaiscript.hpp>
class Entity
{
public:
int width;
int height;
int x;
int y;
std::string name;
class Entity {
public:
int width;
int height;
int x;
int y;
std::string name;
std::function<void (Entity &)> updater;
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))
{
}
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);
}
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);
}
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);
}
// 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;
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()
{
int main() {
chaiscript::ChaiScript chai;
chai.add(chaiscript::fun(&Entity::width), "width");
@ -71,7 +63,6 @@ int main()
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");
@ -92,11 +83,5 @@ int main()
print(f.get_entity("entity3").x == 20) // this one has no updater, so it stays the same
)"";
chai.eval(script);
}

View File

@ -1,13 +1,12 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2018, 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>
@ -19,43 +18,38 @@
#include <chaiscript/chaiscript.hpp>
#ifdef READLINE_AVAILABLE
#include <readline/readline.h>
#include <readline/history.h>
#include <readline/readline.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
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
strcpy_s(d, len + 1, s); // Copy the characters
#else
strncpy(d, s, len); // Copy the characters
strncpy(d, s, len); // Copy the characters
#endif
d[len] = '\0';
return d; // Return the new string
return d; // Return the new string
}
char* readline(const char* p)
{
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(){}
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 *cast_module_symbol(std::vector<std::string> (*t_path)()) {
union cast_union {
std::vector<std::string> (*in_ptr)();
void *out_ptr;
};
@ -64,11 +58,11 @@ void *cast_module_symbol(std::vector<std::string>(*t_path)())
return c.out_ptr;
}
std::vector<std::string> default_search_paths()
{
std::vector<std::string> default_search_paths() {
std::vector<std::string> paths;
#ifdef CHAISCRIPT_WINDOWS // force no unicode
#ifndef CHAISCRIPT_NO_DYNLOAD
#ifdef CHAISCRIPT_WINDOWS // force no unicode
CHAR path[4096];
int size = GetModuleFileNameA(0, path, sizeof(path) - 1);
@ -76,14 +70,12 @@ std::vector<std::string> default_search_paths()
size_t lastslash = exepath.rfind('\\');
size_t secondtolastslash = exepath.rfind('\\', lastslash - 1);
if (lastslash != std::string::npos)
{
if (lastslash != std::string::npos) {
paths.push_back(exepath.substr(0, lastslash));
}
if (secondtolastslash != std::string::npos)
{
return{ exepath.substr(0, secondtolastslash) + "\\lib\\chaiscript\\" };
if (secondtolastslash != std::string::npos) {
return {exepath.substr(0, secondtolastslash) + "\\lib\\chaiscript\\"};
}
#else
@ -92,29 +84,23 @@ std::vector<std::string> default_search_paths()
std::vector<char> buf(2048);
ssize_t size = -1;
if ((size = readlink("/proc/self/exe", &buf.front(), buf.size())) > 0)
{
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)
{
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)
{
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())
{
if (exepath.empty()) {
Dl_info rInfo;
memset(&rInfo, 0, sizeof(rInfo));
if (!dladdr(cast_module_symbol(&default_search_paths), &rInfo) || !rInfo.dli_fname) {
@ -127,62 +113,55 @@ std::vector<std::string> default_search_paths()
size_t lastslash = exepath.rfind('/');
size_t secondtolastslash = exepath.rfind('/', lastslash - 1);
if (lastslash != std::string::npos)
{
if (lastslash != std::string::npos) {
paths.push_back(exepath.substr(0, lastslash));
}
if (secondtolastslash != std::string::npos)
{
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::cout << "ChaiScript evaluator. To evaluate an expression, type it and press <enter>.\n";
std::cout << "Additionally, you can inspect the runtime system using:\n";
std::cout << " dump_system() - outputs all functions registered to the system\n";
std::cout << " dump_object(x) - dumps information about the given symbol\n";
} else {
std::cout << "usage : chai [option]+\n";
std::cout << "option:\n";
std::cout << " -h | --help\n";
std::cout << " -i | --interactive\n";
std::cout << " -c | --command cmd\n";
std::cout << " -v | --version\n";
std::cout << " - --stdin\n";
std::cout << " filepath\n";
}
}
std::string helloWorld(const std::string &t_name)
{
std::string helloWorld(const std::string &t_name) {
return "Hello " + t_name + "!";
}
bool throws_exception(const std::function<void()> &f)
{
bool throws_exception(const std::function<void()> &f) {
try {
f();
}
catch (...) {
} catch (...) {
return true;
}
return false;
}
chaiscript::exception::eval_error get_eval_error(const std::function<void()> &f)
{
chaiscript::exception::eval_error get_eval_error(const std::function<void()> &f) {
try {
f();
}
catch (const chaiscript::exception::eval_error &e) {
} catch (const chaiscript::exception::eval_error &e) {
return e;
}
@ -198,13 +177,11 @@ std::string get_next_command() {
std::string val(input_raw);
size_t pos = val.find_first_not_of("\t \n");
if (pos != std::string::npos)
{
if (pos != std::string::npos) {
val.erase(0, pos);
}
pos = val.find_last_not_of("\t \n");
if (pos != std::string::npos)
{
if (pos != std::string::npos) {
val.erase(pos + 1, std::string::npos);
}
@ -213,11 +190,7 @@ std::string get_next_command() {
::free(input_raw);
}
}
if (retval == "quit"
|| retval == "exit"
|| retval == "help"
|| retval == "version")
{
if (retval == "quit" || retval == "exit" || retval == "help" || retval == "version") {
retval += "(0)";
}
return retval;
@ -229,8 +202,7 @@ void myexit(int return_val) {
exit(return_val);
}
void interactive(chaiscript::ChaiScript& chai)
{
void interactive(chaiscript::ChaiScript &chai) {
using_history();
for (;;) {
@ -239,32 +211,28 @@ void interactive(chaiscript::ChaiScript& chai)
// evaluate input
chaiscript::Boxed_Value val = chai.eval(input);
//Then, we try to print the result of the evaluation to the user
// Then, we try to print the result of the evaluation to the user
if (!val.get_type_info().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
std::cout << chai.eval<std::function<std::string(const chaiscript::Boxed_Value &bv)>>("to_string")(val) << '\n';
} catch (...) {
} // If we can't, do nothing
}
}
catch (const chaiscript::exception::eval_error &ee) {
} 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 << "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 << '\n';
} 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.
int main(int argc, char *argv[]) {
// Disable deprecation warning for getenv call.
#ifdef CHAISCRIPT_MSVC
#pragma warning(push)
#pragma warning(disable : 4996)
@ -279,8 +247,7 @@ int main(int argc, char *argv[])
std::vector<std::string> usepaths;
usepaths.push_back("");
if (usepath)
{
if (usepath) {
usepaths.push_back(usepath);
}
@ -288,12 +255,11 @@ int main(int argc, char *argv[])
std::vector<std::string> searchpaths = default_search_paths();
modulepaths.insert(modulepaths.end(), searchpaths.begin(), searchpaths.end());
modulepaths.push_back("");
if (modulepath)
{
if (modulepath) {
modulepaths.push_back(modulepath);
}
//chaiscript::ChaiScript chai(modulepaths, usepaths);
// chaiscript::ChaiScript chai(modulepaths, usepaths);
chaiscript::ChaiScript chai(usepaths);
chai.add(chaiscript::fun(&myexit), "exit");
@ -306,8 +272,7 @@ int main(int argc, char *argv[])
clock_t begin = clock();
for (int i = 0; i < 1000; i++)
{
for (int i = 0; i < 1000; i++) {
std::string str = helloWorld("Bob12345");
fwrite(str.c_str(), 1, str.size(), stdout);
}
@ -315,17 +280,17 @@ int main(int argc, char *argv[])
clock_t end = clock();
double elapsed_secs = double(end - begin) / CLOCKS_PER_SEC;
//begin = clock();
// 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");
// 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);
// 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) {
@ -335,69 +300,64 @@ int main(int argc, char *argv[])
std::string arg(i ? argv[i] : "--interactive");
enum {
eInteractive
, eCommand
, eFile
} mode = eCommand;
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 {
} else {
arg = argv[++i];
}
}
else if (arg == "-" || arg == "--stdin") {
} else if (arg == "-" || arg == "--stdin") {
arg = "";
std::string line;
while (std::getline(std::cin, line)) {
arg += line + '\n';
}
}
else if (arg == "-v" || arg == "--version") {
} else if (arg == "-v" || arg == "--version") {
arg = "version()";
}
else if (arg == "-h" || arg == "--help") {
} else if (arg == "-h" || arg == "--help") {
arg = "help(-1)";
}
else if (arg == "-i" || arg == "--interactive") {
} else if (arg == "-i" || arg == "--interactive") {
mode = eInteractive;
}
else if (arg.find('-') == 0) {
} else if (arg.find('-') == 0) {
std::cout << "unrecognised argument " << arg << std::endl;
return EXIT_FAILURE;
}
else {
} else {
mode = eFile;
}
chaiscript::Boxed_Value val;
try {
switch (mode) {
case eInteractive: interactive(chai); break;
case eCommand: val = chai.eval(arg); break;
case eInteractive:
interactive(chai);
break;
case eCommand:
val = chai.eval(arg);
break;
case eFile: {
begin = clock();
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;
}
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) {
} catch (const chaiscript::exception::eval_error &ee) {
std::cout << ee.pretty_print();
std::cout << std::endl;
return EXIT_FAILURE;
}
catch (std::exception &e) {
} catch (std::exception &e) {
std::cout << e.what() << std::endl;
return EXIT_FAILURE;
}
@ -405,4 +365,3 @@ int main(int argc, char *argv[])
return EXIT_SUCCESS;
}

View File

@ -1,79 +1,66 @@
#include <chaiscript/chaiscript.hpp>
class BaseClass
{
public:
BaseClass()
{
class BaseClass {
public:
BaseClass() = default;
BaseClass(const BaseClass &) = default;
virtual ~BaseClass() = default;
virtual std::string doSomething(float, double) const = 0;
void setValue(const std::string &t_val) {
if (validateValue(t_val)) {
m_value = t_val;
}
}
BaseClass(const BaseClass &) = default;
std::string getValue() const { return m_value; }
virtual ~BaseClass() {}
protected:
virtual bool validateValue(const std::string &t_val) = 0;
virtual std::string doSomething(float, double) const = 0;
void setValue(const std::string &t_val) {
if (validateValue(t_val))
{
m_value = t_val;
}
}
std::string getValue() const {
return m_value;
}
protected:
virtual bool validateValue(const std::string &t_val) = 0;
private:
std::string m_value;
private:
std::string m_value;
};
class ChaiScriptDerived : public BaseClass
{
public:
ChaiScriptDerived(const std::vector<chaiscript::Boxed_Value> &t_funcs)
{
// using the range-checked .at() methods to give us an exception
// instead of a crash if the user passed in too-few params
tie(t_funcs.at(0), m_doSomethingImpl);
tie(t_funcs.at(1), m_validateValueImpl);
}
class ChaiScriptDerived : public BaseClass {
public:
ChaiScriptDerived(const std::vector<chaiscript::Boxed_Value> &t_funcs) {
// using the range-checked .at() methods to give us an exception
// instead of a crash if the user passed in too-few params
tie(t_funcs.at(0), m_doSomethingImpl);
tie(t_funcs.at(1), m_validateValueImpl);
}
std::string doSomething(float f, double d) const override
{
assert(m_doSomethingImpl);
return m_doSomethingImpl(*this, f, d);
}
std::string doSomething(float f, double d) const override {
assert(m_doSomethingImpl);
return m_doSomethingImpl(*this, f, d);
}
protected:
bool validateValue(const std::string &t_val) override
{
assert(m_validateValueImpl);
return m_validateValueImpl(*this, t_val);
}
protected:
bool validateValue(const std::string &t_val) override {
assert(m_validateValueImpl);
return m_validateValueImpl(*this, t_val);
}
private:
template<typename Param>
void tie(const chaiscript::Boxed_Value &t_func, Param &t_param)
{
t_param = chaiscript::boxed_cast<Param>(t_func);
}
private:
template<typename Param>
void tie(const chaiscript::Boxed_Value &t_func, Param &t_param) {
t_param = chaiscript::boxed_cast<Param>(t_func);
}
std::function<std::string (const ChaiScriptDerived&, float, double)> m_doSomethingImpl;
std::function<bool (ChaiScriptDerived&, const std::string &t_val)> m_validateValueImpl;
std::function<std::string(const ChaiScriptDerived &, float, double)> m_doSomethingImpl;
std::function<bool(ChaiScriptDerived &, const std::string &t_val)> m_validateValueImpl;
};
int main()
{
int main() {
chaiscript::ChaiScript chai;
chai.add(chaiscript::fun(&BaseClass::doSomething), "doSomething");
chai.add(chaiscript::fun(&BaseClass::setValue), "setValue");
chai.add(chaiscript::fun(&BaseClass::getValue), "getValue");
chai.add(chaiscript::constructor<ChaiScriptDerived (const std::vector<chaiscript::Boxed_Value> &)>(), "ChaiScriptDerived");
chai.add(chaiscript::constructor<ChaiScriptDerived(const std::vector<chaiscript::Boxed_Value> &)>(), "ChaiScriptDerived");
chai.add(chaiscript::base_class<BaseClass, ChaiScriptDerived>());
chai.add(chaiscript::user_type<BaseClass>(), "BaseClass");
chai.add(chaiscript::user_type<ChaiScriptDerived>(), "ChaiScriptDerived");
@ -105,8 +92,8 @@ int main()
)"";
chai.eval(script);
BaseClass &myderived = chai.eval<ChaiScriptDerived&>("myderived");
BaseClass &myderived = chai.eval<ChaiScriptDerived &>("myderived");
// at this point in the code myderived is both a ChaiScript variable and a C++ variable. In both cases
// it is a derivation of BaseClass, and the implementation is provided via ChaiScript functors
@ -121,8 +108,7 @@ int main()
myderived.setValue("12345");
assert(myderived.getValue() == "1234");
chai.eval("myderived.setValue(\"new\")"); // set the value via chaiscript
chai.eval(R"(myderived.setValue("new"))"); // set the value via chaiscript
assert(myderived.getValue() == "new");
// call the other derived method via chaiscript and return the value to c++ land:
@ -131,5 +117,3 @@ int main()
// The whole process is fully orthogonal
}

View File

@ -3,12 +3,10 @@
#include <chaiscript/chaiscript.hpp>
#ifdef READLINE_AVAILABLE
#include <readline/readline.h>
#include <readline/history.h>
#include <readline/readline.h>
#endif
std::string get_next_command() {
#ifdef READLINE_AVAILABLE
char *input_raw;
@ -23,42 +21,32 @@ std::string get_next_command() {
#endif
}
void function(void)
{
void function(void) {
// do nothing
}
class test
{
class test {
chaiscript::ChaiScript chai;
chaiscript::ChaiScript::State backupState = chai.get_state();
public:
void ResetState()
{
public:
void ResetState() {
chai.set_state(backupState);
chai.add(chaiscript::fun(&function),"Whatever()");
chai.add(chaiscript::fun(&function), "Whatever()");
}
void RunFile(std::string sFile)
{
void RunFile(std::string sFile) {
try {
chaiscript::Boxed_Value val = chai.eval_file(sFile);
}
catch (std::exception &e) {
} catch (std::exception &e) {
std::cout << e.what() << '\n';
}
}
};
int main(int /*argc*/, char * /*argv*/[]) {
test myChai;
std::string command = "";
//
@ -70,12 +58,11 @@ int main(int /*argc*/, char * /*argv*/[]) {
// scenario3 - RunFile gets in changing intervals: memory usage goes up and down, but never as
// low as in case 1 scenario3 :
while(command != "quit")
{
for(int i = 1; i < 200; i++)
while (command != "quit") {
for (int i = 1; i < 200; i++)
myChai.ResetState();
if(command == "runfile")
if (command == "runfile")
myChai.RunFile("Test.chai");
command = get_next_command();

View File

@ -2,15 +2,12 @@
#include <chaiscript/dispatchkit/bootstrap_stl.hpp>
#include <chaiscript/dispatchkit/function_call.hpp>
int main( int /*argc*/ , char * /*argv*/[] )
{
int main(int /*argc*/, char * /*argv*/[]) {
chaiscript::ChaiScript ch;
try
{
static const char script[ ] =
R""(
try {
static const char script[] =
R""(
class Rectangle
{
@ -21,12 +18,9 @@ int main( int /*argc*/ , char * /*argv*/[] )
)"";
ch.eval( script );
}
catch ( const std::exception &e )
{
printf( " >>> Exception thrown: %s \n" , e.what( ) );
ch.eval(script);
} catch (const std::exception &e) {
printf(" >>> Exception thrown: %s \n", e.what());
}
return 1;

View File

@ -1,7 +1,6 @@
#include <chaiscript/chaiscript_stdlib.hpp>
// MSVC doesn't like that we are using C++ return types from our C declared module
// but this is the best way to do it for cross platform compatibility
#ifdef CHAISCRIPT_MSVC
@ -14,13 +13,10 @@
#pragma clang diagnostic ignored "-Wreturn-type-c-linkage"
#endif
CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_chaiscript_stdlib()
{
CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_chaiscript_stdlib() {
return chaiscript::Std_Lib::library();
}
#ifdef __llvm__
#pragma clang diagnostic pop
#endif

325
src/libfuzzer_client.cpp Normal file
View File

@ -0,0 +1,325 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2018, 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 "../static_libs/chaiscript_parser.hpp"
#include "../static_libs/chaiscript_stdlib.hpp"
#include <chaiscript/chaiscript.hpp>
#include "sha3.h"
#ifdef READLINE_AVAILABLE
#include <readline/history.h>
#include <readline/readline.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 * /*unused*/) {}
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(nullptr, 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) == 0 || rInfo.dli_fname == nullptr) {
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 + 1));
}
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>.\n";
std::cout << "Additionally, you can inspect the runtime system using:\n";
std::cout << " dump_system() - outputs all functions registered to the system\n";
std::cout << " dump_object(x) - dumps information about the given symbol\n";
} else {
std::cout << "usage : chai [option]+\n";
std::cout << "option:" << '\n';
std::cout << " -h | --help" << '\n';
std::cout << " -i | --interactive" << '\n';
std::cout << " -c | --command cmd" << '\n';
std::cout << " -v | --version" << '\n';
std::cout << " - --stdin" << '\n';
std::cout << " filepath" << '\n';
}
}
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 != nullptr) {
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_Basic &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) << '\n';
} catch (...) {
} // If we can't, do nothing
}
} catch (const chaiscript::exception::eval_error &ee) {
std::cout << ee.what();
if (!ee.call_stack.empty()) {
std::cout << "during evaluation at (" << ee.call_stack[0].start().line << ", " << ee.call_stack[0].start().column << ")";
}
std::cout << '\n';
} catch (const std::exception &e) {
std::cout << e.what();
std::cout << '\n';
}
}
}
double now() {
using namespace std::chrono;
auto now = high_resolution_clock::now();
return duration_cast<duration<double>>(now.time_since_epoch()).count();
}
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
chaiscript::ChaiScript chai;
chai.eval(R"chaiscript(
def assert_equal(x, y)
{
if (x == y)
{
// Passes
} else {
// Fails
print("assert_equal failure: got '" + to_string(y) + "' expected '" + to_string(x) + "'");
// exit(-1);
}
}
def assert_false(f)
{
if (f)
{
print("assert_false failure");
// exit(-1);
}
}
def assert_true(f)
{
if (!f)
{
print("assert_true failure");
// exit(-1);
}
}
def assert_not_equal(x, y)
{
if (!(x == y))
{
// Passes
} else {
// Fails
print("assert_not_equal failure: got " + to_string(y) + " which was not expected.");
// exit(-1);
}
}
def assert_throws(desc, x)
{
if (throws_exception(x))
{
// Passes
} else {
// Fails
print("assert_throws failure, function did not throw exception: " + to_string(desc));
// exit(-1);
}
})chaiscript");
SHA3 sha3;
std::string sha = sha3(data, size);
std::string input(reinterpret_cast<const char *>(data), size);
try {
chai.eval(std::string(reinterpret_cast<const char *>(data), size));
std::ofstream ofs("VALID/" + sha);
ofs << input;
} catch (const chaiscript::exception::eval_error &) {
std::ofstream ofs("EVAL_ERROR/" + sha);
ofs << input;
} catch (const chaiscript::Boxed_Value &) {
std::ofstream ofs("BOXED_VALUE/" + sha);
ofs << input;
} catch (const chaiscript::exception::load_module_error &e) {
std::cout << "Unhandled module load error\n"
<< e.what() << '\n';
} catch (const std::exception &) {
std::ofstream ofs("STD_EXCEPTION/" + sha);
ofs << input;
} catch (...) {
std::ofstream ofs("UNKOWN_EXCEPTION/" + sha);
ofs << input;
}
return 0;
}

View File

@ -1,13 +1,12 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2018, 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>
@ -16,48 +15,43 @@
#define _CRT_SECURE_NO_WARNINGS
#endif
#include <chaiscript/chaiscript_basic.hpp>
#include "../static_libs/chaiscript_parser.hpp"
#include "../static_libs/chaiscript_stdlib.hpp"
#include <chaiscript/chaiscript_basic.hpp>
#ifdef READLINE_AVAILABLE
#include <readline/readline.h>
#include <readline/history.h>
#include <readline/readline.h>
#else
char *mystrdup (const char *s) {
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
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
strcpy_s(d, len + 1, s); // Copy the characters
#else
strncpy(d,s,len); // Copy the characters
strncpy(d, s, len); // Copy the characters
#endif
d[len] = '\0';
return d; // Return the new string
return d; // Return the new string
}
char* readline(const char* p)
{
char *readline(const char *p) {
std::string retval;
std::cout << p ;
std::cout << p;
std::getline(std::cin, retval);
return std::cin.eof() ? nullptr : mystrdup(retval.c_str());
}
void add_history(const char* /*unused*/){}
void using_history(){}
void add_history(const char * /*unused*/) {}
void using_history() {}
#endif
void *cast_module_symbol(std::vector<std::string> (*t_path)())
{
union cast_union
{
void *cast_module_symbol(std::vector<std::string> (*t_path)()) {
union cast_union {
std::vector<std::string> (*in_ptr)();
void *out_ptr;
};
@ -67,25 +61,23 @@ void *cast_module_symbol(std::vector<std::string> (*t_path)())
return c.out_ptr;
}
std::vector<std::string> default_search_paths()
{
std::vector<std::string> default_search_paths() {
std::vector<std::string> paths;
#ifdef CHAISCRIPT_WINDOWS // force no unicode
#ifndef CHAISCRIPT_NO_DYNLOAD
#ifdef CHAISCRIPT_WINDOWS // force no unicode
CHAR path[4096];
int size = GetModuleFileNameA(nullptr, path, sizeof(path)-1);
int size = GetModuleFileNameA(nullptr, 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)
{
if (lastslash != std::string::npos) {
paths.push_back(exepath.substr(0, lastslash));
}
if (secondtolastslash != std::string::npos)
{
if (secondtolastslash != std::string::npos) {
return {exepath.substr(0, secondtolastslash) + "\\lib\\chaiscript\\"};
}
#else
@ -95,32 +87,26 @@ std::vector<std::string> default_search_paths()
std::vector<char> buf(2048);
ssize_t size = -1;
if ((size = readlink("/proc/self/exe", &buf.front(), buf.size())) >= 0)
{
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)
{
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)
{
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())
{
if (exepath.empty()) {
Dl_info rInfo;
memset( &rInfo, 0, sizeof(rInfo) );
if ( dladdr(cast_module_symbol(&default_search_paths), &rInfo) == 0 || rInfo.dli_fname == nullptr ) {
memset(&rInfo, 0, sizeof(rInfo));
if (dladdr(cast_module_symbol(&default_search_paths), &rInfo) == 0 || rInfo.dli_fname == nullptr) {
return paths;
}
@ -130,51 +116,48 @@ std::vector<std::string> default_search_paths()
size_t lastslash = exepath.rfind('/');
size_t secondtolastslash = exepath.rfind('/', lastslash - 1);
if (lastslash != std::string::npos)
{
paths.push_back(exepath.substr(0, lastslash+1));
if (lastslash != std::string::npos) {
paths.push_back(exepath.substr(0, lastslash + 1));
}
if (secondtolastslash != std::string::npos)
{
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 ) {
if (n >= 0) {
std::cout << "ChaiScript evaluator. To evaluate an expression, type it and press <enter>.\n";
std::cout << "Additionally, you can inspect the runtime system using:\n";
std::cout << " dump_system() - outputs all functions registered to the system\n";
std::cout << " dump_object(x) - dumps information about the given symbol\n";
} else {
std::cout << "usage : chai [option]+\n";
std::cout << "option:" << '\n';
std::cout << " -h | --help" << '\n';
std::cout << " -i | --interactive" << '\n';
std::cout << " -c | --command cmd" << '\n';
std::cout << " -v | --version" << '\n';
std::cout << " - --stdin" << '\n';
std::cout << " filepath" << '\n';
std::cout << "option:" << '\n';
std::cout << " -h | --help" << '\n';
std::cout << " -i | --interactive" << '\n';
std::cout << " -c | --command cmd" << '\n';
std::cout << " -v | --version" << '\n';
std::cout << " - --stdin" << '\n';
std::cout << " filepath" << '\n';
}
}
bool throws_exception(const std::function<void ()> &f)
{
std::string throws_exception(const std::function<void()> &f) {
try {
f();
} catch (...) {
return true;
} catch (const std::exception &e) {
return e.what();
}
return false;
return "";
}
chaiscript::exception::eval_error get_eval_error(const std::function<void ()> &f)
{
chaiscript::exception::eval_error get_eval_error(const std::function<void()> &f) {
try {
f();
} catch (const chaiscript::exception::eval_error &e) {
@ -186,21 +169,19 @@ chaiscript::exception::eval_error get_eval_error(const std::function<void ()> &f
std::string get_next_command() {
std::string retval("quit");
if ( ! std::cin.eof() ) {
if (!std::cin.eof()) {
char *input_raw = readline("eval> ");
if ( input_raw != nullptr ) {
if (input_raw != nullptr) {
add_history(input_raw);
std::string val(input_raw);
size_t pos = val.find_first_not_of("\t \n");
if (pos != std::string::npos)
{
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);
if (pos != std::string::npos) {
val.erase(pos + 1, std::string::npos);
}
retval = val;
@ -208,11 +189,7 @@ std::string get_next_command() {
::free(input_raw);
}
}
if( retval == "quit"
|| retval == "exit"
|| retval == "help"
|| retval == "version")
{
if (retval == "quit" || retval == "exit" || retval == "help" || retval == "version") {
retval += "(0)";
}
return retval;
@ -224,8 +201,7 @@ void myexit(int return_val) {
exit(return_val);
}
void interactive(chaiscript::ChaiScript_Basic& chai)
{
void interactive(chaiscript::ChaiScript_Basic &chai) {
using_history();
for (;;) {
@ -234,39 +210,34 @@ void interactive(chaiscript::ChaiScript_Basic& chai)
// evaluate input
chaiscript::Boxed_Value val = chai.eval(input);
//Then, we try to print the result of the evaluation to the user
// Then, we try to print the result of the evaluation to the user
if (!val.get_type_info().bare_equal(chaiscript::user_type<void>())) {
try {
std::cout << chai.eval<std::function<std::string (const chaiscript::Boxed_Value &bv)> >("to_string")(val) << '\n';
}
catch (...) {} //If we can't, do nothing
std::cout << chai.eval<std::function<std::string(const chaiscript::Boxed_Value &bv)>>("to_string")(val) << '\n';
} catch (...) {
} // If we can't, do nothing
}
}
catch (const chaiscript::exception::eval_error &ee) {
} catch (const chaiscript::exception::eval_error &ee) {
std::cout << ee.what();
if ( !ee.call_stack.empty() ) {
std::cout << "during evaluation at (" << ee.call_stack[0]->start().line << ", " << ee.call_stack[0]->start().column << ")";
if (!ee.call_stack.empty()) {
std::cout << "during evaluation at (" << ee.call_stack[0].start().line << ", " << ee.call_stack[0].start().column << ")";
}
std::cout << '\n';
}
catch (const std::exception &e) {
} catch (const std::exception &e) {
std::cout << e.what();
std::cout << '\n';
}
}
}
double now()
{
double now() {
using namespace std::chrono;
auto now = high_resolution_clock::now();
return duration_cast<duration<double>>(now.time_since_epoch()).count();
}
int main(int argc, char *argv[])
{
// Disable deprecation warning for getenv call.
int main(int argc, char *argv[]) {
// Disable deprecation warning for getenv call.
#ifdef CHAISCRIPT_MSVC
#pragma warning(push)
#pragma warning(disable : 4996)
@ -280,22 +251,20 @@ int main(int argc, char *argv[])
#endif
std::vector<std::string> usepaths;
usepaths.push_back("");
if (usepath != nullptr)
{
usepaths.push_back(usepath);
usepaths.emplace_back("");
if (usepath != nullptr) {
usepaths.emplace_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 != nullptr)
{
modulepaths.push_back(modulepath);
modulepaths.emplace_back("");
if (modulepath != nullptr) {
modulepaths.emplace_back(modulepath);
}
chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser(),modulepaths,usepaths);
chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(), create_chaiscript_parser(), modulepaths, usepaths);
chai.add(chaiscript::fun(&myexit), "exit");
chai.add(chaiscript::fun(&myexit), "quit");
@ -306,45 +275,51 @@ int main(int argc, char *argv[])
bool eval_error_ok = false;
bool boxed_exception_ok = false;
bool any_exception_ok = false;
for (int i = 0; i < argc; ++i) {
if ( i == 0 && argc > 1 ) {
if (i == 0 && argc > 1) {
++i;
}
std::string arg( i != 0 ? argv[i] : "--interactive" );
std::string arg(i != 0 ? argv[i] : "--interactive");
enum { eInteractive
, eCommand
, eFile
} mode = eCommand ;
enum {
eInteractive,
eCommand,
eFile
} mode
= eCommand;
if ( arg == "-c" || arg == "--command" ) {
if ( (i+1) >= argc ) {
if (arg == "-c" || arg == "--command") {
if ((i + 1) >= argc) {
std::cout << "insufficient input following " << arg << '\n';
return EXIT_FAILURE;
}
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 = "print(version())" ;
} else if ( arg == "-h" || arg == "--help" ) {
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 = "print(version())";
} else if (arg == "-h" || arg == "--help") {
arg = "help(-1)";
} else if ( arg == "-e" || arg == "--evalerrorok" ) {
} else if (arg == "-e" || arg == "--evalerrorok") {
eval_error_ok = true;
continue;
} else if ( arg == "--exception" ) {
} else if (arg == "--exception") {
boxed_exception_ok = true;
continue;
} else if ( arg == "-i" || arg == "--interactive" ) {
mode = eInteractive ;
} else if ( arg.find('-') == 0 ) {
} else if (arg == "--any-exception") {
any_exception_ok = true;
continue;
} else if (arg == "-i" || arg == "--interactive") {
mode = eInteractive;
} else if (arg.find('-') == 0) {
std::cout << "unrecognised argument " << arg << '\n';
return EXIT_FAILURE;
} else {
@ -352,7 +327,7 @@ int main(int argc, char *argv[])
}
try {
switch ( mode ) {
switch (mode) {
case eInteractive:
interactive(chai);
break;
@ -362,30 +337,33 @@ int main(int argc, char *argv[])
case eFile:
chai.eval_file(arg);
}
}
catch (const chaiscript::exception::eval_error &ee) {
} catch (const chaiscript::exception::eval_error &ee) {
std::cout << ee.pretty_print();
std::cout << '\n';
if (!eval_error_ok) {
return EXIT_FAILURE;
}
}
catch (const chaiscript::Boxed_Value &e) {
} catch (const chaiscript::Boxed_Value &e) {
std::cout << "Unhandled exception thrown of type " << e.get_type_info().name() << '\n';
if (!boxed_exception_ok) {
return EXIT_FAILURE;
}
} catch (const chaiscript::exception::load_module_error &e) {
std::cout << "Unhandled module load error\n"
<< e.what() << '\n';
} catch (std::exception &e) {
std::cout << "Unhandled standard exception: " << e.what() << '\n';
if (!any_exception_ok) {
throw;
}
} catch (...) {
std::cout << "Unhandled unknown exception" << '\n';
if (!any_exception_ok) {
throw;
}
}
catch (const chaiscript::exception::load_module_error &e) {
std::cout << "Unhandled module load error\n" << e.what() << '\n';
}
// catch (std::exception &e) {
// std::cout << e.what() << '\n';
// return EXIT_FAILURE;
// }
}
return EXIT_SUCCESS;

View File

@ -4,64 +4,52 @@
// and Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#include <iostream>
// NOT TO BE USED AS A SOURCE OF BEST PRACTICES
// FOR CHAISCRIPT
#include <ctime>
#include <iostream>
#include <chaiscript/chaiscript.hpp>
#include <chaiscript/dispatchkit/bootstrap_stl.hpp>
#include <chaiscript/dispatchkit/function_call.hpp>
void log(const std::string &msg)
{
void log(const std::string &msg) {
std::cout << "[" << time(nullptr) << "] " << msg << '\n';
}
void log(const std::string &module, const std::string &msg)
{
void log(const std::string &module, const std::string &msg) {
std::cout << "[" << time(nullptr) << "] <" << module << "> " << msg << '\n';
}
void bound_log(const std::string &msg)
{
void bound_log(const std::string &msg) {
log(msg);
}
void hello_world(const chaiscript::Boxed_Value & /*o*/)
{
void hello_world(const chaiscript::Boxed_Value & /*o*/) {
std::cout << "Hello World\n";
}
void hello_constructor(const chaiscript::Boxed_Value & /*o*/)
{
void hello_constructor(const chaiscript::Boxed_Value & /*o*/) {
std::cout << "Hello Constructor\n";
}
struct System {
std::map<std::string, std::function<std::string(const std::string &)>> m_callbacks;
struct System
{
std::map<std::string, std::function<std::string (const std::string &) > > m_callbacks;
void add_callback(const std::string &t_name,
const std::function<std::string (const std::string &)> &t_func)
{
void add_callback(const std::string &t_name, const std::function<std::string(const std::string &)> &t_func) {
m_callbacks[t_name] = t_func;
}
void do_callbacks(const std::string &inp)
{
void do_callbacks(const std::string &inp) {
log("Running Callbacks: " + inp);
for (std::map<std::string, std::function<std::string (const std::string &)> >::iterator itr = m_callbacks.begin();
itr != m_callbacks.end();
++itr)
{
log("Callback: " + itr->first, itr->second(inp));
for (auto &m_callback : m_callbacks) {
log("Callback: " + m_callback.first, m_callback.second(inp));
}
}
};
void take_shared_ptr(const std::shared_ptr<const std::string> &p)
{
void take_shared_ptr(const std::shared_ptr<const std::string> &p) {
std::cout << *p << '\n';
}
@ -69,109 +57,105 @@ int main(int /*argc*/, char * /*argv*/[]) {
using namespace chaiscript;
ChaiScript chai;
//Create a new system object and share it with the chaiscript engine
// Create a new system object and share it with the chaiscript engine
System system;
chai.add_global(var(&system), "system");
//Add a bound callback method
// Add a bound callback method
chai.add(fun(&System::add_callback, std::ref(system)), "add_callback_bound");
//Register the two methods of the System structure.
// Register the two methods of the System structure.
chai.add(fun(&System::add_callback), "add_callback");
chai.add(fun(&System::do_callbacks), "do_callbacks");
chai.add(fun(&take_shared_ptr), "take_shared_ptr");
// Let's use chaiscript to add a new lambda callback to our system.
// Let's use chaiscript to add a new lambda callback to our system.
// The function "{ 'Callback1' + x }" is created in chaiscript and passed into our C++ application
// in the "add_callback" function of struct System the chaiscript function is converted into a
// in the "add_callback" function of struct System the chaiscript function is converted into a
// std::function, so it can be handled and called easily and type-safely
chai.eval("system.add_callback(\"#1\", fun(x) { \"Callback1 \" + x });");
chai.eval(R"(system.add_callback("#1", fun(x) { "Callback1 " + x });)");
// Because we are sharing the "system" object with the chaiscript engine we have equal
// access to it both from within chaiscript and from C++ code
system.do_callbacks("TestString");
chai.eval("system.do_callbacks(\"TestString\");");
chai.eval(R"(system.do_callbacks("TestString");)");
// The log function is overloaded, therefore we have to give the C++ compiler a hint as to which
// version we want to register. One way to do this is to create a typedef of the function pointer
// then cast your function to that typedef.
typedef void (*PlainLog)(const std::string &);
typedef void (*ModuleLog)(const std::string &, const std::string &);
using PlainLog = void (*)(const std::string &);
using ModuleLog = void (*)(const std::string &, const std::string &);
chai.add(fun(PlainLog(&log)), "log");
chai.add(fun(ModuleLog(&log)), "log");
chai.eval("log(\"Test Message\")");
chai.eval(R"(log("Test Message"))");
// A shortcut to using eval is just to use the chai operator()
chai("log(\"Test Module\", \"Test Message\");");
chai(R"(log("Test Module", "Test Message");)");
//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](){ return system.do_callbacks("Bound Test"); }), "do_callbacks");
// 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]() { return system.do_callbacks("Bound Test"); }), "do_callbacks");
//Call bound version of do_callbacks
// Call bound version of do_callbacks
chai("do_callbacks()");
std::function<void ()> caller = chai.eval<std::function<void ()> >("fun() { system.do_callbacks(\"From Functor\"); }");
std::function<void()> caller = chai.eval<std::function<void()>>(R"(fun() { system.do_callbacks("From Functor"); })");
caller();
//If we would like a type-safe return value from all call, we can use
//the templated version of eval:
// If we would like a type-safe return value from all call, we can use
// the templated version of eval:
int i = chai.eval<int>("5+5");
std::cout << "5+5: " << i << '\n';
//Add a new variable
// Add a new variable
chai("var scripti = 15");
//We can even get a handle to the variables in the system
// We can even get a handle to the variables in the system
int &scripti = chai.eval<int &>("scripti");
std::cout << "scripti: " << scripti << '\n';
scripti *= 2;
std::cout << "scripti (updated): " << scripti << '\n';
chai("print(\"Scripti from chai: \" + to_string(scripti))");
chai(R"(print("Scripti from chai: " + to_string(scripti)))");
//To do: Add examples of handling Boxed_Values directly when needed
// To do: Add examples of handling Boxed_Values directly when needed
//Creating a functor on the stack and using it immediately
int x = chai.eval<std::function<int (int, int)> >("fun (x, y) { return x + y; }")(5, 6);
// Creating a functor on the stack and using it immediately
int x = chai.eval<std::function<int(int, int)>>("fun (x, y) { return x + y; }")(5, 6);
std::stringstream ss;
ss << x;
log("Functor test output", ss.str());
chai.add(var(std::shared_ptr<int>()), "nullvar");
chai("print(\"This should be true.\"); print(nullvar.is_var_null())");
chai(R"(print("This should be true."); print(nullvar.is_var_null()))");
// test the global const action
chai.add_global_const(const_var(1), "constvar");
chai("def getvar() { return constvar; }");
chai("print( getvar() )");
//Ability to create our own container types when needed. std::vector and std::map are
//mostly supported currently
chai.add(bootstrap::standard_library::vector_type<std::vector<int> >("IntVector"));
// Ability to create our own container types when needed. std::vector and std::map are
// mostly supported currently
// chai.add(bootstrap::standard_library::vector_type<std::vector<int> >("IntVector"));
// Test ability to register a function that excepts a shared_ptr version of a type
chai("take_shared_ptr(\"Hello World as a shared_ptr\");");
chai(R"(take_shared_ptr("Hello World as a shared_ptr");)");
chai.add(fun(&bound_log, std::string("Msg")), "BoundFun");
//Dynamic objects test
// Dynamic objects test
chai.add(chaiscript::Proxy_Function(new dispatch::detail::Dynamic_Object_Function("TestType", fun(&hello_world))), "hello_world");
chai.add(chaiscript::Proxy_Function(new dispatch::detail::Dynamic_Object_Constructor("TestType", fun(&hello_constructor))), "TestType");
// chai.add(fun(std::function<Boxed_Value (dispatch::Dynamic_Object &)>(std::bind(&dispatch::detail::Dynamic_Object_Attribute::func, "TestType", "attr", std::placeholders::_1))), "attr");
// chai.add(fun(std::function<Boxed_Value (dispatch::Dynamic_Object &)>(std::bind(&dispatch::detail::Dynamic_Object_Attribute::func,
// "TestType", "attr", std::placeholders::_1))), "attr");
chai.eval("var x = TestType()");
// chai.eval("x.attr = \"hi\"");
// chai.eval("print(x.attr)");
// chai.eval("x.attr = \"hi\"");
// chai.eval("print(x.attr)");
chai.eval("x.hello_world()");
}

289
src/sha3.cpp Normal file
View File

@ -0,0 +1,289 @@
// //////////////////////////////////////////////////////////
// sha3.cpp
// Copyright (c) 2014,2015 Stephan Brumme. All rights reserved.
// see http://create.stephan-brumme.com/disclaimer.html
//
#include "sha3.h"
// big endian architectures need #define __BYTE_ORDER __BIG_ENDIAN
#ifndef _MSC_VER
#include <endian.h>
#endif
/// same as reset()
SHA3::SHA3(Bits bits)
: m_blockSize(200 - 2 * (bits / 8))
, m_bits(bits) {
reset();
}
/// restart
void SHA3::reset() {
for (size_t i = 0; i < StateSize; i++)
m_hash[i] = 0;
m_numBytes = 0;
m_bufferSize = 0;
}
/// constants and local helper functions
namespace {
const unsigned int Rounds = 24;
const uint64_t XorMasks[Rounds]
= {0x0000000000000001ULL, 0x0000000000008082ULL, 0x800000000000808aULL, 0x8000000080008000ULL, 0x000000000000808bULL, 0x0000000080000001ULL, 0x8000000080008081ULL, 0x8000000000008009ULL, 0x000000000000008aULL, 0x0000000000000088ULL, 0x0000000080008009ULL, 0x000000008000000aULL, 0x000000008000808bULL, 0x800000000000008bULL, 0x8000000000008089ULL, 0x8000000000008003ULL, 0x8000000000008002ULL, 0x8000000000000080ULL, 0x000000000000800aULL, 0x800000008000000aULL, 0x8000000080008081ULL, 0x8000000000008080ULL, 0x0000000080000001ULL, 0x8000000080008008ULL};
/// rotate left and wrap around to the right
inline uint64_t rotateLeft(uint64_t x, uint8_t numBits) {
return (x << numBits) | (x >> (64 - numBits));
}
/// convert litte vs big endian
inline uint64_t swap(uint64_t x) {
#if defined(__GNUC__) || defined(__clang__)
return __builtin_bswap64(x);
#endif
#ifdef _MSC_VER
return _byteswap_uint64(x);
#endif
return (x >> 56) | ((x >> 40) & 0x000000000000FF00ULL) | ((x >> 24) & 0x0000000000FF0000ULL) | ((x >> 8) & 0x00000000FF000000ULL)
| ((x << 8) & 0x000000FF00000000ULL) | ((x << 24) & 0x0000FF0000000000ULL) | ((x << 40) & 0x00FF000000000000ULL) | (x << 56);
}
/// return x % 5 for 0 <= x <= 9
unsigned int mod5(unsigned int x) {
if (x < 5)
return x;
return x - 5;
}
} // namespace
/// process a full block
void SHA3::processBlock(const void *data) {
#if defined(__BYTE_ORDER) && (__BYTE_ORDER != 0) && (__BYTE_ORDER == __BIG_ENDIAN)
#define LITTLEENDIAN(x) swap(x)
#else
#define LITTLEENDIAN(x) (x)
#endif
const uint64_t *data64 = (const uint64_t *)data;
// mix data into state
for (unsigned int i = 0; i < m_blockSize / 8; i++)
m_hash[i] ^= LITTLEENDIAN(data64[i]);
// re-compute state
for (unsigned int round = 0; round < Rounds; round++) {
// Theta
uint64_t coefficients[5];
for (unsigned int i = 0; i < 5; i++)
coefficients[i] = m_hash[i] ^ m_hash[i + 5] ^ m_hash[i + 10] ^ m_hash[i + 15] ^ m_hash[i + 20];
for (unsigned int i = 0; i < 5; i++) {
uint64_t one = coefficients[mod5(i + 4)] ^ rotateLeft(coefficients[mod5(i + 1)], 1);
m_hash[i] ^= one;
m_hash[i + 5] ^= one;
m_hash[i + 10] ^= one;
m_hash[i + 15] ^= one;
m_hash[i + 20] ^= one;
}
// temporary
uint64_t one;
// Rho Pi
uint64_t last = m_hash[1];
one = m_hash[10];
m_hash[10] = rotateLeft(last, 1);
last = one;
one = m_hash[7];
m_hash[7] = rotateLeft(last, 3);
last = one;
one = m_hash[11];
m_hash[11] = rotateLeft(last, 6);
last = one;
one = m_hash[17];
m_hash[17] = rotateLeft(last, 10);
last = one;
one = m_hash[18];
m_hash[18] = rotateLeft(last, 15);
last = one;
one = m_hash[3];
m_hash[3] = rotateLeft(last, 21);
last = one;
one = m_hash[5];
m_hash[5] = rotateLeft(last, 28);
last = one;
one = m_hash[16];
m_hash[16] = rotateLeft(last, 36);
last = one;
one = m_hash[8];
m_hash[8] = rotateLeft(last, 45);
last = one;
one = m_hash[21];
m_hash[21] = rotateLeft(last, 55);
last = one;
one = m_hash[24];
m_hash[24] = rotateLeft(last, 2);
last = one;
one = m_hash[4];
m_hash[4] = rotateLeft(last, 14);
last = one;
one = m_hash[15];
m_hash[15] = rotateLeft(last, 27);
last = one;
one = m_hash[23];
m_hash[23] = rotateLeft(last, 41);
last = one;
one = m_hash[19];
m_hash[19] = rotateLeft(last, 56);
last = one;
one = m_hash[13];
m_hash[13] = rotateLeft(last, 8);
last = one;
one = m_hash[12];
m_hash[12] = rotateLeft(last, 25);
last = one;
one = m_hash[2];
m_hash[2] = rotateLeft(last, 43);
last = one;
one = m_hash[20];
m_hash[20] = rotateLeft(last, 62);
last = one;
one = m_hash[14];
m_hash[14] = rotateLeft(last, 18);
last = one;
one = m_hash[22];
m_hash[22] = rotateLeft(last, 39);
last = one;
one = m_hash[9];
m_hash[9] = rotateLeft(last, 61);
last = one;
one = m_hash[6];
m_hash[6] = rotateLeft(last, 20);
last = one;
m_hash[1] = rotateLeft(last, 44);
// Chi
for (unsigned int j = 0; j < 25; j += 5) {
// temporaries
uint64_t one = m_hash[j];
uint64_t two = m_hash[j + 1];
m_hash[j] ^= m_hash[j + 2] & ~two;
m_hash[j + 1] ^= m_hash[j + 3] & ~m_hash[j + 2];
m_hash[j + 2] ^= m_hash[j + 4] & ~m_hash[j + 3];
m_hash[j + 3] ^= one & ~m_hash[j + 4];
m_hash[j + 4] ^= two & ~one;
}
// Iota
m_hash[0] ^= XorMasks[round];
}
}
/// add arbitrary number of bytes
void SHA3::add(const void *data, size_t numBytes) {
const uint8_t *current = (const uint8_t *)data;
// copy data to buffer
if (m_bufferSize > 0) {
while (numBytes > 0 && m_bufferSize < m_blockSize) {
m_buffer[m_bufferSize++] = *current++;
numBytes--;
}
}
// full buffer
if (m_bufferSize == m_blockSize) {
processBlock((void *)m_buffer);
m_numBytes += m_blockSize;
m_bufferSize = 0;
}
// no more data ?
if (numBytes == 0)
return;
// process full blocks
while (numBytes >= m_blockSize) {
processBlock(current);
current += m_blockSize;
m_numBytes += m_blockSize;
numBytes -= m_blockSize;
}
// keep remaining bytes in buffer
while (numBytes > 0) {
m_buffer[m_bufferSize++] = *current++;
numBytes--;
}
}
/// process everything left in the internal buffer
void SHA3::processBuffer() {
// add padding
size_t offset = m_bufferSize;
// add a "1" byte
m_buffer[offset++] = 0x06;
// fill with zeros
while (offset < m_blockSize)
m_buffer[offset++] = 0;
// and add a single set bit
m_buffer[offset - 1] |= 0x80;
processBlock(m_buffer);
}
/// return latest hash as 16 hex characters
std::string SHA3::getHash() {
// process remaining bytes
processBuffer();
// convert hash to string
static const char dec2hex[16 + 1] = "0123456789abcdef";
// number of significant elements in hash (uint64_t)
unsigned int hashLength = m_bits / 64;
std::string result;
result.reserve(m_bits / 4);
for (unsigned int i = 0; i < hashLength; i++)
for (unsigned int j = 0; j < 8; j++) // 64 bits => 8 bytes
{
// convert a byte to hex
unsigned char oneByte = (unsigned char)(m_hash[i] >> (8 * j));
result += dec2hex[oneByte >> 4];
result += dec2hex[oneByte & 15];
}
// SHA3-224's last entry in m_hash provides only 32 bits instead of 64 bits
unsigned int remainder = m_bits - hashLength * 64;
unsigned int processed = 0;
while (processed < remainder) {
// convert a byte to hex
unsigned char oneByte = (unsigned char)(m_hash[hashLength] >> processed);
result += dec2hex[oneByte >> 4];
result += dec2hex[oneByte & 15];
processed += 8;
}
return result;
}
/// compute SHA3 of a memory block
std::string SHA3::operator()(const void *data, size_t numBytes) {
reset();
add(data, numBytes);
return getHash();
}
/// compute SHA3 of a string, excluding final zero
std::string SHA3::operator()(const std::string &text) {
reset();
add(text.c_str(), text.size());
return getHash();
}

81
src/sha3.h Normal file
View File

@ -0,0 +1,81 @@
// //////////////////////////////////////////////////////////
// sha3.h
// Copyright (c) 2014,2015 Stephan Brumme. All rights reserved.
// see http://create.stephan-brumme.com/disclaimer.html
//
#pragma once
//#include "hash.h"
#include <string>
// define fixed size integer types
#ifdef _MSC_VER
// Windows
typedef unsigned __int8 uint8_t;
typedef unsigned __int64 uint64_t;
#else
// GCC
#include <stdint.h>
#endif
/// compute SHA3 hash
/** Usage:
SHA3 sha3;
std::string myHash = sha3("Hello World"); // std::string
std::string myHash2 = sha3("How are you", 11); // arbitrary data, 11 bytes
// or in a streaming fashion:
SHA3 sha3;
while (more data available)
sha3.add(pointer to fresh data, number of new bytes);
std::string myHash3 = sha3.getHash();
*/
class SHA3 //: public Hash
{
public:
/// algorithm variants
enum Bits { Bits224 = 224, Bits256 = 256, Bits384 = 384, Bits512 = 512 };
/// same as reset()
explicit SHA3(Bits bits = Bits256);
/// compute hash of a memory block
std::string operator()(const void* data, size_t numBytes);
/// compute hash of a string, excluding final zero
std::string operator()(const std::string& text);
/// add arbitrary number of bytes
void add(const void* data, size_t numBytes);
/// return latest hash as hex characters
std::string getHash();
/// restart
void reset();
private:
/// process a full block
void processBlock(const void* data);
/// process everything left in the internal buffer
void processBuffer();
/// 1600 bits, stored as 25x64 bit, BlockSize is no more than 1152 bits (Keccak224)
enum { StateSize = 1600 / (8 * 8),
MaxBlockSize = 200 - 2 * (224 / 8) };
/// hash
uint64_t m_hash[StateSize];
/// size of processed data in bytes
uint64_t m_numBytes;
/// block size (less or equal to MaxBlockSize)
size_t m_blockSize;
/// valid bytes in m_buffer
size_t m_bufferSize;
/// bytes not processed yet
uint8_t m_buffer[MaxBlockSize];
/// variant
Bits m_bits;
};

View File

@ -1,13 +1,12 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2018, 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 <chaiscript/chaiscript_basic.hpp>
#include <chaiscript/dispatchkit/bootstrap_stl.hpp>
#include <list>
@ -25,11 +24,10 @@
#pragma clang diagnostic ignored "-Wreturn-type-c-linkage"
#endif
CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_stl_extra()
{
CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_stl_extra() {
auto module = std::make_shared<chaiscript::Module>();
chaiscript::bootstrap::standard_library::list_type<std::list<chaiscript::Boxed_Value> >("List", *module);
chaiscript::bootstrap::standard_library::vector_type<std::vector<uint16_t> >("u16vector", *module);
chaiscript::bootstrap::standard_library::list_type<std::list<chaiscript::Boxed_Value>>("List", *module);
chaiscript::bootstrap::standard_library::vector_type<std::vector<uint16_t>>("u16vector", *module);
module->add(chaiscript::vector_conversion<std::vector<uint16_t>>());
return module;
}

View File

@ -3,133 +3,121 @@
#include <chaiscript/dispatchkit/bootstrap.hpp>
#include <string>
class TestBaseType {
public:
TestBaseType() noexcept
: val(10)
, const_val(15)
, mdarray{} {
}
TestBaseType(int) noexcept
: val(10)
, const_val(15)
, mdarray{} {
}
TestBaseType(int *) noexcept
: val(10)
, const_val(15)
, mdarray{} {
}
TestBaseType(const TestBaseType &other) noexcept
: val(other.val)
, const_val(other.const_val)
, const_val_ptr(&const_val)
, func_member(other.func_member) {
}
class TestBaseType
{
public:
TestBaseType() : val(10), const_val(15), mdarray{} { }
TestBaseType(int) : val(10), const_val(15), mdarray{} { }
TestBaseType(int *) : val(10), const_val(15), mdarray{} { }
TestBaseType(TestBaseType &&other) noexcept
: val(other.val)
, const_val(other.const_val)
, const_val_ptr(&const_val)
, func_member(std::move(other.func_member)) {
}
TestBaseType(const TestBaseType &) = default;
virtual ~TestBaseType() {}
virtual int func() { return 0; }
TestBaseType &operator=(TestBaseType &&) = delete;
TestBaseType &operator=(const TestBaseType &) = delete;
int base_only_func() { return -9; }
virtual ~TestBaseType() = default;
virtual int func() { return 0; }
const TestBaseType &constMe() const { return *this; }
int base_only_func() { return -9; }
int val;
const int const_val;
const int *const_val_ptr = &const_val;
const TestBaseType &constMe() const { return *this; }
const int *get_const_val_ptr() {
return const_val_ptr;
}
int val;
const int const_val;
const int *const_val_ptr = &const_val;
int mdarray[2][3][5];
std::function<int (int)> func_member;
const int *get_const_val_ptr() { return const_val_ptr; }
void set_string_val(std::string &t_str)
{
t_str = "42";
}
int mdarray[2][3][5];
std::function<int(int)> func_member;
private:
TestBaseType &operator=(const TestBaseType &) = delete;
void set_string_val(std::string &t_str) { t_str = "42"; }
};
class Type2
{
public:
Type2(TestBaseType t_bt)
: m_bt(std::move(t_bt)),
m_str("Hello World")
{
}
class Type2 {
public:
Type2(TestBaseType t_bt) noexcept
: m_bt(std::move(t_bt))
, m_str("Hello World") {
}
int get_val() const
{
return m_bt.val;
}
int get_val() const { return m_bt.val; }
const char *get_str() const { return m_str.c_str(); }
const char *get_str() const
{
return m_str.c_str();
}
private:
TestBaseType m_bt;
std::string m_str;
private:
TestBaseType m_bt;
std::string m_str;
};
enum TestEnum
{
enum TestEnum {
TestValue1 = 1
};
int to_int(TestEnum t)
{
int to_int(TestEnum t) {
return t;
}
class TestDerivedType : public TestBaseType
{
public:
virtual ~TestDerivedType() {}
TestDerivedType(const TestDerivedType &) = default;
TestDerivedType() = default;
virtual int func() override { return 1; }
int derived_only_func() { return 19; }
private:
TestDerivedType &operator=(const TestDerivedType &) = delete;
class TestDerivedType : public TestBaseType {
public:
int func() override { return 1; }
int derived_only_func() { return 19; }
};
class TestMoreDerivedType : public TestDerivedType
{
public:
TestMoreDerivedType(const TestMoreDerivedType &) = default;
TestMoreDerivedType() = default;
virtual ~TestMoreDerivedType() {}
class TestMoreDerivedType : public TestDerivedType {
public:
};
std::shared_ptr<TestBaseType> derived_type_factory()
{
std::shared_ptr<TestBaseType> derived_type_factory() {
return std::make_shared<TestDerivedType>();
}
std::shared_ptr<TestBaseType> more_derived_type_factory()
{
std::shared_ptr<TestBaseType> more_derived_type_factory() {
return std::make_shared<TestMoreDerivedType>();
}
std::shared_ptr<TestBaseType> null_factory()
{
std::shared_ptr<TestBaseType> null_factory() {
return std::shared_ptr<TestBaseType>();
}
void update_shared_ptr(std::shared_ptr<TestBaseType> &ptr)
{
void update_shared_ptr(std::shared_ptr<TestBaseType> &ptr) {
ptr = std::make_shared<TestDerivedType>();
}
void nullify_shared_ptr(std::shared_ptr<TestBaseType> &ptr)
{
void nullify_shared_ptr(std::shared_ptr<TestBaseType> &ptr) {
ptr = nullptr;
}
std::string hello_world()
{
std::string hello_world() {
return "Hello World";
}
static int global_i = 1;
int *get_new_int()
{
int *get_new_int() {
return &global_i;
}
@ -145,8 +133,7 @@ int *get_new_int()
#pragma clang diagnostic ignored "-Wreturn-type-c-linkage"
#endif
CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_test_module()
{
CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_test_module() {
chaiscript::ModulePtr m(new chaiscript::Module());
m->add(chaiscript::fun(hello_world), "hello_world");
@ -156,16 +143,16 @@ CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_test_mo
m->add(chaiscript::user_type<TestMoreDerivedType>(), "TestMoreDerivedType");
m->add(chaiscript::user_type<Type2>(), "Type2");
m->add(chaiscript::constructor<TestBaseType ()>(), "TestBaseType");
// m->add(chaiscript::constructor<TestBaseType (int)>(), "TestBaseType");
m->add(chaiscript::constructor<TestBaseType (const TestBaseType &)>(), "TestBaseType");
m->add(chaiscript::constructor<TestBaseType (int *)>(), "TestBaseType");
m->add(chaiscript::constructor<TestBaseType()>(), "TestBaseType");
// m->add(chaiscript::constructor<TestBaseType (int)>(), "TestBaseType");
m->add(chaiscript::constructor<TestBaseType(const TestBaseType &)>(), "TestBaseType");
m->add(chaiscript::constructor<TestBaseType(int *)>(), "TestBaseType");
m->add(chaiscript::constructor<TestDerivedType ()>(), "TestDerivedType");
m->add(chaiscript::constructor<TestDerivedType (const TestDerivedType &)>(), "TestDerivedType");
m->add(chaiscript::constructor<TestDerivedType()>(), "TestDerivedType");
m->add(chaiscript::constructor<TestDerivedType(const TestDerivedType &)>(), "TestDerivedType");
m->add(chaiscript::constructor<TestMoreDerivedType ()>(), "TestMoreDerivedType");
m->add(chaiscript::constructor<TestMoreDerivedType (const TestMoreDerivedType &)>(), "TestMoreDerivedType");
m->add(chaiscript::constructor<TestMoreDerivedType()>(), "TestMoreDerivedType");
m->add(chaiscript::constructor<TestMoreDerivedType(const TestMoreDerivedType &)>(), "TestMoreDerivedType");
/// \todo automatic chaining of base classes?
m->add(chaiscript::base_class<TestBaseType, TestDerivedType>());
@ -197,7 +184,6 @@ CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_test_mo
m->add(chaiscript::fun(&TestBaseType::func_member), "func_member");
m->add(chaiscript::fun(&get_new_int), "get_new_int");
m->add_global_const(chaiscript::const_var(TestValue1), "TestValue1");
m->add(chaiscript::user_type<TestEnum>(), "TestEnum");
@ -210,16 +196,14 @@ CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_test_mo
m->add(chaiscript::fun(&Type2::get_val), "get_val");
m->add(chaiscript::fun(&Type2::get_str), "get_str");
m->add(chaiscript::type_conversion<const char *, std::string>());
m->add(chaiscript::constructor<Type2 (const TestBaseType &)>(), "Type2");
m->add(chaiscript::constructor<Type2(const TestBaseType &)>(), "Type2");
m->add(chaiscript::fun(&update_shared_ptr), "update_shared_ptr");
m->add(chaiscript::fun(&nullify_shared_ptr), "nullify_shared_ptr");
return m;
}
#ifdef __llvm__
#pragma clang diagnostic pop
#endif

View File

@ -1,8 +1,6 @@
#include "../include/chaiscript/language/chaiscript_parser.hpp"
#include "chaiscript_parser.hpp"
std::unique_ptr<chaiscript::parser::ChaiScript_Parser_Base> create_chaiscript_parser()
{
std::unique_ptr<chaiscript::parser::ChaiScript_Parser_Base> create_chaiscript_parser() {
return std::make_unique<chaiscript::parser::ChaiScript_Parser<chaiscript::eval::Noop_Tracer, chaiscript::optimizer::Optimizer_Default>>();
}

View File

@ -2,11 +2,13 @@
#ifndef CHAISCRIPT_PARSER_LIB
#define CHAISCRIPT_PARSER_LIB
#include <memory>
namespace chaiscript {
namespace parser {
class ChaiScript_Parser_Base;
}
}
} // namespace chaiscript
std::unique_ptr<chaiscript::parser::ChaiScript_Parser_Base> create_chaiscript_parser();

View File

@ -1,8 +1,6 @@
#include "../include/chaiscript/chaiscript_stdlib.hpp"
#include "chaiscript_stdlib.hpp"
std::shared_ptr<chaiscript::Module> create_chaiscript_stdlib()
{
std::shared_ptr<chaiscript::Module> create_chaiscript_stdlib() {
return chaiscript::Std_Lib::library();
}

View File

@ -1,2 +0,0 @@
assert_throws("Mismatched types in equation, lhs is const.", fun() { 1 = 2 } );
assert_throws("Mismatched types in equation, lhs is const.", fun() { 1 + 2 = 2 } );

View File

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

View File

@ -1,34 +0,0 @@
def add(x, y)
{
return x + y;
}
assert_equal(2, add.get_arity());
var b = bind(add, 2, _);
assert_equal(1, b.get_arity());
var c = bind(b, 3);
assert_equal(0, c.get_arity());
assert_equal(6, b(4));
assert_equal(5, c());
def concat2(a,b,c,d)
{
return to_string(a) + to_string(b) + to_string(c) + to_string(d);
}
var d = bind(concat2, _, " Hello ", _, " World");
assert_equal(2, d.get_arity());
assert_equal("1 Hello 3 World", d(1,3));
var e = bind(`<`, _, 5);
var types = e.get_param_types();
assert_equal(2, types.size());
assert_equal(true, types[0].bare_equal(bool_type));

View File

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

View File

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

View File

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

View File

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

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