Compare commits

...

835 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
064a385a64 Merge branch 'develop' of github.com:ChaiScript/ChaiScript into develop 2017-02-22 15:56:04 -07:00
Jason Turner
e342243193 Update release notes for 6.0.0 2017-02-22 15:33:42 -07:00
Jason Turner
283785faaf Add PVS Studio and address some issues it found 2017-02-22 15:18:56 -07:00
Jason Turner
c0c0bd3172 Address warning from MSVC /analyze 2017-02-22 14:04:56 -07:00
Jason Turner
40fb8d257e Fix warnings from MSVC 2017-02-22 13:55:02 -07:00
Jason Turner
f5f6ddf219 Disable tests on MSVC for broken literal handling 2017-02-20 13:28:31 -07:00
Jason Turner
87f1242ed4 Update copyrights to 2017 2017-02-15 15:55:40 -07:00
Jason Turner
faba0f1317 Require thread_local support, move to xcode8 2017-02-15 15:38:44 -07:00
Jason Turner
077c93ab27 Fix/enhance unique_ptr support 2017-02-04 09:14:07 -08:00
Jason Turner
914bca6295 Merge pull request #324 from Dalzhim/uniquePtrTests
Add test to call base class methods through std::unique_ptr<derived>.
2017-02-04 09:18:39 -07:00
Gabriel Aubut-Lussier
2549b4e983 Add test to call base class methods through std::unique_ptr<derived>. 2017-02-03 23:19:25 -05:00
Jason Turner
1cb15d8b22 Handle return of std::unique_ptr objects 2017-02-03 19:34:12 -08:00
Jason Turner
2ce155237d Add test for unique_ptr returned from function 2017-02-03 18:55:58 -08:00
Jason Turner
dca3ce4ea6 Enhance testing of integer literals
* enable the ability to check a boxed_number conversion
 * fix integer_literal_test to pass on MacOS
2017-02-02 15:07:37 -07:00
Jason Turner
ca7d4ab734 Add test for calling method of unique_ptr var 2017-02-02 13:17:59 -08:00
Jason Turner
f5ced799cf Hopefully find balance with gcc/clang for static_string 2017-02-02 08:10:47 -08:00
Jason Turner
1499061f86 Add check for negate conversion to bool
Check for #321
2017-02-02 08:06:41 -08:00
Jason Turner
24352c62e8 Some clang specific fixes / warnings 2017-02-02 08:00:57 -08:00
Jason Turner
6b4c47c5ba Merge branch 'develop' of github.com:ChaiScript/ChaiScript into develop 2017-02-01 20:03:17 -08:00
Jason Turner
396d43a13f sublime now at ChaiScript/sublimetext-chaiscript 2017-02-01 20:01:30 -08:00
Jason Turner
18cf09b512 Merge pull request #319 from Tw1ddle/patch-1
Add double stringize trick so _MSC_FULL_VER macro gets expanded
2017-02-01 20:12:04 -07:00
Jason Turner
2782cdd33b Remove 2-value bind in favor of lambdas
closes #320
2017-02-01 15:42:32 -08:00
Jason Turner
d8d7bc79b7 Enhance number parsing tests 2017-02-01 09:07:40 -08:00
Jason Turner
3e04210027 Add more integer literal tests / fix neg test
Addresses #322
2017-02-01 07:02:18 -08:00
Jason Turner
c82c9ccb6e Revert "Fix parsing of negative numbers"
This reverts commit 83b7973cb885af928e36195a7cbc6ab8f04a93b6.
2017-02-01 06:18:14 -08:00
Jason Turner
efd37a7071 Add some more integer literal tests 2017-01-31 17:05:53 -08:00
Jason Turner
83b7973cb8 Fix parsing of negative numbers 2017-01-31 15:41:21 -08:00
Jason Turner
e7a6b2306c Add tests for parsing of neg numbers 2017-01-31 15:30:38 -08:00
Jason Turner
0a18f0a809 Remove unnecessary params 2017-01-31 13:40:16 -08:00
Jason Turner
8efba903c3 use std::end instead of end because of MSVC 2017-01-31 13:28:40 -08:00
Jason Turner
ca87c05cd4 Don't add 'this' if it was explicitly captured 2017-01-31 13:25:26 -08:00
Jason Turner
94fb7c2453 Add test for explicitly capturing "this" 2017-01-31 13:24:53 -08:00
Jason Turner
c54d84fae6 Don't force compiler when building cppcheck 2017-01-31 10:11:28 -08:00
Sam Twidale
574f4a9664 Add double stringize trick so _MSC_FULL_VER macro gets expanded
This fixes CHAISCRIPT_COMPILER_VERSION, so it gets the compiler version number instead of the string "_MSC_FULL_VER".

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

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

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

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

View File

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

View File

@ -2,8 +2,4 @@ compilers:
- name: clang - name: clang
cmake_extra_flags: -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DCOMMIT_SHA=$COMMIT_SHA cmake_extra_flags: -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DCOMMIT_SHA=$COMMIT_SHA
build_package_generator: TBZ2 build_package_generator: TBZ2
- name: clang
build_type: Debug
cmake_extra_flags: -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DCOMMIT_SHA=$COMMIT_SHA
skip_packaging: true

View File

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

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

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

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

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

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

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

6
.gitignore vendored Normal file
View File

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

View File

@ -1,33 +1,71 @@
language: cpp language: cpp
compiler:
- gcc
env:
matrix:
- GCC_VER="4.6"
- GCC_VER="4.8"
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++-7
- g++-8
coverity_scan:
project:
name: "ChaiScript/ChaiScript"
description: "Build submitted via Travis CI"
notification_email: jason@emptycrate.com
build_command_prepend: "cmake -D ENABLE_COVERAGE:BOOL=TRUE -D CMAKE_BUILD_TYPE:STRING=Debug . "
build_command: "cmake --build . -- -j2"
branch_pattern: coverity_scan
matrix:
include:
- os: linux
sudo: false
env: GCC_VER="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="8" CPPCHECK=1 COVERAGE=1 CMAKE_OPTIONS="-D RUN_FUZZY_TESTS:BOOL=TRUE"
compiler: gcc
#- 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: global:
- secure: eiaR6pXiiEpyB8+LLQ1NvZdl0Yylru1BLy9lMoHl+IpUNGGQGywmW/2WAn77rFfmR1OPA2qWQLfgPwgK0HxUA9HHlot9tre5QhiN2Lw8NOT8tCZ6tTm2+QntDBjBGJyal/knRvQkn/6qs6GxlXRerz4ArnnuPL1vESt3zwB0YtU= - secure: eiaR6pXiiEpyB8+LLQ1NvZdl0Yylru1BLy9lMoHl+IpUNGGQGywmW/2WAn77rFfmR1OPA2qWQLfgPwgK0HxUA9HHlot9tre5QhiN2Lw8NOT8tCZ6tTm2+QntDBjBGJyal/knRvQkn/6qs6GxlXRerz4ArnnuPL1vESt3zwB0YtU=
# The next declaration is the encrypted COVERITY_SCAN_TOKEN, created # The next declaration is the encrypted COVERITY_SCAN_TOKEN, created
- secure: "LfolGjP8tWm3yAwthfu3yp8Zn40aueFae580UUR34gusG87cyglq2tQDtxdy+63gWEeNfArbv9n5rZv+bDW3ggHyPjuCKKc1PlZAy07lfXUXf1uz+SFhNvNoYTn3mQG3VZ08o116p4Le2p8yqu4bylJ8wckEq7PrTwvSGVQWTWM=" - secure: "LfolGjP8tWm3yAwthfu3yp8Zn40aueFae580UUR34gusG87cyglq2tQDtxdy+63gWEeNfArbv9n5rZv+bDW3ggHyPjuCKKc1PlZAy07lfXUXf1uz+SFhNvNoYTn3mQG3VZ08o116p4Le2p8yqu4bylJ8wckEq7PrTwvSGVQWTWM="
before_install: before_install:
- export CXX="g++-$GCC_VER" CC="gcc-$GCC_VER" GCOV="gcov-$GCC_VER" - if [ "${GCC_VER}" != "" ]; then export CXX="g++-$GCC_VER" CC="gcc-$GCC_VER" GCOV="gcov-$GCC_VER" ; fi
- if [ "$GCC_VER" = "4.8" ]; then export COVERAGE=1 CPPCHECK=1; fi #- if [ "${CLANG_VER}" != "" ]; then export CXX="clang++-$CLANG_VER"; fi
- if [ ${COVERAGE} = 1 ]; then export FUZZY_CMD="-D RUN_FUZZY_TESTS:BOOL=TRUE"; fi - pip install --user cpp-coveralls
- sudo pip install cpp-coveralls
- sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y
- sudo apt-get update
- sudo apt-get install -qq g++-$GCC_VER
script: script:
- if [ ${COVERITY_SCAN_BRANCH} != 1 ]; then cmake -D ENABLE_COVERAGE:BOOL=TRUE -D CMAKE_BUILD_TYPE:STRING=Debug $FUZZY_CMD . ; fi - cmake -D ENABLE_COVERAGE:BOOL=TRUE -D CMAKE_BUILD_TYPE:STRING=Debug $CMAKE_OPTIONS .
- if [ ${COVERITY_SCAN_BRANCH} != 1 ]; then make -j2 ; fi - cmake --build . -- -j2
- make test - 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 - if [ "${COVERAGE}" = "1" ]; then bash <(curl -s https://raw.githubusercontent.com/codecov/codecov-bash/master/codecov) -x $GCOV -a "-s `pwd`" ; fi
after_script: #after_script:
- if [ ${CPPCHECK} = 1 ]; then contrib/codeanalysis/runcppcheck.sh ; fi # - if [ ${CPPCHECK} = 1 ]; then contrib/codeanalysis/runcppcheck.sh ; fi
notifications: notifications:
@ -42,15 +80,3 @@ notifications:
on_success: change # options: [always|never|change] default: always on_success: change # options: [always|never|change] default: always
on_failure: always # options: [always|never|change] default: always on_failure: always # options: [always|never|change] default: always
on_start: false # default: false on_start: false # default: false
addons:
coverity_scan:
project:
name: "ChaiScript/ChaiScript"
description: "Build submitted via Travis CI"
notification_email: jason@emptycrate.com
build_command_prepend: "cmake -D ENABLE_COVERAGE:BOOL=TRUE -D CMAKE_BUILD_TYPE:STRING=Debug . "
build_command: "cmake --build . -- -j2"
branch_pattern: coverity_scan

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,25 +1,23 @@
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") set(CMAKE_CXX_STANDARD 20)
cmake_policy(SET CMP0054 NEW) set(CMAKE_CXX_STANDARD_REQUIRED ON)
endif()
IF(BIICODE)
INIT_BIICODE_BLOCK()
ADD_BIICODE_TARGETS()
ELSE()
# Your regular CMakeLists configuration here
# required since cmake 3.4 at least for libc++
set(CMAKE_ENABLE_EXPORTS ON)
project(chaiscript) project(chaiscript)
option(MULTITHREAD_SUPPORT_ENABLED "Multithreaded Support Enabled" TRUE) option(MULTITHREAD_SUPPORT_ENABLED "Multithreaded Support Enabled" TRUE)
option(DYNLOAD_ENABLED "Dynamic Loading Support Enabled" TRUE)
option(BUILD_MODULES "Build Extra Modules (stl)" TRUE) option(BUILD_MODULES "Build Extra Modules (stl)" TRUE)
option(BUILD_SAMPLES "Build Samples Folder" FALSE) option(BUILD_SAMPLES "Build Samples Folder" FALSE)
option(RUN_FUZZY_TESTS "Run tests generated by AFL" FALSE) option(RUN_FUZZY_TESTS "Run tests generated by AFL" FALSE)
option(USE_STD_MAKE_SHARED "Use std::make_shared instead of chaiscript::make_shared" FALSE) option(USE_STD_MAKE_SHARED "Use std::make_shared instead of chaiscript::make_shared" FALSE)
option(RUN_PERFORMANCE_TESTS "Run Performance Tests" FALSE)
mark_as_advanced(USE_STD_MAKE_SHARED) mark_as_advanced(USE_STD_MAKE_SHARED)
@ -47,12 +45,14 @@ if(CMAKE_COMPILER_IS_GNUCC OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
if(ENABLE_ADDRESS_SANITIZER) if(ENABLE_ADDRESS_SANITIZER)
add_definitions(-fsanitize=address -g) add_definitions(-fsanitize=address -g)
set(LINKER_FLAGS "${LINKER_FLAGS} -fsanitize=address") set(LINKER_FLAGS "${LINKER_FLAGS} -fsanitize=address")
option(BUILD_LIBFUZZ_TESTER "Build libfuzzer tool" FALSE)
endif() endif()
option(ENABLE_MEMORY_SANITIZER "Enable memory sanitizer testing in gcc/clang" FALSE) option(ENABLE_MEMORY_SANITIZER "Enable memory sanitizer testing in gcc/clang" FALSE)
if(ENABLE_MEMORY_SANITIZER) if(ENABLE_MEMORY_SANITIZER)
add_definitions(-fsanitize=memory -g) add_definitions(-fsanitize=memory -fsanitize-memory-track-origins -g)
set(LINKER_FLAGS "${LINKER_FLAGS} -fsanitize=memory") set(LINKER_FLAGS "${LINKER_FLAGS} -fsanitize=memory -fsanitize-memory-track-origins ")
endif() endif()
option(ENABLE_UNDEFINED_SANITIZER "Enable undefined behavior sanitizer testing in gcc/clang" FALSE) option(ENABLE_UNDEFINED_SANITIZER "Enable undefined behavior sanitizer testing in gcc/clang" FALSE)
@ -62,27 +62,26 @@ if(CMAKE_COMPILER_IS_GNUCC OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
endif() endif()
option(ENABLE_LTO "Enable Link Time Optimization" FALSE) option(ENABLE_LTO "Enable Link Time Optimization" FALSE)
if(ENABLE_LTO)
if (ENABLE_LTO) check_ipo_supported()
add_definitions(-flto) set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE)
set(LINKER_FLAGS "${LINKER_FLAGS} -flto")
endif() endif()
option(GPROF_OUTPUT "Generate profile data" FALSE) option(GPROF_OUTPUT "Generate profile data" FALSE)
if (GPROF_OUTPUT) if(GPROF_OUTPUT)
add_definitions(-pg) add_definitions(-pg)
set(LINKER_FLAGS "${LINKER_FLAGS} -pg") set(LINKER_FLAGS "${LINKER_FLAGS} -pg")
endif() endif()
option(PROFILE_GENERATE "Generate profile data" FALSE) option(PROFILE_GENERATE "Generate profile data" FALSE)
if (PROFILE_GENERATE) if(PROFILE_GENERATE)
add_definitions(-fprofile-generate) add_definitions(-fprofile-generate)
set(LINKER_FLAGS "${LINKER_FLAGS} -fprofile-generate") set(LINKER_FLAGS "${LINKER_FLAGS} -fprofile-generate")
endif() endif()
option(PROFILE_USE "Use profile data" FALSE) option(PROFILE_USE "Use profile data" FALSE)
if (PROFILE_USE) if(PROFILE_USE)
add_definitions(-fprofile-use) add_definitions(-fprofile-use)
set(LINKER_FLAGS "${LINKER_FLAGS} -fprofile-use") set(LINKER_FLAGS "${LINKER_FLAGS} -fprofile-use")
endif() endif()
@ -100,9 +99,9 @@ set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/license.txt")
set(CPACK_RESOURCE_FILE_README "${CMAKE_CURRENT_SOURCE_DIR}/readme.md") set(CPACK_RESOURCE_FILE_README "${CMAKE_CURRENT_SOURCE_DIR}/readme.md")
set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/description.txt") set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/description.txt")
set(CPACK_PACKAGE_VERSION_MAJOR 5) set(CPACK_PACKAGE_VERSION_MAJOR 7)
set(CPACK_PACKAGE_VERSION_MINOR 7) set(CPACK_PACKAGE_VERSION_MINOR 0)
set(CPACK_PACKAGE_VERSION_PATCH 2) set(CPACK_PACKAGE_VERSION_PATCH 0)
set(CPACK_PACKAGE_EXECUTABLES "chai;ChaiScript Eval") set(CPACK_PACKAGE_EXECUTABLES "chai;ChaiScript Eval")
set(CPACK_PACKAGE_VENDOR "ChaiScript.com") set(CPACK_PACKAGE_VENDOR "ChaiScript.com")
@ -121,17 +120,14 @@ configure_file(Doxyfile.in ${CMAKE_BINARY_DIR}/Doxyfile)
include(CTest) include(CTest)
include(CPack) include(CPack)
include(cmake/Catch.cmake)
include(cmake/CheckCXX11Features.cmake)
if(NOT MINGW) if(NOT MINGW)
find_library(READLINE_LIBRARY NAMES readline PATH /usr/lib /usr/local/lib /opt/local/lib) find_library(READLINE_LIBRARY NAMES readline PATH /usr/lib /usr/local/lib /opt/local/lib)
endif() endif()
if(HAS_CXX11_VARIADIC_TEMPLATES) if(UNIX AND NOT APPLE)
message(STATUS "Variadic Template support detected") find_program(VALGRIND NAMES valgrind PATH /usr/bin /usr/local/bin)
else()
message(SEND_ERROR "The selected compiler does not support the C++11 feature Variadic Templates.")
endif() endif()
enable_testing() enable_testing()
@ -148,27 +144,18 @@ else()
set(READLINE_FLAG) set(READLINE_FLAG)
endif() endif()
if(CMAKE_COMPILER_IS_GNUCC)
execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpversion OUTPUT_VARIABLE GCC_VERSION)
if(GCC_VERSION VERSION_LESS 4.8)
set(CPP11_FLAG "-std=c++0x")
else()
set(CPP11_FLAG "-std=c++11")
endif()
else()
set(CPP11_FLAG "-std=c++11")
endif()
if(MSVC) if(MSVC)
add_definitions(/W4) add_definitions(/W4 /w14545 /w34242 /w34254 /w34287 /w44263 /w44265 /w44296 /w44311 /w44826 /we4289 /w14546 /w14547 /w14549 /w14555 /w14619 /w14905 /w14906 /w14928)
if(MSVC_VERSION STREQUAL "1800")
# VS2013 doesn't have magic statics # VS2013 doesn't have magic statics
if (MSVC_VERSION STREQUAL "1800")
add_definitions(/w44640) add_definitions(/w44640)
else()
# enum warnings are too noisy on MSVC2013
add_definitions(/w34062)
endif() endif()
add_definitions(/bigobj) add_definitions(/bigobj /permissive- /utf-8)
# Note on MSVC compiler flags. # Note on MSVC compiler flags.
# The code base selective disables warnings as necessary when the compiler is complaining too much # The code base selective disables warnings as necessary when the compiler is complaining too much
# about something that is perfectly valid, or there is simply no technical way around it # 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. # how to workaround or fix the error. So I'm disabling it globally.
add_definitions(/wd4503) add_definitions(/wd4503)
else() else()
add_definitions(-Wall -Wextra -Wshadow -Wnon-virtual-dtor -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") 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-sign-conversion -Wno-missing-prototypes -Wno-padded -Wno-missing-noreturn -Wno-exit-time-destructors) add_definitions(-Weverything -Wno-c++98-compat-pedantic -Wno-c++98-compat -Wno-documentation -Wno-switch-enum -Wno-weak-vtables -Wno-missing-prototypes -Wno-padded -Wno-missing-noreturn -Wno-exit-time-destructors -Wno-documentation-unknown-command -Wno-unused-template -Wno-undef -Wno-double-promotion)
else() else()
add_definitions(-Wnoexcept) add_definitions(-Wnoexcept)
endif() endif()
@ -192,16 +179,12 @@ else()
endif() endif()
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
option(USE_LIBCXX "Use clang's libcxx" TRUE) option(USE_LIBCXX "Use clang's libcxx" FALSE)
if(USE_LIBCXX) if(USE_LIBCXX)
add_definitions(-stdlib=libc++) add_definitions(-stdlib=libc++)
set(LINKER_FLAGS "${LINKER_FLAGS} ${CPP11_FLAG} -stdlib=libc++") set(LINKER_FLAGS "${LINKER_FLAGS} -stdlib=libc++")
else()
set(LINKER_FLAGS "${LINKER_FLAGS} ${CPP11_FLAG}")
endif() endif()
elseif(CMAKE_COMPILER_IS_GNUCC)
set(LINKER_FLAGS "${LINKER_FLAGS} ${CPP11_FLAG}")
endif() endif()
# limitations in MinGW require us to make an optimized build # limitations in MinGW require us to make an optimized build
@ -213,7 +196,7 @@ endif()
include_directories(include) include_directories(include)
set(Chai_INCLUDES include/chaiscript/chaiscript.hpp include/chaiscript/chaiscript_threading.hpp include/chaiscript/dispatchkit/bad_boxed_cast.hpp include/chaiscript/dispatchkit/bind_first.hpp include/chaiscript/dispatchkit/bootstrap.hpp include/chaiscript/dispatchkit/bootstrap_stl.hpp include/chaiscript/dispatchkit/boxed_cast.hpp include/chaiscript/dispatchkit/boxed_cast_helper.hpp include/chaiscript/dispatchkit/boxed_number.hpp include/chaiscript/dispatchkit/boxed_value.hpp include/chaiscript/dispatchkit/dispatchkit.hpp include/chaiscript/dispatchkit/type_conversions.hpp include/chaiscript/dispatchkit/dynamic_object.hpp include/chaiscript/dispatchkit/exception_specification.hpp include/chaiscript/dispatchkit/function_call.hpp include/chaiscript/dispatchkit/function_call_detail.hpp include/chaiscript/dispatchkit/handle_return.hpp include/chaiscript/dispatchkit/operators.hpp include/chaiscript/dispatchkit/proxy_constructors.hpp include/chaiscript/dispatchkit/proxy_functions.hpp include/chaiscript/dispatchkit/proxy_functions_detail.hpp include/chaiscript/dispatchkit/register_function.hpp include/chaiscript/dispatchkit/type_info.hpp include/chaiscript/language/chaiscript_algebraic.hpp include/chaiscript/language/chaiscript_common.hpp include/chaiscript/language/chaiscript_engine.hpp include/chaiscript/language/chaiscript_eval.hpp include/chaiscript/language/chaiscript_parser.hpp include/chaiscript/language/chaiscript_prelude.chai include/chaiscript/language/chaiscript_prelude_docs.hpp include/chaiscript/utility/utility.hpp) set(Chai_INCLUDES include/chaiscript/chaiscript.hpp include/chaiscript/chaiscript_threading.hpp include/chaiscript/dispatchkit/bad_boxed_cast.hpp include/chaiscript/dispatchkit/bind_first.hpp include/chaiscript/dispatchkit/bootstrap.hpp include/chaiscript/dispatchkit/bootstrap_stl.hpp include/chaiscript/dispatchkit/boxed_cast.hpp include/chaiscript/dispatchkit/boxed_cast_helper.hpp include/chaiscript/dispatchkit/boxed_number.hpp include/chaiscript/dispatchkit/boxed_value.hpp include/chaiscript/dispatchkit/dispatchkit.hpp include/chaiscript/dispatchkit/type_conversions.hpp include/chaiscript/dispatchkit/dynamic_object.hpp include/chaiscript/dispatchkit/exception_specification.hpp include/chaiscript/dispatchkit/function_call.hpp include/chaiscript/dispatchkit/function_call_detail.hpp include/chaiscript/dispatchkit/handle_return.hpp include/chaiscript/dispatchkit/operators.hpp include/chaiscript/dispatchkit/proxy_constructors.hpp include/chaiscript/dispatchkit/proxy_functions.hpp include/chaiscript/dispatchkit/proxy_functions_detail.hpp include/chaiscript/dispatchkit/register_function.hpp include/chaiscript/dispatchkit/type_info.hpp include/chaiscript/language/chaiscript_algebraic.hpp include/chaiscript/language/chaiscript_common.hpp include/chaiscript/language/chaiscript_engine.hpp include/chaiscript/language/chaiscript_eval.hpp include/chaiscript/language/chaiscript_parser.hpp include/chaiscript/language/chaiscript_prelude.hpp include/chaiscript/language/chaiscript_prelude_docs.hpp include/chaiscript/utility/utility.hpp include/chaiscript/utility/json.hpp include/chaiscript/utility/json_wrap.hpp)
set_source_files_properties(${Chai_INCLUDES} PROPERTIES HEADER_FILE_ONLY TRUE) set_source_files_properties(${Chai_INCLUDES} PROPERTIES HEADER_FILE_ONLY TRUE)
@ -221,10 +204,16 @@ if(NOT MULTITHREAD_SUPPORT_ENABLED)
add_definitions(-DCHAISCRIPT_NO_THREADS) add_definitions(-DCHAISCRIPT_NO_THREADS)
endif() endif()
if(NOT DYNLOAD_ENABLED)
add_definitions(-DCHAISCRIPT_NO_DYNLOAD)
endif()
if(CMAKE_HOST_UNIX) if(CMAKE_HOST_UNIX)
if(DYNLOAD_ENABLED)
if(NOT ${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD" AND NOT ${CMAKE_SYSTEM_NAME} MATCHES "Haiku") if(NOT ${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD" AND NOT ${CMAKE_SYSTEM_NAME} MATCHES "Haiku")
list(APPEND LIBS "dl") list(APPEND LIBS "dl")
endif() endif()
endif()
if(MULTITHREAD_SUPPORT_ENABLED) if(MULTITHREAD_SUPPORT_ENABLED)
if(CMAKE_COMPILER_IS_GNUCC) if(CMAKE_COMPILER_IS_GNUCC)
@ -249,70 +238,70 @@ set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${LINKER_FLAGS}")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${LINKER_FLAGS}") set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${LINKER_FLAGS}")
set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${LINKER_FLAGS}") set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${LINKER_FLAGS}")
add_library(stdlib STATIC static_libs/chaiscript_stdlib.cpp)
add_library(parser STATIC static_libs/chaiscript_parser.cpp)
add_library(chaiscript_stdlib-${CHAI_VERSION} MODULE src/chaiscript_stdlib.cpp) add_library(chaiscript_stdlib-${CHAI_VERSION} MODULE src/chaiscript_stdlib_module.cpp)
target_link_libraries(chaiscript_stdlib-${CHAI_VERSION} ${LIBS} ${CMAKE_THREAD_LIBS_INIT}) target_link_libraries(chaiscript_stdlib-${CHAI_VERSION} ${LIBS} ${CMAKE_THREAD_LIBS_INIT})
set(CHAISCRIPT_LIBS stdlib parser)
add_executable(chai src/main.cpp ${Chai_INCLUDES}) add_executable(chai src/main.cpp ${Chai_INCLUDES})
target_link_libraries(chai ${LIBS}) target_link_libraries(chai ${LIBS} ${CHAISCRIPT_LIBS})
add_dependencies(chai chaiscript_stdlib-${CHAI_VERSION})
add_library(chaiscript INTERFACE)
target_include_directories(chaiscript INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/include)
if(BUILD_SAMPLES) if(BUILD_SAMPLES)
add_executable(example samples/example.cpp) add_executable(sanity_checks src/sanity_checks.cpp)
target_link_libraries(example ${LIBS}) target_link_libraries(sanity_checks ${LIBS})
add_executable(test_num_exceptions samples/test_num_exceptions.cpp) add_executable(test_num_exceptions samples/test_num_exceptions.cpp)
target_link_libraries(test_num_exceptions ${LIBS}) target_link_libraries(test_num_exceptions ${LIBS} ${CHAISCRIPT_LIBS})
add_executable(memory_leak_test samples/memory_leak_test.cpp) add_executable(memory_leak_test samples/memory_leak_test.cpp)
target_link_libraries(memory_leak_test ${LIBS}) target_link_libraries(memory_leak_test ${LIBS} ${CHAISCRIPT_LIBS})
add_executable(inheritance samples/inheritance.cpp) add_executable(inheritance samples/inheritance.cpp)
target_link_libraries(inheritance ${LIBS}) target_link_libraries(inheritance ${LIBS} ${CHAISCRIPT_LIBS})
add_executable(factory samples/factory.cpp)
target_link_libraries(factory ${LIBS} ${CHAISCRIPT_LIBS})
add_executable(fun_call_performance samples/fun_call_performance.cpp) add_executable(fun_call_performance samples/fun_call_performance.cpp)
target_link_libraries(fun_call_performance ${LIBS}) target_link_libraries(fun_call_performance ${LIBS} ${CHAISCRIPT_LIBS})
endif() endif()
if(BUILD_MODULES) if(BUILD_MODULES)
add_library(test_module MODULE src/test_module.cpp)
target_link_libraries(test_module ${LIBS})
add_library(stl_extra MODULE src/stl_extra.cpp) add_library(stl_extra MODULE src/stl_extra.cpp)
target_link_libraries(stl_extra ${LIBS}) target_link_libraries(stl_extra ${LIBS})
set(MODULES stl_extra) set(MODULES stl_extra)
endif() endif()
file(GLOB UNIT_TESTS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/unittests/ ${CMAKE_CURRENT_SOURCE_DIR}/unittests/*.chai ${CMAKE_CURRENT_SOURCE_DIR}/unittests/3.x/*.chai) file(GLOB UNIT_TESTS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/unittests/ ${CMAKE_CURRENT_SOURCE_DIR}/unittests/*.chai ${CMAKE_CURRENT_SOURCE_DIR}/unittests/3.x/*.chai)
list(SORT UNIT_TESTS) list(SORT UNIT_TESTS)
file(GLOB PERFORMANCE_TESTS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/performance_tests/ ${CMAKE_CURRENT_SOURCE_DIR}/performance_tests/*.chai)
list(SORT PERFORMANCE_TESTS)
if (RUN_FUZZY_TESTS)
if(RUN_FUZZY_TESTS)
file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/unittests") file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/unittests")
execute_process( execute_process(
COMMAND ${CMAKE_COMMAND} -E tar xjf ${CMAKE_CURRENT_SOURCE_DIR}/unittests/fuzzy_tests-2015-07-16.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 WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/unittests
) )
file(GLOB FUZZY_CRASH_TESTS RELATIVE ${CMAKE_BINARY_DIR}/unittests/ ${CMAKE_BINARY_DIR}/unittests/fuzzy_tests/crashes/id*) file(GLOB FUZZY_TESTS RELATIVE ${CMAKE_BINARY_DIR}/unittests/ ${CMAKE_BINARY_DIR}/unittests/MINIMIZED/*)
list(SORT FUZZY_CRASH_TESTS) list(SORT FUZZY_TESTS)
file(GLOB FUZZY_EXCEPTION_TESTS RELATIVE ${CMAKE_BINARY_DIR}/unittests/ ${CMAKE_BINARY_DIR}/unittests/fuzzy_tests/exceptions/id*) foreach(filename ${FUZZY_TESTS})
list(SORT FUZZY_EXCEPTION_TESTS)
foreach(filename ${FUZZY_CRASH_TESTS})
message(STATUS "Adding test ${filename}") 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}) 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_CRASH_TESTS}
PROPERTY ENVIRONMENT
"CHAI_USE_PATH=${CMAKE_BINARY_DIR}/unittests/"
"CHAI_MODULE_PATH=${CMAKE_CURRENT_BINARY_DIR}/"
)
foreach(filename ${FUZZY_EXCEPTION_TESTS})
message(STATUS "Adding test ${filename}")
add_test(${filename} chai "--exception" ${CMAKE_BINARY_DIR}/unittests/fuzzy_tests/exceptions/unit_test.inc ${CMAKE_BINARY_DIR}/unittests/${filename})
endforeach() endforeach()
set_property(TEST ${FUZZY_EXCEPTION_TESTS} set_property(TEST ${FUZZY_EXCEPTION_TESTS}
@ -326,37 +315,6 @@ endif()
if(BUILD_TESTING) 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(${test_name} "${executable}" ${test_name})
set_tests_properties(${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) 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) }") 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) }")
@ -380,12 +338,32 @@ if(BUILD_TESTING)
) )
set(TESTS "")
foreach(filename ${UNIT_TESTS}) foreach(filename ${UNIT_TESTS})
message(STATUS "Adding test ${filename}") message(STATUS "Adding unit test ${filename}")
add_test(${filename} chai ${CMAKE_CURRENT_SOURCE_DIR}/unittests/unit_test.inc ${CMAKE_CURRENT_SOURCE_DIR}/unittests/${filename}) add_test(unit.${filename} chai ${CMAKE_CURRENT_SOURCE_DIR}/unittests/unit_test.inc ${CMAKE_CURRENT_SOURCE_DIR}/unittests/${filename})
list(APPEND TESTS unit.${filename})
endforeach() endforeach()
set_property(TEST ${UNIT_TESTS} if(RUN_PERFORMANCE_TESTS)
foreach(filename ${PERFORMANCE_TESTS})
message(STATUS "Adding performance test ${filename}")
add_test(NAME performance.${filename} COMMAND ${VALGRIND} --tool=callgrind --callgrind-out-file=callgrind.performance.${filename} $<TARGET_FILE:chai> ${CMAKE_CURRENT_SOURCE_DIR}/performance_tests/${filename})
list(APPEND TESTS performance.${filename})
endforeach()
add_executable(profile_cpp_calls_2 performance_tests/profile_cpp_calls_2.cpp)
target_link_libraries(profile_cpp_calls_2 ${LIBS})
add_test(NAME performance.profile_cpp_calls_2 COMMAND ${VALGRIND} --tool=callgrind --callgrind-out-file=callgrind.performance.profile_cpp_calls_2 $<TARGET_FILE:profile_cpp_calls_2>)
add_executable(profile_fun_wrappers performance_tests/profile_fun_wrappers.cpp)
target_link_libraries(profile_fun_wrappers ${LIBS})
add_test(NAME performance.profile_fun_wrappers COMMAND ${VALGRIND} --tool=callgrind --callgrind-out-file=callgrind.performance.profile_fun_wrappers $<TARGET_FILE:profile_fun_wrappers>)
endif()
set_property(TEST ${TESTS}
PROPERTY ENVIRONMENT PROPERTY ENVIRONMENT
"CHAI_USE_PATH=${CMAKE_CURRENT_SOURCE_DIR}/unittests/" "CHAI_USE_PATH=${CMAKE_CURRENT_SOURCE_DIR}/unittests/"
"CHAI_MODULE_PATH=${CMAKE_CURRENT_BINARY_DIR}/" "CHAI_MODULE_PATH=${CMAKE_CURRENT_BINARY_DIR}/"
@ -393,9 +371,12 @@ if(BUILD_TESTING)
if(NOT UNIT_TEST_LIGHT) if(NOT UNIT_TEST_LIGHT)
add_executable(compiled_tests unittests/compiled_tests.cpp) add_executable(compiled_tests unittests/compiled_tests.cpp)
target_link_libraries(compiled_tests ${LIBS}) 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) add_executable(boxed_cast_test unittests/boxed_cast_test.cpp)
target_link_libraries(boxed_cast_test ${LIBS}) target_link_libraries(boxed_cast_test ${LIBS})
@ -406,11 +387,11 @@ if(BUILD_TESTING)
add_test(NAME Type_Info_Test COMMAND type_info_test) add_test(NAME Type_Info_Test COMMAND type_info_test)
add_executable(c_linkage_test unittests/c_linkage_test.cpp) add_executable(c_linkage_test unittests/c_linkage_test.cpp)
target_link_libraries(c_linkage_test ${LIBS}) target_link_libraries(c_linkage_test ${LIBS} ${CHAISCRIPT_LIBS})
add_test(NAME C_Linkage_Test COMMAND c_linkage_test) add_test(NAME C_Linkage_Test COMMAND c_linkage_test)
add_executable(integer_literal_test unittests/integer_literal_test.cpp) add_executable(integer_literal_test unittests/integer_literal_test.cpp)
target_link_libraries(integer_literal_test ${LIBS}) target_link_libraries(integer_literal_test ${LIBS} ${CHAISCRIPT_LIBS})
add_test(NAME Integer_Literal_Test COMMAND integer_literal_test) add_test(NAME Integer_Literal_Test COMMAND integer_literal_test)
if(MULTITHREAD_SUPPORT_ENABLED) if(MULTITHREAD_SUPPORT_ENABLED)
@ -422,10 +403,8 @@ if(BUILD_TESTING)
"CHAI_USE_PATH=${CMAKE_CURRENT_SOURCE_DIR}/unittests/" "CHAI_USE_PATH=${CMAKE_CURRENT_SOURCE_DIR}/unittests/"
"CHAI_MODULE_PATH=${CMAKE_CURRENT_BINARY_DIR}/" "CHAI_MODULE_PATH=${CMAKE_CURRENT_BINARY_DIR}/"
) )
endif() endif()
add_executable(multifile_test add_executable(multifile_test
unittests/multifile_test_main.cpp unittests/multifile_test_main.cpp
unittests/multifile_test_chai.cpp unittests/multifile_test_chai.cpp
@ -434,14 +413,19 @@ if(BUILD_TESTING)
target_link_libraries(multifile_test ${LIBS}) target_link_libraries(multifile_test ${LIBS})
add_test(NAME MultiFile_Test COMMAND multifile_test) add_test(NAME MultiFile_Test COMMAND multifile_test)
add_library(test_module MODULE src/test_module.cpp) install(TARGETS test_module RUNTIME DESTINATION bin LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}/chaiscript")
target_link_libraries(test_module ${LIBS})
install(TARGETS test_module RUNTIME DESTINATION bin LIBRARY DESTINATION lib/chaiscript)
endif() endif()
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 install(DIRECTORY include/chaiscript DESTINATION include
PATTERN "*.hpp" PATTERN "*.hpp"
@ -462,8 +446,6 @@ install(DIRECTORY samples DESTINATION share/chaiscript
configure_file(contrib/pkgconfig/chaiscript.pc.in lib/pkgconfig/chaiscript.pc @ONLY) configure_file(contrib/pkgconfig/chaiscript.pc.in lib/pkgconfig/chaiscript.pc @ONLY)
install(FILES "${chaiscript_BINARY_DIR}/lib/pkgconfig/chaiscript.pc" install(FILES "${chaiscript_BINARY_DIR}/lib/pkgconfig/chaiscript.pc"
DESTINATION lib/pkgconfig) DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
ENDIF()

28
DesignGoals.md Normal file
View File

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

View File

@ -1,4 +1,6 @@
Copyright 2009-2015 Jason Turner BSD-3-Clause License
Copyright 2009-2018 Jason Turner
Copyright 2009-2012 Jonathan Turner. Copyright 2009-2012 Jonathan Turner.
All Rights Reserved. All Rights Reserved.

23
appveyor.yml Normal file
View File

@ -0,0 +1,23 @@
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 "%VS_VERSION%" -DBUILD_TESTING:BOOL=ON -DBUILD_MODULES:BOOL=ON
cmake --build . --config Debug
test_script:
- cmd: ctest -C Debug
notifications:
- provider: Webhook
url: https://webhooks.gitter.im/e/9ff725a985b5679d1d5d
on_build_success: true
on_build_failure: true
on_build_status_changed: false

3
buckaroo.json Normal file
View File

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

View File

@ -11,38 +11,46 @@ ChaiScript tries to follow the [Semantic Versioning](http://semver.org/) scheme.
# Initializing ChaiScript # Initializing ChaiScript
``` ```
chaiscript::ChaiScript chai; // loads stdlib from loadable module on file system chaiscript::ChaiScript chai; // initializes ChaiScript, adding the standard ChaiScript types (map, string, ...)
chaiscript::ChaiScript chai(chaiscript::Std_Lib::library()); // compiles in stdlib
``` ```
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 Things To The Engine
## Adding a Function / Method / Member ## Adding a Function / Method / Member
### General ### General
``` ```cpp
chai.add(chaiscript::fun(&function_name), "function_name"); chai.add(chaiscript::fun(&function_name), "function_name");
chai.add(chaiscript::fun(&Class::method_name), "method_name"); chai.add(chaiscript::fun(&Class::method_name), "method_name");
chai.add(chaiscript::fun(&Class::member_name), "member_name"); 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 #### Preferred
``` ```cpp
chai.add(chaiscript::fun<ReturnType (ParamType1, ParamType2)>(&function_with_overloads), "function_name"); chai.add(chaiscript::fun<ReturnType (ParamType1, ParamType2)>(&function_with_overloads), "function_name");
``` ```
#### Alternative #### 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 members using derived type
```
This overload technique is also used when exposing base member using derived type
``` ```cpp
struct Base struct Base
{ {
int data; int data;
@ -56,9 +64,9 @@ chai.add(chaiscript::fun(static_cast<int(Derived::*)>(&Derived::data)), "data");
### Lambda ### Lambda
``` ```cpp
chai.add( chai.add(
chaiscript::fun<std::string (bool)>( chaiscript::fun<std::function<std::string (bool)>>(
[](bool type) { [](bool type) {
if (type) { return "x"; } if (type) { return "x"; }
else { return "y"; } else { return "y"; }
@ -67,7 +75,7 @@ chai.add(
### Constructors ### Constructors
``` ```cpp
chai.add(chaiscript::constructor<MyType ()>(), "MyType"); chai.add(chaiscript::constructor<MyType ()>(), "MyType");
chai.add(chaiscript::constructor<MyType (const MyType &)>(), "MyType"); chai.add(chaiscript::constructor<MyType (const MyType &)>(), "MyType");
``` ```
@ -76,13 +84,56 @@ chai.add(chaiscript::constructor<MyType (const MyType &)>(), "MyType");
It's not strictly necessary to add types, but it helps with many things. Cloning, better errors, etc. 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"); chai.add(chaiscript::user_type<MyClass>(), "MyClass");
``` ```
## Adding Type Conversions ## 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++.
### ChaiScript Defined Conversions
Function objects (including lambdas) can be used to add type conversions
from inside of ChaiScript:
```
add_type_conversion(type("string"), type("Type_Info"), fun(s) { return type(s); });
```
### C++ Defined Conversions
Invoking a C++ type conversion possible with `static_cast`
```cpp
chai.add(chaiscript::type_conversion<T, bool>());
```
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 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>());
```
### Helpers
A helper function exists for strongly typed and ChaiScript `Vector` function conversion definition: A helper function exists for strongly typed and ChaiScript `Vector` function conversion definition:
@ -90,23 +141,51 @@ A helper function exists for strongly typed and ChaiScript `Vector` function con
chai.add(chaiscript::vector_conversion<std::vector<int>>()); chai.add(chaiscript::vector_conversion<std::vector<int>>());
``` ```
A helper function also exists for strongly typed and ChaiScript `Map` function conversion definition:
```
chai.add(chaiscript::map_conversion<std::map<std::string, int>>());
```
This allows you to pass a ChaiScript function to a function requiring `std::vector<int>` This allows you to pass a ChaiScript function to a function requiring `std::vector<int>`
## Adding Objects ## Adding Objects
``` ```
chai.add(chaiscript::var(somevar), "somevar"); // copied in 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); 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::var(shareddouble), "shareddouble"); // by shared_ptr, shared between c++ and chai
chai.add(chaiscript::const_var(somevar), "somevar"); // copied in and made const chai.add(chaiscript::const_var(somevar), "somevar"); // copied in and made const
chai.add_global_const(chaiscript::const_var(somevar), "somevar"); // global const. Throws if value is non-const chai.add_global_const(chaiscript::const_var(somevar), "somevar"); // global const. Throws if value is non-const, throws if object exists
chai.add_global(chaiscript::var(somevar), "somevar"); // global non-const chai.add_global(chaiscript::var(somevar), "somevar"); // global non-const, throws if object exists
chai.set_global(chaiscript::var(somevar), "somevar"); // global non-const, overwrites existing object
``` ```
# Using STL
ChaiScript recognize many types from STL, but you have to add specific instantiation yourself.
## 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; typedef std::vector<std::pair<int, std::string>> data_list;
data_list my_list{ make_pair(0, "Hello"), make_pair(1, "World") }; data_list my_list{ make_pair(0, "Hello"), make_pair(1, "World") };
chai.add(chaiscript::bootstrap::standard_library::vector_type<data_list>("DataList")); chai.add(chaiscript::bootstrap::standard_library::vector_type<data_list>("DataList"));
@ -124,7 +203,7 @@ chai.eval(R"_(
## General ## General
``` ```cpp
chai.eval("print(\"Hello World\")"); chai.eval("print(\"Hello World\")");
chai.eval(R"(print("Hello World"))"); chai.eval(R"(print("Hello World"))");
``` ```
@ -135,13 +214,13 @@ Returns values are of the type `Boxed_Value` which is meant to be opaque to the
### Prefered ### Prefered
``` ```cpp
chai.eval<double>("5.3 + 2.1"); // returns 7.4 as a C++ double chai.eval<double>("5.3 + 2.1"); // returns 7.4 as a C++ double
``` ```
### Alternative ### Alternative
``` ```cpp
auto v = chai.eval("5.3 + 2.1"); auto v = chai.eval("5.3 + 2.1");
chai.boxed_cast<double>(v); // extracts double value from boxed_value and applies known conversions 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 chaiscript::boxed_cast<double>(v); // free function version, does not know about conversions
@ -149,15 +228,37 @@ chaiscript::boxed_cast<double>(v); // free function version, does not know about
### Converting Between Algebraic Types ### Converting Between Algebraic Types
``` ```cpp
chaiscript::Boxed_Number(chai.eval("5.3 + 2.1")).get_as<int>(); // works with any number type 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: // 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 static_cast<int>(chai.eval<double>("5.3+2.1")); // this version only works if we know that it's a double
``` ```
### Conversion Caveats
Conversion to `std::shared_ptr<T> &` is supported for function calls, but if you attempt to keep a reference to a `shared_ptr<>` you might invoke undefined behavior
```cpp
// ok this is supported, you can register it with chaiscript engine
void nullify_shared_ptr(std::shared_ptr<int> &t) {
t = nullptr
}
```
```cpp
int main()
{
// do some stuff and create a chaiscript instance
std::shared_ptr<int> &ptr = chai.eval<std::shared_ptr<int> &>(somevalue);
// DO NOT do this. Taking a non-const reference to a shared_ptr is not
// supported and causes undefined behavior in the chaiscript engine
}
```
## Sharing Values ## Sharing Values
``` ```cpp
double &d = chai.eval("var i = 5.2; i"); // d is now a reference to i in the script 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 std::shared_ptr<double> d = chai.eval("var i = 5.2; i"); // same result but reference counted
@ -167,7 +268,7 @@ chai.eval("print(i)"); // prints 3
## Catching Eval Errors ## Catching Eval Errors
``` ```cpp
try { try {
chai.eval("2.3 + \"String\""); chai.eval("2.3 + \"String\"");
} catch (const chaiscript::exception::eval_error &e) { } catch (const chaiscript::exception::eval_error &e) {
@ -177,7 +278,7 @@ try {
## Catching Errors Thrown From Script ## Catching Errors Thrown From Script
``` ```cpp
try { try {
chai.eval("throw(runtime_error(\"error\"))", chaiscript::exception_specification<int, double, float, const std::string &, const std::exception &>()); chai.eval("throw(runtime_error(\"error\"))", chaiscript::exception_specification<int, double, float, const std::string &, const std::exception &>());
} catch (const double e) { } catch (const double e) {
@ -185,26 +286,26 @@ try {
} catch (float) { } catch (float) {
} catch (const std::string &) { } catch (const std::string &) {
} catch (const std::exception &e) { } catch (const std::exception &e) {
// This is the one what will be called in the specific throw() above // This is the one that will be called in the specific throw() above
} }
``` ```
## Sharing Functions ## Sharing Functions
``` ```cpp
auto p = chai.eval<std::function<std::string (double)>>("to_string"); auto p = chai.eval<std::function<std::string (double)>>("to_string");
p(5); // calls chaiscript's 'to_string' function, returning std::string("5") p(5); // calls chaiscript's 'to_string' function, returning std::string("5")
``` ```
Note: backtick treats operators as normal functions Note: backtick treats operators as normal functions
``` ```cpp
auto p = chai.eval<std::function<int (int, int)>>(`+`); auto p = chai.eval<std::function<int (int, int)>>("`+`");
p(5, 6); // calls chaiscript's '+' function, returning 11 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); }"); 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++ p(3,4.2); // evaluates the lambda function, returning the string "34.2" to C++
``` ```
@ -221,20 +322,91 @@ var k = 5; // initialized to 5 (integer)
var l := k; // reference to k var l := k; // reference to k
auto &m = k; // reference to k auto &m = k; // reference to k
GLOBAL g = 5; // creates a global variable. If global already exists, it is not re-added global g = 5; // creates a global variable. If global already exists, it is not re-added
GLOBAL g = 2; // global 'g' now equals 2 global g = 2; // global 'g' now equals 2
GLOBAL g2; global g2;
if (g2.is_var_undef()) { g2 = 4; } // only initialize g2 once, if GLOBAL decl hit more than once if (g2.is_var_undef()) { g2 = 4; } // only initialize g2 once, if global decl hit more than once
GLOBAL g3; // all upper case version also accepted
``` ```
## Built in Types ## Looping
```
// c-style for loops
for (var i = 0; i < 100; ++i) { print(i); }
```
```
// while
while (some_condition()) { /* do something */ }
```
```
// ranged for
for (i : [1, 2, 3]) { print(i); }
```
Each of the loop styles can be broken using the `break` statement. For example:
```
while (some_condition()) {
/* do something */
if (another_condition()) { break; }
}
```
## Conditionals
```
if (expression) { }
```
```
// C++17-style init-if blocks
// Value of 'statement' is scoped for entire `if` block
if (statement; expression) { }
```
## 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 v = [1,2,3u,4ll,"16", `+`]; // creates vector of heterogenous values
var m = ["a":1, "b":2]; // map of string:value pairs 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 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 such as `f`, `ll`, `u` as well as scientific notation are supported
@ -255,7 +427,7 @@ on your platform.
## Functions ## Functions
Note that any type of ChaiScript function can be passed freely to C++ and automatically 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 ### General
@ -354,6 +526,20 @@ o.f = fun(y) { print(this.x + y); }
o.f(10); // prints 13 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 ### Option Explicit
If you want to disable dynamic parameter definitions, you can `set_explicit`. If you want to disable dynamic parameter definitions, you can `set_explicit`.
@ -365,6 +551,7 @@ class My_Class {
this.x = 2; // this would fail with explicit set to true this.x = 2; // this would fail with explicit set to true
} }
}; };
```
## method_missing ## method_missing
@ -385,8 +572,15 @@ the contained function.
If both a 2 parameter and a 3 parameter signature match, the 3 parameter function always wins. If both a 2 parameter and a 3 parameter signature match, the 3 parameter function always wins.
## Context
# Built In Functions * `__LINE__` Current file line number
* `__FILE__` Full path of current file
* `__CLASS__` Name of current class
* `__FUNC__` Name of current function
# Built-in Functions
## Evaluation ## Evaluation
@ -399,4 +593,10 @@ use("filename") // evals file exactly once and returns value of last statement
Both `use` and `eval_file` search the 'usepaths' passed to the ChaiScript constructor Both `use` and `eval_file` search the 'usepaths' passed to the ChaiScript constructor
## JSON
* `from_json` converts a JSON string into its strongly typed (map, vector, int, double, string) representations
* `to_json` converts a ChaiScript object (either a `Object` or one of map, vector, int, double, string) tree into its JSON string representation
## 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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

11
contrib/check_for_tabs.rb Executable file
View File

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

11
contrib/check_for_todos.rb Executable file
View File

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

View File

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

View File

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

View File

@ -2,3 +2,4 @@ def greet {
return("hello") return("hello")
} }
fun(){ "world" }

View File

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

View File

@ -1,93 +0,0 @@
# [PackageDev] target_format: plist, ext: tmLanguage
---
comment: 'ChaiScript Syntax: version 2.0'
fileTypes: [chai]
firstLineMatch: ^#!/usr/bin/env node
foldingStartMarker: ^.*\bdef\s*(\w+\s*)?\([^\)]*\)(\s*\{[^\}]*)?\s*$
foldingStopMarker: ^\s*\}
keyEquivalent: ^~J
name: ChaiScript
patterns:
- {comment: chaiscript shebang, match: ^#, name: comment.line.chai}
- {match: '\b((0(x|X)[0-9a-fA-F]+)|([0-9]+(\.[0-9]+)?))\b', name: constant.numeric.chai}
- begin: ''''
beginCaptures:
'0': {name: punctuation.definition.string.begin.chai}
end: ''''
endCaptures:
'0': {name: punctuation.definition.string.end.chai}
name: string.quoted.single.chai
patterns:
- {match: '\\(x\h{2}|[0-2][0-7]{,2}|3[0-6][0-7]?|37[0-7]?|[4-7][0-7]?|.)', name: constant.character.escape.chai}
- begin: '"'
beginCaptures:
'0': {name: punctuation.definition.string.begin.chai}
end: '"'
endCaptures:
'0': {name: punctuation.definition.string.end.chai}
name: string.quoted.double.chai
patterns:
- {match: '\\(x\h{2}|[0-2][0-7]{,2}|3[0-6][0-7]|37[0-7]?|[4-7][0-7]?|.)', name: constant.character.escape.chai}
- begin: /\*\*(?!/)
captures:
'0': {name: punctuation.definition.comment.chai}
end: \*/
name: comment.block.documentation.chai
- begin: /\*
captures:
'0': {name: punctuation.definition.comment.chai}
end: \*/
name: comment.block.chai
- captures:
'1': {name: punctuation.definition.comment.chai}
match: (//).*$\n?
name: comment.line.double-slash.chai
- captures:
'0': {name: punctuation.definition.comment.html.chai}
'2': {name: punctuation.definition.comment.html.chai}
match: (<!--|-->)
name: comment.block.html.chai
- {match: \b(boolean|byte|char|class|double|enum|float|fun|def|int|interface|long|short|var|auto|attr)\b,
name: storage.type.chai}
- {match: \b(break|case|catch|continue|default|do|else|finally|else if|for|goto|if|return|switch|throw|try|while)\b,
name: keyword.control.chai}
- {match: \b(delete|in|instanceof|new|typeof|with)\b, name: keyword.operator.chai}
- {match: \btrue\b, name: constant.language.boolean.true.chai}
- {match: \bfalse\b, name: constant.language.boolean.false.chai}
- {match: \bnull\b, name: constant.language.null.chai}
- {match: \b(Anchor|Applet|Area|Array|Boolean|Button|Checkbox|Date|document|event|FileUpload|Form|Frame|Function|Hidden|History|Image|JavaArray|JavaClass|JavaObject|JavaPackage|java|Layer|Link|Location|Math|MimeType|Number|navigator|netscape|Object|Option|Packages|Password|Plugin|Radio|RegExp|Reset|Select|String|Style|Submit|screen|sun|Text|Textarea|window|XMLHttpRequest)\b,
name: support.class.chai}
- {match: '\b(s(h(ift|ow(Mod(elessDialog|alDialog)|Help))|croll(X|By(Pages|Lines)?|Y|To)?|t(op|rike)|i(n|zeToContent|debar|gnText)|ort|u(p|b(str(ing)?)?)|pli(ce|t)|e(nd|t(Re(sizable|questHeader)|M(i(nutes|lliseconds)|onth)|Seconds|Ho(tKeys|urs)|Year|Cursor|Time(out)?|Interval|ZOptions|Date|UTC(M(i(nutes|lliseconds)|onth)|Seconds|Hours|Date|FullYear)|FullYear|Active)|arch)|qrt|lice|avePreferences|mall)|h(ome|andleEvent)|navigate|c(har(CodeAt|At)|o(s|n(cat|textual|firm)|mpile)|eil|lear(Timeout|Interval)?|a(ptureEvents|ll)|reate(StyleSheet|Popup|EventObject))|t(o(GMTString|S(tring|ource)|U(TCString|pperCase)|Lo(caleString|werCase))|est|a(n|int(Enabled)?))|i(s(NaN|Finite)|ndexOf|talics)|d(isableExternalCapture|ump|etachEvent)|u(n(shift|taint|escape|watch)|pdateCommands)|j(oin|avaEnabled)|p(o(p|w)|ush|lugins.refresh|a(ddings|rse(Int|Float)?)|r(int|ompt|eference))|e(scape|nableExternalCapture|val|lementFromPoint|x(p|ec(Script|Command)?))|valueOf|UTC|queryCommand(State|Indeterm|Enabled|Value)|f(i(nd|le(ModifiedDate|Size|CreatedDate|UpdatedDate)|xed)|o(nt(size|color)|rward)|loor|romCharCode)|watch|l(ink|o(ad|g)|astIndexOf)|a(sin|nchor|cos|t(tachEvent|ob|an(2)?)|pply|lert|b(s|ort))|r(ou(nd|teEvents)|e(size(By|To)|calc|turnValue|place|verse|l(oad|ease(Capture|Events)))|andom)|g(o|et(ResponseHeader|M(i(nutes|lliseconds)|onth)|Se(conds|lection)|Hours|Year|Time(zoneOffset)?|Da(y|te)|UTC(M(i(nutes|lliseconds)|onth)|Seconds|Hours|Da(y|te)|FullYear)|FullYear|A(ttention|llResponseHeaders)))|m(in|ove(B(y|elow)|To(Absolute)?|Above)|ergeAttributes|a(tch|rgins|x))|b(toa|ig|o(ld|rderWidths)|link|ack))\b(?=\()',
name: support.function.chai}
- {match: '\b(s(ub(stringData|mit)|plitText|e(t(NamedItem|Attribute(Node)?)|lect))|has(ChildNodes|Feature)|namedItem|c(l(ick|o(se|neNode))|reate(C(omment|DATASection|aption)|T(Head|extNode|Foot)|DocumentFragment|ProcessingInstruction|E(ntityReference|lement)|Attribute))|tabIndex|i(nsert(Row|Before|Cell|Data)|tem)|open|delete(Row|C(ell|aption)|T(Head|Foot)|Data)|focus|write(ln)?|a(dd|ppend(Child|Data))|re(set|place(Child|Data)|move(NamedItem|Child|Attribute(Node)?)?)|get(NamedItem|Element(sBy(Name|TagName)|ById)|Attribute(Node)?)|blur)\b(?=\()',
name: support.function.dom.chai}
- {match: '(?<=\.)(s(ystemLanguage|cr(ipts|ollbars|een(X|Y|Top|Left))|t(yle(Sheets)?|atus(Text|bar)?)|ibling(Below|Above)|ource|uffixes|e(curity(Policy)?|l(ection|f)))|h(istory|ost(name)?|as(h|Focus))|y|X(MLDocument|SLDocument)|n(ext|ame(space(s|URI)|Prop))|M(IN_VALUE|AX_VALUE)|c(haracterSet|o(n(structor|trollers)|okieEnabled|lorDepth|mp(onents|lete))|urrent|puClass|l(i(p(boardData)?|entInformation)|osed|asses)|alle(e|r)|rypto)|t(o(olbar|p)|ext(Transform|Indent|Decoration|Align)|ags)|SQRT(1_2|2)|i(n(ner(Height|Width)|put)|ds|gnoreCase)|zIndex|o(scpu|n(readystatechange|Line)|uter(Height|Width)|p(sProfile|ener)|ffscreenBuffering)|NEGATIVE_INFINITY|d(i(splay|alog(Height|Top|Width|Left|Arguments)|rectories)|e(scription|fault(Status|Ch(ecked|arset)|View)))|u(ser(Profile|Language|Agent)|n(iqueID|defined)|pdateInterval)|_content|p(ixelDepth|ort|ersonalbar|kcs11|l(ugins|atform)|a(thname|dding(Right|Bottom|Top|Left)|rent(Window|Layer)?|ge(X(Offset)?|Y(Offset)?))|r(o(to(col|type)|duct(Sub)?|mpter)|e(vious|fix)))|e(n(coding|abledPlugin)|x(ternal|pando)|mbeds)|v(isibility|endor(Sub)?|Linkcolor)|URLUnencoded|P(I|OSITIVE_INFINITY)|f(ilename|o(nt(Size|Family|Weight)|rmName)|rame(s|Element)|gColor)|E|whiteSpace|l(i(stStyleType|n(eHeight|kColor))|o(ca(tion(bar)?|lName)|wsrc)|e(ngth|ft(Context)?)|a(st(M(odified|atch)|Index|Paren)|yer(s|X)|nguage))|a(pp(MinorVersion|Name|Co(deName|re)|Version)|vail(Height|Top|Width|Left)|ll|r(ity|guments)|Linkcolor|bove)|r(ight(Context)?|e(sponse(XML|Text)|adyState))|global|x|m(imeTypes|ultiline|enubar|argin(Right|Bottom|Top|Left))|L(N(10|2)|OG(10E|2E))|b(o(ttom|rder(Width|RightWidth|BottomWidth|Style|Color|TopWidth|LeftWidth))|ufferDepth|elow|ackground(Color|Image)))\b',
name: support.constant.chai}
- {match: '(?<=\.)(s(hape|ystemId|c(heme|ope|rolling)|ta(ndby|rt)|ize|ummary|pecified|e(ctionRowIndex|lected(Index)?)|rc)|h(space|t(tpEquiv|mlFor)|e(ight|aders)|ref(lang)?)|n(o(Resize|tation(s|Name)|Shade|Href|de(Name|Type|Value)|Wrap)|extSibling|ame)|c(h(ildNodes|Off|ecked|arset)?|ite|o(ntent|o(kie|rds)|de(Base|Type)?|l(s|Span|or)|mpact)|ell(s|Spacing|Padding)|l(ear|assName)|aption)|t(ype|Bodies|itle|Head|ext|a(rget|gName)|Foot)|i(sMap|ndex|d|m(plementation|ages))|o(ptions|wnerDocument|bject)|d(i(sabled|r)|o(c(type|umentElement)|main)|e(clare|f(er|ault(Selected|Checked|Value)))|at(eTime|a))|useMap|p(ublicId|arentNode|r(o(file|mpt)|eviousSibling))|e(n(ctype|tities)|vent|lements)|v(space|ersion|alue(Type)?|Link|Align)|URL|f(irstChild|orm(s)?|ace|rame(Border)?)|width|l(ink(s)?|o(ngDesc|wSrc)|a(stChild|ng|bel))|a(nchors|c(ce(ssKey|pt(Charset)?)|tion)|ttributes|pplets|l(t|ign)|r(chive|eas)|xis|Link|bbr)|r(ow(s|Span|Index)|ules|e(v|ferrer|l|adOnly))|m(ultiple|e(thod|dia)|a(rgin(Height|Width)|xLength))|b(o(dy|rder)|ackground|gColor))\b',
name: support.constant.dom.chai}
- {match: \b(ELEMENT_NODE|ATTRIBUTE_NODE|TEXT_NODE|CDATA_SECTION_NODE|ENTITY_REFERENCE_NODE|ENTITY_NODE|PROCESSING_INSTRUCTION_NODE|COMMENT_NODE|DOCUMENT_NODE|DOCUMENT_TYPE_NODE|DOCUMENT_FRAGMENT_NODE|NOTATION_NODE|INDEX_SIZE_ERR|DOMSTRING_SIZE_ERR|HIERARCHY_REQUEST_ERR|WRONG_DOCUMENT_ERR|INVALID_CHARACTER_ERR|NO_DATA_ALLOWED_ERR|NO_MODIFICATION_ALLOWED_ERR|NOT_FOUND_ERR|NOT_SUPPORTED_ERR|INUSE_ATTRIBUTE_ERR)\b,
name: support.constant.dom.chai}
- {match: '\bon(R(ow(s(inserted|delete)|e(nter|xit))|e(s(ize(start|end)?|et)|adystatechange))|Mouse(o(ut|ver)|down|up|move)|B(efore(cut|deactivate|u(nload|pdate)|p(aste|rint)|editfocus|activate)|lur)|S(croll|top|ubmit|elect(start|ionchange)?)|H(over|elp)|C(hange|ont(extmenu|rolselect)|ut|ellchange|l(ick|ose))|D(eactivate|ata(setc(hanged|omplete)|available)|r(op|ag(start|over|drop|en(ter|d)|leave)?)|blclick)|Unload|P(aste|ropertychange)|Error(update)?|Key(down|up|press)|Focus|Load|A(ctivate|fter(update|print)|bort))\b',
name: support.function.event-handler.chai}
- {match: '!|\$|%|&|\*|\-\-|\-|\+\+|\+|~|===|==|=|!=|!==|<=|>=|<<=|>>=|>>>=|<>|<|>|!|&&|\|\||\?\:|\*=|(?<!\()/=|%=|\+=|\-=|&=|\^=|\b(in|instanceof|new|delete|typeof|void)\b',
name: keyword.operator.chai}
- {match: \b(Infinity|NaN|undefined)\b, name: constant.language.chai}
- begin: (?<=[=(:]|^|return|&&|\|\||!)\s*(/)(?![/*+{}?])
beginCaptures:
'1': {name: punctuation.definition.string.begin.chai}
end: (/)[igm]*
endCaptures:
'1': {name: punctuation.definition.string.end.chai}
name: string.regexp.chai
patterns:
- {match: \\., name: constant.character.escape.chai}
- {match: \;, name: punctuation.terminator.statement.chai}
- {match: ',[ |\t]*', name: meta.delimiter.object.comma.chai}
- {match: \., name: meta.delimiter.method.period.chai}
- {match: '\{|\}', name: meta.brace.curly.chai}
- {match: \(|\), name: meta.brace.round.chai}
- {match: '\[|\]', name: meta.brace.square.chai}
scopeName: source.chai
uuid: 93E017CC-6F27-11D9-90EB-000D93589AF6
...

View File

@ -1,333 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>comment</key>
<string>ChaiScript Syntax: version 2.0</string>
<key>fileTypes</key>
<array>
<string>chai</string>
</array>
<key>firstLineMatch</key>
<string>^#!/usr/bin/env node</string>
<key>foldingStartMarker</key>
<string>^.*\bdef\s*(\w+\s*)?\([^\)]*\)(\s*\{[^\}]*)?\s*$</string>
<key>foldingStopMarker</key>
<string>^\s*\}</string>
<key>keyEquivalent</key>
<string>^~J</string>
<key>name</key>
<string>ChaiScript</string>
<key>patterns</key>
<array>
<dict>
<key>comment</key>
<string>chaiscript shebang</string>
<key>match</key>
<string>^#</string>
<key>name</key>
<string>comment.line.chai</string>
</dict>
<dict>
<key>match</key>
<string>\b((0(x|X)[0-9a-fA-F]+)|([0-9]+(\.[0-9]+)?))\b</string>
<key>name</key>
<string>constant.numeric.chai</string>
</dict>
<dict>
<key>begin</key>
<string>'</string>
<key>beginCaptures</key>
<dict>
<key>0</key>
<dict>
<key>name</key>
<string>punctuation.definition.string.begin.chai</string>
</dict>
</dict>
<key>end</key>
<string>'</string>
<key>endCaptures</key>
<dict>
<key>0</key>
<dict>
<key>name</key>
<string>punctuation.definition.string.end.chai</string>
</dict>
</dict>
<key>name</key>
<string>string.quoted.single.chai</string>
<key>patterns</key>
<array>
<dict>
<key>match</key>
<string>\\(x\h{2}|[0-2][0-7]{,2}|3[0-6][0-7]?|37[0-7]?|[4-7][0-7]?|.)</string>
<key>name</key>
<string>constant.character.escape.chai</string>
</dict>
</array>
</dict>
<dict>
<key>begin</key>
<string>"</string>
<key>beginCaptures</key>
<dict>
<key>0</key>
<dict>
<key>name</key>
<string>punctuation.definition.string.begin.chai</string>
</dict>
</dict>
<key>end</key>
<string>"</string>
<key>endCaptures</key>
<dict>
<key>0</key>
<dict>
<key>name</key>
<string>punctuation.definition.string.end.chai</string>
</dict>
</dict>
<key>name</key>
<string>string.quoted.double.chai</string>
<key>patterns</key>
<array>
<dict>
<key>match</key>
<string>\\(x\h{2}|[0-2][0-7]{,2}|3[0-6][0-7]|37[0-7]?|[4-7][0-7]?|.)</string>
<key>name</key>
<string>constant.character.escape.chai</string>
</dict>
</array>
</dict>
<dict>
<key>begin</key>
<string>/\*\*(?!/)</string>
<key>captures</key>
<dict>
<key>0</key>
<dict>
<key>name</key>
<string>punctuation.definition.comment.chai</string>
</dict>
</dict>
<key>end</key>
<string>\*/</string>
<key>name</key>
<string>comment.block.documentation.chai</string>
</dict>
<dict>
<key>begin</key>
<string>/\*</string>
<key>captures</key>
<dict>
<key>0</key>
<dict>
<key>name</key>
<string>punctuation.definition.comment.chai</string>
</dict>
</dict>
<key>end</key>
<string>\*/</string>
<key>name</key>
<string>comment.block.chai</string>
</dict>
<dict>
<key>captures</key>
<dict>
<key>1</key>
<dict>
<key>name</key>
<string>punctuation.definition.comment.chai</string>
</dict>
</dict>
<key>match</key>
<string>(//).*$\n?</string>
<key>name</key>
<string>comment.line.double-slash.chai</string>
</dict>
<dict>
<key>captures</key>
<dict>
<key>0</key>
<dict>
<key>name</key>
<string>punctuation.definition.comment.html.chai</string>
</dict>
<key>2</key>
<dict>
<key>name</key>
<string>punctuation.definition.comment.html.chai</string>
</dict>
</dict>
<key>match</key>
<string>(&lt;!--|--&gt;)</string>
<key>name</key>
<string>comment.block.html.chai</string>
</dict>
<dict>
<key>match</key>
<string>\b(boolean|byte|char|class|double|enum|float|fun|def|int|interface|long|short|var|auto|attr)\b</string>
<key>name</key>
<string>storage.type.chai</string>
</dict>
<dict>
<key>match</key>
<string>\b(break|case|catch|continue|default|do|else|finally|else if|for|goto|if|return|switch|throw|try|while)\b</string>
<key>name</key>
<string>keyword.control.chai</string>
</dict>
<dict>
<key>match</key>
<string>\b(delete|in|instanceof|new|typeof|with)\b</string>
<key>name</key>
<string>keyword.operator.chai</string>
</dict>
<dict>
<key>match</key>
<string>\btrue\b</string>
<key>name</key>
<string>constant.language.boolean.true.chai</string>
</dict>
<dict>
<key>match</key>
<string>\bfalse\b</string>
<key>name</key>
<string>constant.language.boolean.false.chai</string>
</dict>
<dict>
<key>match</key>
<string>\bnull\b</string>
<key>name</key>
<string>constant.language.null.chai</string>
</dict>
<dict>
<key>match</key>
<string>\b(Anchor|Applet|Area|Array|Boolean|Button|Checkbox|Date|document|event|FileUpload|Form|Frame|Function|Hidden|History|Image|JavaArray|JavaClass|JavaObject|JavaPackage|java|Layer|Link|Location|Math|MimeType|Number|navigator|netscape|Object|Option|Packages|Password|Plugin|Radio|RegExp|Reset|Select|String|Style|Submit|screen|sun|Text|Textarea|window|XMLHttpRequest)\b</string>
<key>name</key>
<string>support.class.chai</string>
</dict>
<dict>
<key>match</key>
<string>\b(s(h(ift|ow(Mod(elessDialog|alDialog)|Help))|croll(X|By(Pages|Lines)?|Y|To)?|t(op|rike)|i(n|zeToContent|debar|gnText)|ort|u(p|b(str(ing)?)?)|pli(ce|t)|e(nd|t(Re(sizable|questHeader)|M(i(nutes|lliseconds)|onth)|Seconds|Ho(tKeys|urs)|Year|Cursor|Time(out)?|Interval|ZOptions|Date|UTC(M(i(nutes|lliseconds)|onth)|Seconds|Hours|Date|FullYear)|FullYear|Active)|arch)|qrt|lice|avePreferences|mall)|h(ome|andleEvent)|navigate|c(har(CodeAt|At)|o(s|n(cat|textual|firm)|mpile)|eil|lear(Timeout|Interval)?|a(ptureEvents|ll)|reate(StyleSheet|Popup|EventObject))|t(o(GMTString|S(tring|ource)|U(TCString|pperCase)|Lo(caleString|werCase))|est|a(n|int(Enabled)?))|i(s(NaN|Finite)|ndexOf|talics)|d(isableExternalCapture|ump|etachEvent)|u(n(shift|taint|escape|watch)|pdateCommands)|j(oin|avaEnabled)|p(o(p|w)|ush|lugins.refresh|a(ddings|rse(Int|Float)?)|r(int|ompt|eference))|e(scape|nableExternalCapture|val|lementFromPoint|x(p|ec(Script|Command)?))|valueOf|UTC|queryCommand(State|Indeterm|Enabled|Value)|f(i(nd|le(ModifiedDate|Size|CreatedDate|UpdatedDate)|xed)|o(nt(size|color)|rward)|loor|romCharCode)|watch|l(ink|o(ad|g)|astIndexOf)|a(sin|nchor|cos|t(tachEvent|ob|an(2)?)|pply|lert|b(s|ort))|r(ou(nd|teEvents)|e(size(By|To)|calc|turnValue|place|verse|l(oad|ease(Capture|Events)))|andom)|g(o|et(ResponseHeader|M(i(nutes|lliseconds)|onth)|Se(conds|lection)|Hours|Year|Time(zoneOffset)?|Da(y|te)|UTC(M(i(nutes|lliseconds)|onth)|Seconds|Hours|Da(y|te)|FullYear)|FullYear|A(ttention|llResponseHeaders)))|m(in|ove(B(y|elow)|To(Absolute)?|Above)|ergeAttributes|a(tch|rgins|x))|b(toa|ig|o(ld|rderWidths)|link|ack))\b(?=\()</string>
<key>name</key>
<string>support.function.chai</string>
</dict>
<dict>
<key>match</key>
<string>\b(s(ub(stringData|mit)|plitText|e(t(NamedItem|Attribute(Node)?)|lect))|has(ChildNodes|Feature)|namedItem|c(l(ick|o(se|neNode))|reate(C(omment|DATASection|aption)|T(Head|extNode|Foot)|DocumentFragment|ProcessingInstruction|E(ntityReference|lement)|Attribute))|tabIndex|i(nsert(Row|Before|Cell|Data)|tem)|open|delete(Row|C(ell|aption)|T(Head|Foot)|Data)|focus|write(ln)?|a(dd|ppend(Child|Data))|re(set|place(Child|Data)|move(NamedItem|Child|Attribute(Node)?)?)|get(NamedItem|Element(sBy(Name|TagName)|ById)|Attribute(Node)?)|blur)\b(?=\()</string>
<key>name</key>
<string>support.function.dom.chai</string>
</dict>
<dict>
<key>match</key>
<string>(?&lt;=\.)(s(ystemLanguage|cr(ipts|ollbars|een(X|Y|Top|Left))|t(yle(Sheets)?|atus(Text|bar)?)|ibling(Below|Above)|ource|uffixes|e(curity(Policy)?|l(ection|f)))|h(istory|ost(name)?|as(h|Focus))|y|X(MLDocument|SLDocument)|n(ext|ame(space(s|URI)|Prop))|M(IN_VALUE|AX_VALUE)|c(haracterSet|o(n(structor|trollers)|okieEnabled|lorDepth|mp(onents|lete))|urrent|puClass|l(i(p(boardData)?|entInformation)|osed|asses)|alle(e|r)|rypto)|t(o(olbar|p)|ext(Transform|Indent|Decoration|Align)|ags)|SQRT(1_2|2)|i(n(ner(Height|Width)|put)|ds|gnoreCase)|zIndex|o(scpu|n(readystatechange|Line)|uter(Height|Width)|p(sProfile|ener)|ffscreenBuffering)|NEGATIVE_INFINITY|d(i(splay|alog(Height|Top|Width|Left|Arguments)|rectories)|e(scription|fault(Status|Ch(ecked|arset)|View)))|u(ser(Profile|Language|Agent)|n(iqueID|defined)|pdateInterval)|_content|p(ixelDepth|ort|ersonalbar|kcs11|l(ugins|atform)|a(thname|dding(Right|Bottom|Top|Left)|rent(Window|Layer)?|ge(X(Offset)?|Y(Offset)?))|r(o(to(col|type)|duct(Sub)?|mpter)|e(vious|fix)))|e(n(coding|abledPlugin)|x(ternal|pando)|mbeds)|v(isibility|endor(Sub)?|Linkcolor)|URLUnencoded|P(I|OSITIVE_INFINITY)|f(ilename|o(nt(Size|Family|Weight)|rmName)|rame(s|Element)|gColor)|E|whiteSpace|l(i(stStyleType|n(eHeight|kColor))|o(ca(tion(bar)?|lName)|wsrc)|e(ngth|ft(Context)?)|a(st(M(odified|atch)|Index|Paren)|yer(s|X)|nguage))|a(pp(MinorVersion|Name|Co(deName|re)|Version)|vail(Height|Top|Width|Left)|ll|r(ity|guments)|Linkcolor|bove)|r(ight(Context)?|e(sponse(XML|Text)|adyState))|global|x|m(imeTypes|ultiline|enubar|argin(Right|Bottom|Top|Left))|L(N(10|2)|OG(10E|2E))|b(o(ttom|rder(Width|RightWidth|BottomWidth|Style|Color|TopWidth|LeftWidth))|ufferDepth|elow|ackground(Color|Image)))\b</string>
<key>name</key>
<string>support.constant.chai</string>
</dict>
<dict>
<key>match</key>
<string>(?&lt;=\.)(s(hape|ystemId|c(heme|ope|rolling)|ta(ndby|rt)|ize|ummary|pecified|e(ctionRowIndex|lected(Index)?)|rc)|h(space|t(tpEquiv|mlFor)|e(ight|aders)|ref(lang)?)|n(o(Resize|tation(s|Name)|Shade|Href|de(Name|Type|Value)|Wrap)|extSibling|ame)|c(h(ildNodes|Off|ecked|arset)?|ite|o(ntent|o(kie|rds)|de(Base|Type)?|l(s|Span|or)|mpact)|ell(s|Spacing|Padding)|l(ear|assName)|aption)|t(ype|Bodies|itle|Head|ext|a(rget|gName)|Foot)|i(sMap|ndex|d|m(plementation|ages))|o(ptions|wnerDocument|bject)|d(i(sabled|r)|o(c(type|umentElement)|main)|e(clare|f(er|ault(Selected|Checked|Value)))|at(eTime|a))|useMap|p(ublicId|arentNode|r(o(file|mpt)|eviousSibling))|e(n(ctype|tities)|vent|lements)|v(space|ersion|alue(Type)?|Link|Align)|URL|f(irstChild|orm(s)?|ace|rame(Border)?)|width|l(ink(s)?|o(ngDesc|wSrc)|a(stChild|ng|bel))|a(nchors|c(ce(ssKey|pt(Charset)?)|tion)|ttributes|pplets|l(t|ign)|r(chive|eas)|xis|Link|bbr)|r(ow(s|Span|Index)|ules|e(v|ferrer|l|adOnly))|m(ultiple|e(thod|dia)|a(rgin(Height|Width)|xLength))|b(o(dy|rder)|ackground|gColor))\b</string>
<key>name</key>
<string>support.constant.dom.chai</string>
</dict>
<dict>
<key>match</key>
<string>\b(ELEMENT_NODE|ATTRIBUTE_NODE|TEXT_NODE|CDATA_SECTION_NODE|ENTITY_REFERENCE_NODE|ENTITY_NODE|PROCESSING_INSTRUCTION_NODE|COMMENT_NODE|DOCUMENT_NODE|DOCUMENT_TYPE_NODE|DOCUMENT_FRAGMENT_NODE|NOTATION_NODE|INDEX_SIZE_ERR|DOMSTRING_SIZE_ERR|HIERARCHY_REQUEST_ERR|WRONG_DOCUMENT_ERR|INVALID_CHARACTER_ERR|NO_DATA_ALLOWED_ERR|NO_MODIFICATION_ALLOWED_ERR|NOT_FOUND_ERR|NOT_SUPPORTED_ERR|INUSE_ATTRIBUTE_ERR)\b</string>
<key>name</key>
<string>support.constant.dom.chai</string>
</dict>
<dict>
<key>match</key>
<string>\bon(R(ow(s(inserted|delete)|e(nter|xit))|e(s(ize(start|end)?|et)|adystatechange))|Mouse(o(ut|ver)|down|up|move)|B(efore(cut|deactivate|u(nload|pdate)|p(aste|rint)|editfocus|activate)|lur)|S(croll|top|ubmit|elect(start|ionchange)?)|H(over|elp)|C(hange|ont(extmenu|rolselect)|ut|ellchange|l(ick|ose))|D(eactivate|ata(setc(hanged|omplete)|available)|r(op|ag(start|over|drop|en(ter|d)|leave)?)|blclick)|Unload|P(aste|ropertychange)|Error(update)?|Key(down|up|press)|Focus|Load|A(ctivate|fter(update|print)|bort))\b</string>
<key>name</key>
<string>support.function.event-handler.chai</string>
</dict>
<dict>
<key>match</key>
<string>!|\$|%|&amp;|\*|\-\-|\-|\+\+|\+|~|===|==|=|!=|!==|&lt;=|&gt;=|&lt;&lt;=|&gt;&gt;=|&gt;&gt;&gt;=|&lt;&gt;|&lt;|&gt;|!|&amp;&amp;|\|\||\?\:|\*=|(?&lt;!\()/=|%=|\+=|\-=|&amp;=|\^=|\b(in|instanceof|new|delete|typeof|void)\b</string>
<key>name</key>
<string>keyword.operator.chai</string>
</dict>
<dict>
<key>match</key>
<string>\b(Infinity|NaN|undefined)\b</string>
<key>name</key>
<string>constant.language.chai</string>
</dict>
<dict>
<key>begin</key>
<string>(?&lt;=[=(:]|^|return|&amp;&amp;|\|\||!)\s*(/)(?![/*+{}?])</string>
<key>beginCaptures</key>
<dict>
<key>1</key>
<dict>
<key>name</key>
<string>punctuation.definition.string.begin.chai</string>
</dict>
</dict>
<key>end</key>
<string>(/)[igm]*</string>
<key>endCaptures</key>
<dict>
<key>1</key>
<dict>
<key>name</key>
<string>punctuation.definition.string.end.chai</string>
</dict>
</dict>
<key>name</key>
<string>string.regexp.chai</string>
<key>patterns</key>
<array>
<dict>
<key>match</key>
<string>\\.</string>
<key>name</key>
<string>constant.character.escape.chai</string>
</dict>
</array>
</dict>
<dict>
<key>match</key>
<string>\;</string>
<key>name</key>
<string>punctuation.terminator.statement.chai</string>
</dict>
<dict>
<key>match</key>
<string>,[ |\t]*</string>
<key>name</key>
<string>meta.delimiter.object.comma.chai</string>
</dict>
<dict>
<key>match</key>
<string>\.</string>
<key>name</key>
<string>meta.delimiter.method.period.chai</string>
</dict>
<dict>
<key>match</key>
<string>\{|\}</string>
<key>name</key>
<string>meta.brace.curly.chai</string>
</dict>
<dict>
<key>match</key>
<string>\(|\)</string>
<key>name</key>
<string>meta.brace.round.chai</string>
</dict>
<dict>
<key>match</key>
<string>\[|\]</string>
<key>name</key>
<string>meta.brace.square.chai</string>
</dict>
</array>
<key>scopeName</key>
<string>source.chai</string>
<key>uuid</key>
<string>93E017CC-6F27-11D9-90EB-000D93589AF6</string>
</dict>
</plist>

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,14 +1,15 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) // Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.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_ #ifndef CHAISCRIPT_HPP_
#define CHAISCRIPT_HPP_ #define CHAISCRIPT_HPP_
/// @mainpage /// @mainpage
/// [ChaiScript](http://www.chaiscript.com") is a scripting language designed specifically for integration with C++. It provides /// [ChaiScript](http://www.chaiscript.com") is a scripting language designed specifically for integration with C++. It provides
/// seamless integration with C++ on all levels, including shared_ptr objects, functors and exceptions. /// seamless integration with C++ on all levels, including shared_ptr objects, functors and exceptions.
@ -18,7 +19,8 @@
/// ///
/// The end user parts of the API are extremely simple both in size and ease of use. /// The end user parts of the API are extremely simple both in size and ease of use.
/// ///
/// Currently, all source control and project management aspects of ChaiScript occur on [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").
/// ///
/// ------------------------------------------------------------ /// ------------------------------------------------------------
/// ///
@ -65,7 +67,7 @@
/// int main() /// int main()
/// { /// {
/// chaiscript::ChaiScript chai; /// chaiscript::ChaiScript chai;
/// chai.add(&function, "function"); /// chai.add(chaiscript::fun(&function), "function");
/// ///
/// double d = chai.eval<double>("function(3, 4.75);"); /// double d = chai.eval<double>("function(3, 4.75);");
/// } /// }
@ -311,8 +313,8 @@
/// As much as possible, ChaiScript attempts to convert between &, *, const &, const *, std::shared_ptr<T>, /// As much as possible, ChaiScript attempts to convert between &, *, const &, const *, std::shared_ptr<T>,
/// std::shared_ptr<const T>, std::reference_wrapper<T>, std::reference_wrapper<const T> and value types automatically. /// std::shared_ptr<const T>, std::reference_wrapper<T>, std::reference_wrapper<const T> and value types automatically.
/// ///
/// If a chaiscript::var object was created in C++ from a pointer, it cannot be converted to a shared_ptr (this would add invalid reference counting). /// If a chaiscript::var object was created in C++ from a pointer, it cannot be converted to a shared_ptr (this would add invalid reference
/// Const may be added, but never removed. /// 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. /// The take away is that you can pretty much expect function calls to Just Work when you need them to.
/// ///
@ -466,7 +468,8 @@
/// chaiscript::ChaiScript chai; /// chaiscript::ChaiScript chai;
/// ///
/// try { /// try {
/// chai.eval("throw(runtime_error(@"error@"))", chaiscript::exception_specification<int, double, float, const std::string &, const std::exception &>()); /// chai.eval("throw(runtime_error(@"error@"))", chaiscript::exception_specification<int, double, float, const std::string &, const
/// std::exception &>());
/// } catch (const double e) { /// } catch (const double e) {
/// } catch (int) { /// } catch (int) {
/// } catch (float) { /// } catch (float) {
@ -479,8 +482,6 @@
/// @sa chaiscript::Exception_Handler for details on automatic exception unboxing /// @sa chaiscript::Exception_Handler for details on automatic exception unboxing
/// @sa chaiscript::exception_specification /// @sa chaiscript::exception_specification
/// @page LangObjectSystemRef ChaiScript Language Object Model Reference /// @page LangObjectSystemRef ChaiScript Language Object Model Reference
/// ///
/// ///
@ -648,7 +649,6 @@
/// @sa @ref LangKeywordRef /// @sa @ref LangKeywordRef
/// @sa ChaiScript_Language for Built in Functions /// @sa ChaiScript_Language for Built in Functions
/// @page LangKeywordRef ChaiScript Language Keyword Reference /// @page LangKeywordRef ChaiScript Language Keyword Reference
/// ///
/// ///
@ -695,11 +695,10 @@
/// Begins a function or method definition /// Begins a function or method definition
/// ///
/// ~~~~~~~~ /// ~~~~~~~~
/// Function Definition ::= [annotation + CR/LF] "def" identifier "(" [[type] arg ("," [type] arg)*] ")" [":" guard] block /// Function Definition ::= "def" identifier "(" [[type] arg ("," [type] arg)*] ")" [":" guard] block
/// Method Definition ::= [annotation + CR/LF] "def" class_name "::" method_name "(" [[type] arg ("," [type] arg)*] ")" [":" guard] block /// Method Definition ::= "def" class_name "::" method_name "(" [[type] arg ("," [type] arg)*] ")" [":" guard] block
/// ~~~~~~~~ /// ~~~~~~~~
/// ///
/// annotation: meta-annotation on function, currently used as documentation. Optional.
/// identifier: name of function. Required. /// identifier: name of function. Required.
/// args: comma-delimited list of parameter names with optional type specifiers. Optional. /// args: comma-delimited list of parameter names with optional type specifiers. Optional.
/// guards: guarding statement that act as a prerequisite for the function. Optional. /// guards: guarding statement that act as a prerequisite for the function. Optional.
@ -810,23 +809,29 @@
/// ///
/// Synonym for @ref keywordauto /// Synonym for @ref keywordauto
/// @namespace chaiscript /// @namespace chaiscript
/// @brief Namespace chaiscript contains every API call that the average user will be concerned with. /// @brief Namespace chaiscript contains every API call that the average user will be concerned with.
/// @namespace chaiscript::detail /// @namespace chaiscript::detail
/// @brief Classes and functions reserved for internal use. Items in this namespace are not supported. /// @brief Classes and functions reserved for internal use. Items in this namespace are not supported.
#include "chaiscript_defines.hpp" #include "chaiscript_basic.hpp"
#include "chaiscript_stdlib.hpp"
#include "dispatchkit/dispatchkit.hpp" #include "language/chaiscript_parser.hpp"
#include "dispatchkit/function_call.hpp"
#include "dispatchkit/dynamic_object.hpp"
#include "dispatchkit/boxed_number.hpp"
#include "language/chaiscript_eval.hpp"
#include "language/chaiscript_engine.hpp"
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_ */ #endif /* CHAISCRIPT_HPP_ */

View File

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

View File

@ -1,27 +1,29 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) // Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
#ifndef CHAISCRIPT_DEFINES_HPP_ #ifndef CHAISCRIPT_DEFINES_HPP_
#define CHAISCRIPT_DEFINES_HPP_ #define CHAISCRIPT_DEFINES_HPP_
#ifdef _MSC_VER #ifdef _MSC_VER
#define CHAISCRIPT_STRINGIZE(x) "" #x
#define CHAISCRIPT_STRINGIZE_EXPANDED(x) CHAISCRIPT_STRINGIZE(x)
#define CHAISCRIPT_COMPILER_VERSION CHAISCRIPT_STRINGIZE_EXPANDED(_MSC_FULL_VER)
#define CHAISCRIPT_MSVC _MSC_VER #define CHAISCRIPT_MSVC _MSC_VER
#define CHAISCRIPT_HAS_DECLSPEC #define CHAISCRIPT_HAS_DECLSPEC
#if _MSC_VER <= 1800
#define CHAISCRIPT_MSVC_12 static_assert(_MSC_FULL_VER >= 190024210, "Visual C++ 2015 Update 3 or later required");
#endif
#endif #else
#define CHAISCRIPT_COMPILER_VERSION __VERSION__
#ifndef CHAISCRIPT_MSVC_12
#define CHAISCRIPT_HAS_MAGIC_STATICS
#endif #endif
#include <string_view>
#include <vector> #include <vector>
#if defined( _LIBCPP_VERSION ) #if defined(_LIBCPP_VERSION)
#define CHAISCRIPT_LIBCPP #define CHAISCRIPT_LIBCPP
#endif #endif
@ -29,22 +31,27 @@
#define CHAISCRIPT_WINDOWS #define CHAISCRIPT_WINDOWS
#endif #endif
#if (defined(__GNUC__) && __GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8) || (defined(__llvm__) && !defined(CHAISCRIPT_LIBCPP)) #if defined(_WIN32)
/// Currently only g++>=4.8 supports this natively #if defined(__llvm__)
/// \todo Make this support other compilers when possible #define CHAISCRIPT_COMPILER_NAME "clang(windows)"
#define CHAISCRIPT_HAS_THREAD_LOCAL #elif defined(__GNUC__)
#endif #define CHAISCRIPT_COMPILER_NAME "gcc(mingw)"
#if (defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ == 6)
#define CHAISCRIPT_GCC_4_6
#endif
#if (defined(__GNUC__) && __GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7) || defined(CHAISCRIPT_MSVC) || defined(__llvm__)
#define CHAISCRIPT_OVERRIDE override
#else #else
#define CHAISCRIPT_OVERRIDE #define CHAISCRIPT_COMPILER_NAME "msvc"
#endif
#else
#if defined(__llvm__)
#define CHAISCRIPT_COMPILER_NAME "clang"
#elif defined(__GNUC__)
#define CHAISCRIPT_COMPILER_NAME "gcc"
#else
#define CHAISCRIPT_COMPILER_NAME "unknown"
#endif
#endif #endif
#if defined(__llvm__)
#define CHAISCRIPT_CLANG
#endif
#ifdef CHAISCRIPT_HAS_DECLSPEC #ifdef CHAISCRIPT_HAS_DECLSPEC
#define CHAISCRIPT_MODULE_EXPORT extern "C" __declspec(dllexport) #define CHAISCRIPT_MODULE_EXPORT extern "C" __declspec(dllexport)
@ -52,31 +59,186 @@
#define CHAISCRIPT_MODULE_EXPORT extern "C" #define CHAISCRIPT_MODULE_EXPORT extern "C"
#endif #endif
#ifdef CHAISCRIPT_MSVC_12 #if defined(CHAISCRIPT_MSVC) || (defined(__GNUC__) && __GNUC__ >= 5) || defined(CHAISCRIPT_CLANG)
#define CHAISCRIPT_NOEXCEPT throw() #define CHAISCRIPT_UTF16_UTF32
#define CHAISCRIPT_CONSTEXPR
#else
#define CHAISCRIPT_NOEXCEPT noexcept
#define CHAISCRIPT_CONSTEXPR constexpr
#endif #endif
#ifdef _DEBUG
#define CHAISCRIPT_DEBUG true
#else
#define CHAISCRIPT_DEBUG false
#endif
#include <cmath>
#include <memory> #include <memory>
#include <string>
namespace chaiscript { namespace chaiscript {
static const int version_major = 5; constexpr static const int version_major = 7;
static const int version_minor = 7; constexpr static const int version_minor = 0;
static const int version_patch = 2; constexpr static const int version_patch = 0;
template<typename B, typename D, typename ...Arg> constexpr static const char *compiler_version = CHAISCRIPT_COMPILER_VERSION;
inline std::shared_ptr<B> make_shared(Arg && ... arg) 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) {
#ifdef CHAISCRIPT_USE_STD_MAKE_SHARED #ifdef CHAISCRIPT_USE_STD_MAKE_SHARED
return std::make_shared<D>(std::forward<Arg>(arg)...); return std::make_shared<D>(std::forward<Arg>(arg)...);
#else #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 #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 #endif
}
struct Build_Info {
[[nodiscard]] constexpr static int version_major() noexcept { return chaiscript::version_major; }
[[nodiscard]] constexpr static int version_minor() noexcept { return chaiscript::version_minor; }
[[nodiscard]] constexpr static int version_patch() noexcept { return chaiscript::version_patch; }
[[nodiscard]] static std::string version() {
return std::to_string(version_major()) + '.' + std::to_string(version_minor()) + '.' + std::to_string(version_patch());
}
[[nodiscard]] static std::string compiler_id() { return compiler_name() + '-' + compiler_version(); }
[[nodiscard]] static std::string build_id() { return compiler_id() + (debug_build() ? "-Debug" : "-Release"); }
[[nodiscard]] static std::string compiler_version() { return chaiscript::compiler_version; }
[[nodiscard]] static std::string compiler_name() { return chaiscript::compiler_name; }
[[nodiscard]] constexpr static bool debug_build() noexcept { return chaiscript::debug_build; }
};
template<typename T>
[[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;
}
t *= 10;
t += c - '0';
}
return t;
}
template<typename T>
[[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;
for (const auto c : t_str) {
switch (c) {
case '.':
decimal_place = 10;
break;
case 'e':
case 'E':
exponent = 1;
decimal_place = 0;
base = t;
t = 0;
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 exponent ? base * std::pow(T(10), t * static_cast<T>(exponent)) : t;
}
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 {
};
};
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
};
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

@ -14,53 +14,53 @@
#include <vector> #include <vector>
#include "chaiscript_defines.hpp" #include "chaiscript_defines.hpp"
#include "dispatchkit/dispatchkit.hpp" #include "language/chaiscript_common.hpp"
#include "dispatchkit/function_call.hpp"
//#include "dispatchkit/dispatchkit.hpp"
#include "dispatchkit/bootstrap.hpp" #include "dispatchkit/bootstrap.hpp"
#include "dispatchkit/bootstrap_stl.hpp" #include "dispatchkit/bootstrap_stl.hpp"
#include "dispatchkit/boxed_value.hpp" #include "dispatchkit/operators.hpp"
#include "language/chaiscript_prelude.chai" //#include "dispatchkit/boxed_value.hpp"
#include "dispatchkit/register_function.hpp"
#include "language/chaiscript_prelude.hpp"
#include "utility/json_wrap.hpp" #include "utility/json_wrap.hpp"
#ifndef CHAISCRIPT_NO_THREADS #ifndef CHAISCRIPT_NO_THREADS
#include <future> #include <future>
#endif #endif
/// @file /// @file
/// ///
/// This file generates the standard library that normal ChaiScript usage requires. /// This file generates the standard library that normal ChaiScript usage requires.
namespace chaiscript namespace chaiscript {
{ class Std_Lib {
class Std_Lib
{
public: public:
[[nodiscard]] static ModulePtr library() {
auto lib = std::make_shared<Module>();
bootstrap::Bootstrap::bootstrap(*lib);
static ModulePtr library() bootstrap::standard_library::vector_type<std::vector<Boxed_Value>>("Vector", *lib);
{ bootstrap::standard_library::string_type<std::string>("string", *lib);
using namespace bootstrap; 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);
ModulePtr lib = Bootstrap::bootstrap();
lib->add(standard_library::vector_type<std::vector<Boxed_Value> >("Vector"));
lib->add(standard_library::string_type<std::string>("string"));
lib->add(standard_library::map_type<std::map<std::string, Boxed_Value> >("Map"));
lib->add(standard_library::pair_type<std::pair<Boxed_Value, Boxed_Value > >("Pair"));
#ifndef CHAISCRIPT_NO_THREADS #ifndef CHAISCRIPT_NO_THREADS
lib->add(standard_library::future_type<std::future<chaiscript::Boxed_Value>>("future")); 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"); lib->add(chaiscript::fun(
[](const std::function<chaiscript::Boxed_Value()> &t_func) { return std::async(std::launch::async, t_func); }),
"async");
#endif #endif
lib->add(json_wrap::library()); json_wrap::library(*lib);
lib->eval(ChaiScript_Prelude::chaiscript_prelude() /*, "standard prelude"*/ ); lib->eval(ChaiScript_Prelude::chaiscript_prelude() /*, "standard prelude"*/);
return lib; return lib;
} }
}; };
} } // namespace chaiscript
#endif #endif

View File

@ -1,21 +1,24 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) // Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.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_ #ifndef CHAISCRIPT_THREADING_HPP_
#define CHAISCRIPT_THREADING_HPP_ #define CHAISCRIPT_THREADING_HPP_
#include <unordered_map> #include <unordered_map>
#ifndef CHAISCRIPT_NO_THREADS #ifndef CHAISCRIPT_NO_THREADS
#include <thread>
#include <mutex> #include <mutex>
#include <shared_mutex>
#include <thread>
#else #else
#ifndef CHAISCRIPT_NO_THREADS_WARNING #ifndef CHAISCRIPT_NO_THREADS_WARNING
#pragma message ("ChaiScript is compiling without thread safety.") #pragma message("ChaiScript is compiling without thread safety.")
#endif #endif
#endif #endif
@ -29,213 +32,102 @@
/// It also has the side effect that the chaiscript::ChaiScript object may not be accessed from more than /// It also has the side effect that the chaiscript::ChaiScript object may not be accessed from more than
/// one thread simultaneously. /// one thread simultaneously.
namespace chaiscript /// 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.
namespace detail /// This allows us to avoid \#ifdef code in the sections that need thread safety.
{ namespace chaiscript::detail::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 threading
{
#ifndef CHAISCRIPT_NO_THREADS #ifndef CHAISCRIPT_NO_THREADS
template<typename T> template<typename T>
class unique_lock : public std::unique_lock<T> using unique_lock = std::unique_lock<T>;
{
public:
unique_lock(T &t) : std::unique_lock<T>(t) {}
};
template<typename T> template<typename T>
class shared_lock : public std::unique_lock<T> using shared_lock = std::shared_lock<T>;
{
public:
shared_lock(T &t) : std::unique_lock<T>(t) {}
void unlock() {}
};
template<typename T> template<typename T>
class lock_guard : public std::lock_guard<T> using lock_guard = std::lock_guard<T>;
{
public:
lock_guard(T &t) : std::lock_guard<T>(t) {}
};
class shared_mutex : public std::mutex { }; using std::shared_mutex;
using std::mutex; using std::mutex;
using std::recursive_mutex; using std::recursive_mutex;
#ifdef CHAISCRIPT_HAS_THREAD_LOCAL
/// Typesafe thread specific storage. If threading is enabled, this class uses a mutex protected map. If /// Typesafe thread specific storage. If threading is enabled, this class uses a mutex protected map. If
/// threading is not enabled, the class always returns the same data, regardless of which thread it is called from. /// threading is not enabled, the class always returns the same data, regardless of which thread it is called from.
template<typename T> template<typename T>
class Thread_Storage class Thread_Storage {
{
public: 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;
Thread_Storage(void *t_key) ~Thread_Storage() { t().erase(this); }
: m_key(t_key)
{
}
~Thread_Storage() inline const T *operator->() const noexcept { return &(t()[this]); }
{
t().erase(m_key);
}
inline const T *operator->() const inline const T &operator*() const noexcept { return t()[this]; }
{
return &(t()[m_key]);
}
inline const T &operator*() const inline T *operator->() noexcept { return &(t()[this]); }
{
return t()[m_key];
}
inline T *operator->()
{
return &(t()[m_key]);
}
inline T &operator*()
{
return t()[m_key];
}
inline T &operator*() noexcept { return t()[this]; }
void *m_key; void *m_key;
private: private:
static std::unordered_map<void*, T> &t() /// todo: is it valid to make this noexcept? The allocation could fail, but if it
{ /// does there is no possible way to recover
thread_local static std::unordered_map<void *, T> my_t; static std::unordered_map<const void *, T> &t() noexcept {
static thread_local std::unordered_map<const void *, T> my_t;
return my_t; return my_t;
} }
}; };
#else
/// Typesafe thread specific storage. If threading is enabled, this class uses a mutex protected map. If
/// threading is not enabled, the class always returns the same data, regardless of which thread it is called from.
///
/// This version is used if the compiler does not support thread_local
template<typename T>
class Thread_Storage
{
public:
Thread_Storage(void *)
{
}
inline const T *operator->() const
{
return get_tls().get();
}
inline const T &operator*() const
{
return *get_tls();
}
inline T *operator->()
{
return get_tls().get();
}
inline T &operator*()
{
return *get_tls();
}
private:
/// \todo this leaks thread instances. It needs to be culled from time to time
std::shared_ptr<T> get_tls() const
{
unique_lock<mutex> lock(m_mutex);
auto itr = m_instances.find(std::this_thread::get_id());
if (itr != m_instances.end()) { return itr->second; }
std::shared_ptr<T> new_instance(std::make_shared<T>());
m_instances.insert(std::make_pair(std::this_thread::get_id(), new_instance));
return new_instance;
}
mutable mutex m_mutex;
mutable std::unordered_map<std::thread::id, std::shared_ptr<T> > m_instances;
};
#endif // threading enabled but no tls
#else // threading disabled #else // threading disabled
template<typename T> template<typename T>
class unique_lock class unique_lock {
{
public: public:
unique_lock(T &) {} constexpr explicit unique_lock(T &) noexcept {}
void lock() {} constexpr void lock() noexcept {}
void unlock() {} constexpr void unlock() noexcept {}
}; };
template<typename T> template<typename T>
class shared_lock class shared_lock {
{
public: public:
shared_lock(T &) {} constexpr explicit shared_lock(T &) noexcept {}
void lock() {} constexpr void lock() noexcept {}
void unlock() {} constexpr void unlock() noexcept {}
}; };
template<typename T> template<typename T>
class lock_guard class lock_guard {
{
public: public:
lock_guard(T &) {} constexpr explicit lock_guard(T &) noexcept {}
}; };
class shared_mutex { }; class shared_mutex {
};
class recursive_mutex {};
class recursive_mutex {
};
template<typename T> template<typename T>
class Thread_Storage class Thread_Storage {
{
public: public:
Thread_Storage(void *) constexpr explicit Thread_Storage() noexcept {}
{
}
inline T *operator->() const constexpr inline T *operator->() const noexcept { return &obj; }
{
return &obj;
}
inline T &operator*() const constexpr inline T &operator*() const noexcept { return obj; }
{
return obj;
}
private: private:
mutable T obj; mutable T obj;
}; };
#endif #endif
} } // namespace chaiscript::detail::threading
}
}
#endif #endif

View File

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

View File

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

View File

@ -1,74 +1,60 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) // Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.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_ #ifndef CHAISCRIPT_BIND_FIRST_HPP_
#define CHAISCRIPT_BIND_FIRST_HPP_ #define CHAISCRIPT_BIND_FIRST_HPP_
#include <functional> #include <functional>
namespace chaiscript namespace chaiscript {
{ namespace detail {
namespace detail
{
template<typename T> template<typename T>
T* get_pointer(T *t) constexpr T *get_pointer(T *t) noexcept {
{
return t; return t;
} }
template<typename T> template<typename T>
T* get_pointer(const std::reference_wrapper<T> &t) T *get_pointer(const std::reference_wrapper<T> &t) noexcept {
{
return &t.get(); return &t.get();
} }
template<typename O, typename Ret, typename P1, typename ... Param> template<typename O, typename Ret, typename P1, typename... Param>
std::function<Ret (Param...)> bind_first(Ret (*f)(P1, Param...), O&& o) 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)...); };
return std::function<Ret (Param...)>(
[f, o](Param...param) -> Ret {
return f(std::forward<O>(o), std::forward<Param>(param)...);
}
);
} }
template<typename O, typename Ret, typename Class, typename ... Param> template<typename O, typename Ret, typename Class, typename... Param>
std::function<Ret (Param...)> bind_first(Ret (Class::*f)(Param...), O&& o) 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)...); };
return std::function<Ret (Param...)>(
[f, o](Param...param) -> Ret {
return (get_pointer(o)->*f)(std::forward<Param>(param)...);
}
);
} }
template<typename O, typename Ret, typename Class, typename ... Param> template<typename O, typename Ret, typename Class, typename... Param>
std::function<Ret (Param...)> bind_first(Ret (Class::*f)(Param...) const, O&& o) 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)...); };
return std::function<Ret (Param...)>(
[f, o](Param...param) -> Ret {
return (get_pointer(o)->*f)(std::forward<Param>(param)...);
}
);
} }
template<typename O, typename Ret, typename P1, typename ... Param> template<typename O, typename Ret, typename P1, typename... Param>
std::function<Ret (Param...)> bind_first(const std::function<Ret (P1, Param...)> &f, O&& o) 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)...); };
return std::function<Ret (Param...)>(
[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>
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>
constexpr auto bind_first(const F &f, O &&o) {
return bind_first(f, std::forward<O>(o), &F::operator());
}
} // namespace detail
} // namespace chaiscript
#endif #endif

View File

@ -1,136 +1,85 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) // Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.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_ #ifndef CHAISCRIPT_BOOTSTRAP_HPP_
#define CHAISCRIPT_BOOTSTRAP_HPP_ #define CHAISCRIPT_BOOTSTRAP_HPP_
#include <cstdint>
#include <exception>
#include <functional>
#include <memory>
#include <sstream>
#include <stdexcept>
#include <string>
#include <type_traits>
#include <vector>
#include <iterator>
#include "bad_boxed_cast.hpp"
#include "boxed_cast.hpp"
#include "boxed_number.hpp"
#include "boxed_value.hpp"
#include "dispatchkit.hpp"
#include "type_conversions.hpp"
#include "dynamic_object.hpp"
#include "operators.hpp"
#include "proxy_constructors.hpp"
#include "proxy_functions.hpp"
#include "proxy_functions_detail.hpp"
#include "register_function.hpp"
#include "type_info.hpp"
#include "../utility/utility.hpp" #include "../utility/utility.hpp"
#include "../language/chaiscript_common.hpp" #include "register_function.hpp"
namespace chaiscript /// \brief Classes and functions useful for bootstrapping of ChaiScript and adding of new types
{ namespace chaiscript::bootstrap {
/// \brief Classes and functions useful for bootstrapping of ChaiScript and adding of new types template<typename T, typename = typename std::enable_if<std::is_array<T>::value>::type>
namespace bootstrap void array(const std::string &type, Module &m) {
{ using ReturnType = typename std::remove_extent<T>::type;
namespace detail
{
/// \brief Constructs a new POD value object from a Boxed_Number
/// \param[in] v Boxed_Number to copy into the new object
/// \returns The newly created object.
template<typename P1>
std::shared_ptr<P1> construct_pod(const Boxed_Number &v)
{
return std::make_shared<P1>(v.get_as<P1>());
}
}
template<typename T, typename = typename std::enable_if<std::is_array<T>::value>::type > m.add(user_type<T>(), type);
ModulePtr array(const std::string &type, ModulePtr m = std::make_shared<Module>()) m.add(fun([](T &t, size_t index) -> ReturnType & {
{ constexpr const auto extent = std::extent<T>::value;
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) { if (extent > 0 && index >= extent) {
throw std::range_error("Array index out of range. Received: " + std::to_string(index) + " expected < " + std::to_string(extent)); throw std::range_error("Array index out of range. Received: " + std::to_string(index) + " expected < "
+ std::to_string(extent));
} else { } else {
return t[index]; return t[index];
} }
} }),
), "[]" "[]");
);
m->add(fun( m.add(fun([](const T &t, size_t index) -> const ReturnType & {
[extent](const T &t, size_t index)->const ReturnType &{ constexpr const auto extent = std::extent<T>::value;
if (extent > 0 && index >= extent) { if (extent > 0 && index >= extent) {
throw std::range_error("Array index out of range. Received: " + std::to_string(index) + " expected < " + std::to_string(extent)); throw std::range_error("Array index out of range. Received: " + std::to_string(index) + " expected < "
+ std::to_string(extent));
} else { } else {
return t[index]; return t[index];
} }
} }),
), "[]" "[]");
);
m->add(fun( m.add(fun([](const T &) { return std::extent<T>::value; }), "size");
[extent](const T &) {
return extent;
}), "size");
return m;
} }
/// \brief Adds a copy constructor for the given type to the given Model /// \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] 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 /// \param[in,out] m The Module to add the copy constructor to
/// \tparam T The type to add a copy constructor for /// \tparam T The type to add a copy constructor for
/// \returns The passed in ModulePtr, or the newly constructed one if the default param is used /// \returns The passed in Module
template<typename T> template<typename T>
ModulePtr copy_constructor(const std::string &type, ModulePtr m = std::make_shared<Module>()) void copy_constructor(const std::string &type, Module &m) {
{ m.add(constructor<T(const T &)>(), type);
m->add(constructor<T (const T &)>(), type);
return m;
} }
/// \brief Add all comparison operators for the templated type. Used during bootstrap, also available to users. /// \brief Add all comparison operators for the templated type. Used during bootstrap, also available to users.
/// \tparam T Type to create comparison operators for /// \tparam T Type to create comparison operators for
/// \param[in,out] m module to add comparison operators to /// \param[in,out] m module to add comparison operators to
/// \returns the passed in ModulePtr or the newly constructed one if the default params are used. /// \returns the passed in Module.
template<typename T> template<typename T>
ModulePtr opers_comparison(ModulePtr m = std::make_shared<Module>()) void opers_comparison(Module &m) {
{
operators::equal<T>(m); operators::equal<T>(m);
operators::greater_than<T>(m); operators::greater_than<T>(m);
operators::greater_than_equal<T>(m); operators::greater_than_equal<T>(m);
operators::less_than<T>(m); operators::less_than<T>(m);
operators::less_than_equal<T>(m); operators::less_than_equal<T>(m);
operators::not_equal<T>(m); operators::not_equal<T>(m);
return m;
} }
/// \brief Adds default and copy constructors for the given type /// \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] type The name of the type to add the constructors for.
/// \param[in,out] m The Module to add the basic constructors to /// \param[in,out] m The Module to add the basic constructors to
/// \tparam T Type to generate basic constructors for /// \tparam T Type to generate basic constructors for
/// \returns The passed in ModulePtr, or the newly constructed one if the default param is used /// \returns The passed in Module
/// \sa copy_constructor /// \sa copy_constructor
/// \sa constructor /// \sa constructor
template<typename T> template<typename T>
ModulePtr basic_constructors(const std::string &type, ModulePtr m = std::make_shared<Module>()) void basic_constructors(const std::string &type, Module &m) {
{ m.add(constructor<T()>(), type);
m->add(constructor<T ()>(), type);
copy_constructor<T>(type, m); copy_constructor<T>(type, m);
return m;
} }
/// \brief Adds a constructor for a POD type /// \brief Adds a constructor for a POD type
@ -138,94 +87,58 @@ namespace chaiscript
/// \param[in] type The name of the type /// \param[in] type The name of the type
/// \param[in,out] m The Module to add the constructor to /// \param[in,out] m The Module to add the constructor to
template<typename T> template<typename T>
ModulePtr construct_pod(const std::string &type, ModulePtr m = std::make_shared<Module>()) void construct_pod(const std::string &type, Module &m) {
{ m.add(fun([](const Boxed_Number &bn) { return bn.get_as<T>(); }), type);
m->add(fun(&detail::construct_pod<T>), type);
return m;
}
/// to_string function for internal use. Uses ostream operator<<
template<typename Input>
std::string to_string(Input i)
{
std::stringstream ss;
ss << i;
return ss.str();
} }
/// Internal function for converting from a string to a value /// Internal function for converting from a string to a value
/// uses ostream operator >> to perform the conversion /// uses ostream operator >> to perform the conversion
template<typename Input> template<typename Input>
auto parse_string(const std::string &i) Input parse_string(const std::string &i) {
-> typename std::enable_if< if constexpr (!std::is_same<Input, wchar_t>::value && !std::is_same<Input, char16_t>::value && !std::is_same<Input, char32_t>::value) {
!std::is_same<Input, wchar_t>::value
&& !std::is_same<Input, char16_t>::value
&& !std::is_same<Input, char32_t>::value,
Input>::type
{
std::stringstream ss(i); std::stringstream ss(i);
Input t; Input t;
ss >> t; ss >> t;
return t; return t;
} } else {
template<typename Input>
auto parse_string(const std::string &)
-> typename std::enable_if<
std::is_same<Input, wchar_t>::value
|| std::is_same<Input, char16_t>::value
|| std::is_same<Input, char32_t>::value,
Input>::type
{
throw std::runtime_error("Parsing of wide characters is not yet supported"); throw std::runtime_error("Parsing of wide characters is not yet supported");
} }
}
/// Add all common functions for a POD type. All operators, and /// Add all common functions for a POD type. All operators, and
/// common conversions /// common conversions
template<typename T> template<typename T>
ModulePtr bootstrap_pod_type(const std::string &name, ModulePtr m = std::make_shared<Module>()) void bootstrap_pod_type(const std::string &name, Module &m) {
{ m.add(user_type<T>(), name);
m->add(user_type<T>(), name); m.add(constructor<T()>(), name);
m->add(constructor<T()>(), name);
construct_pod<T>(name, m); construct_pod<T>(name, m);
m->add(fun(&parse_string<T>), "to_" + name); m.add(fun(&parse_string<T>), "to_" + name);
return m; m.add(fun([](const T t) { return t; }), "to_" + name);
} }
/// "clone" function for a shared_ptr type. This is used in the case /// "clone" function for a shared_ptr type. This is used in the case
/// where you do not want to make a deep copy of an object during cloning /// where you do not want to make a deep copy of an object during cloning
/// but want to instead maintain the shared_ptr. It is needed internally /// but want to instead maintain the shared_ptr. It is needed internally
/// for handling of Proxy_Function object (that is, /// for handling of Proxy_Function object (that is,
/// function variables. /// function variables.
template<typename Type> template<typename Type>
std::shared_ptr<Type> shared_ptr_clone(const std::shared_ptr<Type> &p) auto shared_ptr_clone(const std::shared_ptr<Type> &p) {
{
return p; return p;
} }
/// Specific version of shared_ptr_clone just for Proxy_Functions /// Specific version of shared_ptr_clone just for Proxy_Functions
template<typename Type> template<typename Type>
std::shared_ptr<typename std::remove_const<Type>::type> std::shared_ptr<std::remove_const_t<Type>> shared_ptr_unconst_clone(const std::shared_ptr<std::add_const_t<Type>> &p) {
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); 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 /// Assignment function for shared_ptr objects, does not perform a copy of the
/// object pointed to, instead maintains the shared_ptr concept. /// object pointed to, instead maintains the shared_ptr concept.
/// Similar to shared_ptr_clone. Used for Proxy_Function. /// Similar to shared_ptr_clone. Used for Proxy_Function.
template<typename Type> template<typename Type>
Boxed_Value ptr_assign(Boxed_Value lhs, const std::shared_ptr<Type> &rhs) Boxed_Value ptr_assign(Boxed_Value lhs, const std::shared_ptr<Type> &rhs) {
{ if (lhs.is_undef() || (!lhs.get_type_info().is_const() && lhs.get_type_info().bare_equal(chaiscript::detail::Get_Type_Info<Type>::get()))) {
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)); lhs.assign(Boxed_Value(rhs));
return lhs; return lhs;
} else { } else {
@ -235,156 +148,110 @@ namespace chaiscript
/// Class consisting of only static functions. All default bootstrapping occurs /// Class consisting of only static functions. All default bootstrapping occurs
/// from this class. /// from this class.
class Bootstrap class Bootstrap {
{
private: private:
/// Function allowing for assignment of an unknown type to any other value /// Function allowing for assignment of an unknown type to any other value
static Boxed_Value unknown_assign(Boxed_Value lhs, Boxed_Value rhs) static Boxed_Value unknown_assign(Boxed_Value lhs, Boxed_Value rhs) {
{ if (lhs.is_undef()) {
if (lhs.is_undef())
{
return (lhs.assign(rhs)); return (lhs.assign(rhs));
} else { } else {
throw exception::bad_boxed_cast("boxed_value has a set type already"); throw exception::bad_boxed_cast("boxed_value has a set type already");
} }
} }
static void print(const std::string &s) static void print(const std::string &s) noexcept { fwrite(s.c_str(), 1, s.size(), stdout); }
{
fwrite(s.c_str(), 1, s.size(), stdout);
}
static void println(const std::string &s)
{
puts(s.c_str());
}
static void println(const std::string &s) noexcept { puts(s.c_str()); }
/// Add all arithmetic operators for PODs /// Add all arithmetic operators for PODs
static void opers_arithmetic_pod(ModulePtr m = std::make_shared<Module>()) static void opers_arithmetic_pod(Module &m) {
{ m.add(fun(&Boxed_Number::equals), "==");
m->add(fun(&Boxed_Number::equals), "=="); m.add(fun(&Boxed_Number::less_than), "<");
m->add(fun(&Boxed_Number::less_than), "<"); m.add(fun(&Boxed_Number::greater_than), ">");
m->add(fun(&Boxed_Number::greater_than), ">"); m.add(fun(&Boxed_Number::greater_than_equal), ">=");
m->add(fun(&Boxed_Number::greater_than_equal), ">="); m.add(fun(&Boxed_Number::less_than_equal), "<=");
m->add(fun(&Boxed_Number::less_than_equal), "<="); m.add(fun(&Boxed_Number::not_equal), "!=");
m->add(fun(&Boxed_Number::not_equal), "!=");
m->add(fun(&Boxed_Number::pre_decrement), "--");
m->add(fun(&Boxed_Number::pre_increment), "++");
m->add(fun(&Boxed_Number::sum), "+");
m->add(fun(&Boxed_Number::unary_plus), "+");
m->add(fun(&Boxed_Number::unary_minus), "-");
m->add(fun(&Boxed_Number::difference), "-");
m->add(fun(&Boxed_Number::assign_bitwise_and), "&=");
m->add(fun(&Boxed_Number::assign), "=");
m->add(fun(&Boxed_Number::assign_bitwise_or), "|=");
m->add(fun(&Boxed_Number::assign_bitwise_xor), "^=");
m->add(fun(&Boxed_Number::assign_remainder), "%=");
m->add(fun(&Boxed_Number::assign_shift_left), "<<=");
m->add(fun(&Boxed_Number::assign_shift_right), ">>=");
m->add(fun(&Boxed_Number::bitwise_and), "&");
m->add(fun(&Boxed_Number::bitwise_complement), "~");
m->add(fun(&Boxed_Number::bitwise_xor), "^");
m->add(fun(&Boxed_Number::bitwise_or), "|");
m->add(fun(&Boxed_Number::assign_product), "*=");
m->add(fun(&Boxed_Number::assign_quotient), "/=");
m->add(fun(&Boxed_Number::assign_sum), "+=");
m->add(fun(&Boxed_Number::assign_difference), "-=");
m->add(fun(&Boxed_Number::quotient), "/");
m->add(fun(&Boxed_Number::shift_left), "<<");
m->add(fun(&Boxed_Number::product), "*");
m->add(fun(&Boxed_Number::remainder), "%");
m->add(fun(&Boxed_Number::shift_right), ">>");
m.add(fun(&Boxed_Number::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 /// Create a bound function object. The first param is the function to bind
/// the remaining parameters are the args to bind into the result /// the remaining parameters are the args to bind into the result
static Boxed_Value bind_function(const std::vector<Boxed_Value> &params) static Boxed_Value bind_function(const Function_Params &params) {
{
if (params.empty()) { if (params.empty()) {
throw exception::arity_error(0, 1); throw exception::arity_error(0, 1);
} }
Const_Proxy_Function f = boxed_cast<Const_Proxy_Function>(params[0]); Const_Proxy_Function f = boxed_cast<Const_Proxy_Function>(params[0]);
if (f->get_arity() != -1 && size_t(f->get_arity()) != params.size() - 1) 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()); 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), return Boxed_Value(Const_Proxy_Function(
std::vector<Boxed_Value>(params.begin() + 1, params.end())))); 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 {
static bool has_guard(const Const_Proxy_Function &t_pf)
{
auto pf = std::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(t_pf); auto pf = std::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(t_pf);
return pf && pf->get_guard(); return pf && pf->has_guard();
} }
static Const_Proxy_Function get_guard(const Const_Proxy_Function &t_pf) 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); const auto pf = std::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(t_pf);
if (pf && pf->get_guard()) if (pf && pf->get_guard()) {
{
return pf->get_guard(); return pf->get_guard();
} else { } else {
throw std::runtime_error("Function does not have a guard"); throw std::runtime_error("Function does not have a guard");
} }
} }
static void throw_exception(const Boxed_Value &bv) {
throw bv;
}
static std::string what(const std::exception &e)
{
return e.what();
}
/// Boolean specialization of internal to_string function
static std::string bool_to_string(bool b)
{
if (b)
{
return "true";
} else {
return "false";
}
}
template<typename FunctionType> template<typename FunctionType>
static std::vector<Boxed_Value> do_return_boxed_value_vector(FunctionType f, static std::vector<Boxed_Value> do_return_boxed_value_vector(FunctionType f, const dispatch::Proxy_Function_Base *b) {
const dispatch::Proxy_Function_Base *b)
{
auto v = (b->*f)(); auto v = (b->*f)();
std::vector<Boxed_Value> vbv; std::vector<Boxed_Value> vbv;
for (const auto &o: v) for (const auto &o : v) {
{
vbv.push_back(const_var(o)); vbv.push_back(const_var(o));
} }
return vbv; return vbv;
} }
static bool has_parse_tree(const chaiscript::Const_Proxy_Function &t_pf) noexcept {
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); const auto pf = std::dynamic_pointer_cast<const chaiscript::dispatch::Dynamic_Proxy_Function>(t_pf);
return pf && pf->get_parse_tree(); return bool(pf);
} }
static chaiscript::AST_NodePtr get_parse_tree(const chaiscript::Const_Proxy_Function &t_pf) 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); const auto pf = std::dynamic_pointer_cast<const chaiscript::dispatch::Dynamic_Proxy_Function>(t_pf);
if (pf && pf->get_parse_tree()) if (pf) {
{
return pf->get_parse_tree(); return pf->get_parse_tree();
} else { } else {
throw std::runtime_error("Function does not have a parse tree"); throw std::runtime_error("Function does not have a parse tree");
@ -392,120 +259,145 @@ namespace chaiscript
} }
template<typename Function> template<typename Function>
static std::function<std::vector<Boxed_Value> (const dispatch::Proxy_Function_Base*)> return_boxed_value_vector(const Function &f) static auto return_boxed_value_vector(const Function &f) {
{ return [f](const dispatch::Proxy_Function_Base *b) { return do_return_boxed_value_vector(f, b); };
return [f](const dispatch::Proxy_Function_Base *b) {
return do_return_boxed_value_vector(f, b);
};
} }
public: public:
/// \brief perform all common bootstrap functions for std::string, void and POD types /// \brief perform all common bootstrap functions for std::string, void and POD types
/// \param[in,out] m Module to add bootstrapped functions to /// \param[in,out] m Module to add bootstrapped functions to
/// \returns passed in ModulePtr, or newly created one if default argument is used /// \returns passed in Module
static ModulePtr bootstrap(ModulePtr m = std::make_shared<Module>()) static void bootstrap(Module &m) {
{ m.add(user_type<void>(), "void");
m->add(user_type<void>(), "void"); m.add(user_type<bool>(), "bool");
m->add(user_type<bool>(), "bool"); m.add(user_type<Boxed_Value>(), "Object");
m->add(user_type<Boxed_Value>(), "Object"); m.add(user_type<Boxed_Number>(), "Number");
m->add(user_type<Boxed_Number>(), "Number"); m.add(user_type<Proxy_Function>(), "Function");
m->add(user_type<Proxy_Function>(), "Function"); m.add(user_type<dispatch::Assignable_Proxy_Function>(), "Assignable_Function");
m->add(user_type<dispatch::Assignable_Proxy_Function>(), "Assignable_Function"); m.add(user_type<std::exception>(), "exception");
m->add(user_type<std::exception>(), "exception");
m->add(fun(&dispatch::Proxy_Function_Base::get_arity), "get_arity"); m.add(fun(&dispatch::Proxy_Function_Base::get_arity), "get_arity");
m->add(fun(&dispatch::Proxy_Function_Base::annotation), "get_annotation"); m.add(fun(&dispatch::Proxy_Function_Base::operator==), "==");
m->add(fun(&dispatch::Proxy_Function_Base::operator==), "==");
m.add(fun(return_boxed_value_vector(&dispatch::Proxy_Function_Base::get_param_types)), "get_param_types");
m.add(fun(return_boxed_value_vector(&dispatch::Proxy_Function_Base::get_contained_functions)), "get_contained_functions");
m->add(fun(return_boxed_value_vector(&dispatch::Proxy_Function_Base::get_param_types)), "get_param_types"); m.add(fun([](const std::exception &e) { return std::string(e.what()); }), "what");
m->add(fun(return_boxed_value_vector(&dispatch::Proxy_Function_Base::get_contained_functions)), "get_contained_functions");
m.add(user_type<std::out_of_range>(), "out_of_range");
m.add(user_type<std::logic_error>(), "logic_error");
m.add(chaiscript::base_class<std::exception, std::logic_error>());
m.add(chaiscript::base_class<std::logic_error, std::out_of_range>());
m.add(chaiscript::base_class<std::exception, std::out_of_range>());
m->add(user_type<std::out_of_range>(), "out_of_range"); m.add(user_type<std::runtime_error>(), "runtime_error");
m->add(user_type<std::logic_error>(), "logic_error"); m.add(chaiscript::base_class<std::exception, std::runtime_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(constructor<std::runtime_error(const std::string &)>(), "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(fun(std::function<std::string (const std::runtime_error &)>(&what)), "what"); 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(user_type<dispatch::Dynamic_Object>(), "Dynamic_Object"); m.add(fun(static_cast<Boxed_Value &(dispatch::Dynamic_Object::*)(const std::string &)>(&dispatch::Dynamic_Object::get_attr)), "get_attr");
m->add(constructor<dispatch::Dynamic_Object (const std::string &)>(), "Dynamic_Object"); m.add(fun(static_cast<const Boxed_Value &(dispatch::Dynamic_Object::*)(const std::string &) const>(&dispatch::Dynamic_Object::get_attr)),
m->add(constructor<dispatch::Dynamic_Object ()>(), "Dynamic_Object"); "get_attr");
m->add(fun(&dispatch::Dynamic_Object::get_type_name), "get_type_name");
m->add(fun(&dispatch::Dynamic_Object::get_attrs), "get_attrs");
m->add(fun(&dispatch::Dynamic_Object::set_explicit), "set_explicit");
m->add(fun(&dispatch::Dynamic_Object::is_explicit), "is_explicit");
m->add(fun(static_cast<Boxed_Value & (dispatch::Dynamic_Object::*)(const std::string &)>(&dispatch::Dynamic_Object::get_attr)), "get_attr"); m.add(fun(static_cast<Boxed_Value &(dispatch::Dynamic_Object::*)(const std::string &)>(&dispatch::Dynamic_Object::method_missing)),
m->add(fun(static_cast<const Boxed_Value & (dispatch::Dynamic_Object::*)(const std::string &) const>(&dispatch::Dynamic_Object::get_attr)), "get_attr"); "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::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::method_missing)), "method_missing"); m.add(fun(static_cast<const Boxed_Value &(dispatch::Dynamic_Object::*)(const std::string &) const>(&dispatch::Dynamic_Object::get_attr)),
"[]");
m->add(fun(static_cast<Boxed_Value & (dispatch::Dynamic_Object::*)(const std::string &)>(&dispatch::Dynamic_Object::get_attr)), "[]"); m.eval(R"chaiscript(
m->add(fun(static_cast<const Boxed_Value & (dispatch::Dynamic_Object::*)(const std::string &) const>(&dispatch::Dynamic_Object::get_attr)), "[]");
m->eval(R""(
def Dynamic_Object::clone() { def Dynamic_Object::clone() {
auto &new_o = Dynamic_Object(this.get_type_name()); 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; } ); for_each(this.get_attrs(), fun[new_o](x) { new_o.get_attr(x.first) = x.second; } );
new_o; new_o;
} }
)"");
m->add(fun(&has_guard), "has_guard"); def `=`(Dynamic_Object lhs, Dynamic_Object rhs) : lhs.get_type_name() == rhs.get_type_name()
m->add(fun(&get_guard), "get_guard"); {
for_each(rhs.get_attrs(), fun[lhs](x) { lhs.get_attr(x.first) = clone(x.second); } );
}
m->add(fun(&Boxed_Value::is_undef), "is_var_undef"); def `!=`(Dynamic_Object lhs, Dynamic_Object rhs) : lhs.get_type_name() == rhs.get_type_name()
m->add(fun(&Boxed_Value::is_null), "is_var_null"); {
m->add(fun(&Boxed_Value::is_const), "is_var_const"); var rhs_attrs := rhs.get_attrs();
m->add(fun(&Boxed_Value::is_ref), "is_var_reference"); var lhs_attrs := lhs.get_attrs();
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"); if (rhs_attrs.size() != lhs_attrs.size()) {
m->add(user_type<Type_Info>(), "Type_Info"); true;
m->add(constructor<Type_Info (const Type_Info &)>(), "Type_Info"); } else {
return any_of(rhs_attrs, fun[lhs](x) { !lhs.has_attr(x.first) || lhs.get_attr(x.first) != x.second; } );
}
}
def `==`(Dynamic_Object lhs, Dynamic_Object rhs) : lhs.get_type_name() == rhs.get_type_name()
{
var rhs_attrs := rhs.get_attrs();
var lhs_attrs := lhs.get_attrs();
if (rhs_attrs.size() != lhs_attrs.size()) {
false;
} else {
return all_of(rhs_attrs, fun[lhs](x) { lhs.has_attr(x.first) && lhs.get_attr(x.first) == x.second; } );
}
}
)chaiscript");
m.add(fun(&has_guard), "has_guard");
m.add(fun(&get_guard), "get_guard");
m.add(fun(&Boxed_Value::is_undef), "is_var_undef");
m.add(fun(&Boxed_Value::is_null), "is_var_null");
m.add(fun(&Boxed_Value::is_const), "is_var_const");
m.add(fun(&Boxed_Value::is_ref), "is_var_reference");
m.add(fun(&Boxed_Value::is_pointer), "is_var_pointer");
m.add(fun(&Boxed_Value::is_return_value), "is_var_return_value");
m.add(fun(&Boxed_Value::reset_return_value), "reset_var_return_value");
m.add(fun(&Boxed_Value::is_type), "is_type");
m.add(fun(&Boxed_Value::get_attr), "get_var_attr");
m.add(fun(&Boxed_Value::copy_attrs), "copy_var_attrs");
m.add(fun(&Boxed_Value::clone_attrs), "clone_var_attrs");
m.add(fun(&Boxed_Value::get_type_info), "get_type_info");
m.add(user_type<Type_Info>(), "Type_Info");
m.add(constructor<Type_Info(const Type_Info &)>(), "Type_Info");
operators::equal<Type_Info>(m); operators::equal<Type_Info>(m);
m->add(fun(&Type_Info::is_const), "is_type_const"); 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_reference), "is_type_reference");
m->add(fun(&Type_Info::is_void), "is_type_void"); 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_undef), "is_type_undef");
m->add(fun(&Type_Info::is_pointer), "is_type_pointer"); 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::is_arithmetic), "is_type_arithmetic");
m->add(fun(&Type_Info::name), "cpp_name"); m.add(fun(&Type_Info::name), "cpp_name");
m->add(fun(&Type_Info::bare_name), "cpp_bare_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::bare_equal), "bare_equal");
basic_constructors<bool>("bool", m); basic_constructors<bool>("bool", m);
operators::assign<bool>(m); operators::assign<bool>(m);
operators::equal<bool>(m); operators::equal<bool>(m);
operators::not_equal<bool>(m); operators::not_equal<bool>(m);
m->add(fun([](const std::string &s) -> std::string { return s; }), "to_string"); m.add(fun([](const std::string &s) { return s; }), "to_string");
m->add(fun(&Bootstrap::bool_to_string), "to_string"); m.add(fun([](const bool b) { return std::string(b ? "true" : "false"); }), "to_string");
m->add(fun(&unknown_assign), "="); m.add(fun(&unknown_assign), "=");
m->add(fun(&throw_exception), "throw"); m.add(fun([](const Boxed_Value &bv) { throw bv; }), "throw");
m->add(fun(&what), "what");
m->add(fun(&to_string<char>), "to_string"); 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(&Boxed_Number::to_string), "to_string");
bootstrap_pod_type<double>("double", m); bootstrap_pod_type<double>("double", m);
bootstrap_pod_type<long double>("long_double", m); bootstrap_pod_type<long double>("long_double", m);
@ -534,97 +426,86 @@ namespace chaiscript
opers_arithmetic_pod(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");
m->add(fun(&print), "print_string"); m.add(fun(&print), "print_string");
m->add(fun(&println), "println_string"); m.add(fun(&println), "println_string");
m->add(dispatch::make_dynamic_proxy_function(&bind_function), "bind"); m.add(dispatch::make_dynamic_proxy_function(&bind_function), "bind");
m->add(fun(&shared_ptr_unconst_clone<dispatch::Proxy_Function_Base>), "clone"); m.add(fun(&shared_ptr_unconst_clone<dispatch::Proxy_Function_Base>), "clone");
m->add(fun(&ptr_assign<std::remove_const<dispatch::Proxy_Function_Base>::type>), "="); m.add(fun(&ptr_assign<std::remove_const<dispatch::Proxy_Function_Base>::type>), "=");
m->add(fun(&ptr_assign<std::add_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(chaiscript::base_class<dispatch::Proxy_Function_Base, dispatch::Assignable_Proxy_Function>());
m->add(fun( m.add(fun([](dispatch::Assignable_Proxy_Function &t_lhs, const std::shared_ptr<const dispatch::Proxy_Function_Base> &t_rhs) {
[](dispatch::Assignable_Proxy_Function &t_lhs, const std::shared_ptr<const dispatch::Proxy_Function_Base> &t_rhs) {
t_lhs.assign(t_rhs); t_lhs.assign(t_rhs);
} }),
), "=" "=");
);
m->add(fun(&Boxed_Value::type_match), "type_match"); m.add(fun(&Boxed_Value::type_match), "type_match");
m.add(chaiscript::fun(&has_parse_tree), "has_parse_tree");
m.add(chaiscript::fun(&get_parse_tree), "get_parse_tree");
m->add(chaiscript::fun(&has_parse_tree), "has_parse_tree"); m.add(chaiscript::base_class<std::runtime_error, chaiscript::exception::eval_error>());
m->add(chaiscript::fun(&get_parse_tree), "get_parse_tree"); m.add(chaiscript::base_class<std::exception, chaiscript::exception::eval_error>());
m->add(chaiscript::base_class<std::runtime_error, chaiscript::exception::eval_error>()); m.add(chaiscript::user_type<chaiscript::exception::arithmetic_error>(), "arithmetic_error");
m.add(chaiscript::base_class<std::runtime_error, chaiscript::exception::arithmetic_error>());
m.add(chaiscript::base_class<std::exception, chaiscript::exception::arithmetic_error>());
m->add(chaiscript::user_type<chaiscript::exception::arithmetic_error>(), "arithmetic_error"); // chaiscript::bootstrap::standard_library::vector_type<std::vector<std::shared_ptr<chaiscript::AST_Node> >
m->add(chaiscript::base_class<std::runtime_error, chaiscript::exception::arithmetic_error>()); // >("AST_NodeVector", m);
chaiscript::utility::add_class<chaiscript::exception::eval_error>(m,
// 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", "eval_error",
{ }, {},
{ {fun(&chaiscript::exception::eval_error::reason), "reason"}, {{fun(&chaiscript::exception::eval_error::reason), "reason"},
{fun(&chaiscript::exception::eval_error::pretty_print), "pretty_print"}, {fun(&chaiscript::exception::eval_error::pretty_print), "pretty_print"},
{fun(std::function<std::vector<Boxed_Value> (const chaiscript::exception::eval_error &t_eval_error)>([](const chaiscript::exception::eval_error &t_eval_error) -> std::vector<Boxed_Value> { {fun([](const chaiscript::exception::eval_error &t_eval_error) {
std::vector<Boxed_Value> retval; std::vector<Boxed_Value> retval;
std::transform(t_eval_error.call_stack.begin(), t_eval_error.call_stack.end(), std::transform(t_eval_error.call_stack.begin(),
t_eval_error.call_stack.end(),
std::back_inserter(retval), std::back_inserter(retval),
&chaiscript::var<const std::shared_ptr<const chaiscript::AST_Node> &>); &chaiscript::var<const chaiscript::AST_Node_Trace &>);
return retval; return retval;
})), "call_stack"} } }),
); "call_stack"}});
chaiscript::utility::add_class<chaiscript::File_Position>(m,
chaiscript::utility::add_class<chaiscript::File_Position>(*m,
"File_Position", "File_Position",
{ constructor<File_Position()>(), {constructor<File_Position()>(), constructor<File_Position(int, int)>()},
constructor<File_Position(int, int)>() }, {{fun(&File_Position::line), "line"},
{ {fun(&File_Position::line), "line"}, {fun(&File_Position::column), "column"}});
{fun(&File_Position::column), "column"} }
);
chaiscript::utility::add_class<AST_Node>(m,
chaiscript::utility::add_class<AST_Node>(*m,
"AST_Node", "AST_Node",
{ }, {},
{ {fun(&AST_Node::text), "text"}, {{fun(&AST_Node::text), "text"},
{fun(&AST_Node::identifier), "identifier"}, {fun(&AST_Node::identifier), "identifier"},
{fun(&AST_Node::filename), "filename"}, {fun(&AST_Node::filename), "filename"},
{fun(&AST_Node::start), "start"}, {fun(&AST_Node::start), "start"},
{fun(&AST_Node::end), "end"}, {fun(&AST_Node::end), "end"},
{fun(&AST_Node::to_string), "to_string"}, {fun(&AST_Node::to_string), "to_string"},
{fun(std::function<std::vector<Boxed_Value> (const chaiscript::AST_Node &t_node)>([](const chaiscript::AST_Node &t_node) -> std::vector<Boxed_Value> { {fun([](const chaiscript::AST_Node &t_node) -> std::vector<Boxed_Value> {
std::vector<Boxed_Value> retval; std::vector<Boxed_Value> retval;
std::transform(t_node.children.begin(), t_node.children.end(), const auto children = t_node.get_children();
std::transform(children.begin(),
children.end(),
std::back_inserter(retval), std::back_inserter(retval),
&chaiscript::var<const std::shared_ptr<chaiscript::AST_Node> &>); &chaiscript::var<const std::reference_wrapper<chaiscript::AST_Node> &>);
return retval; return retval;
})), "children"}, }),
{fun(&AST_Node::replace_child), "replace_child"} "children"}});
}
);
chaiscript::utility::add_class<parser::ChaiScript_Parser>(*m,
"ChaiScript_Parser",
{ constructor<parser::ChaiScript_Parser ()>() },
{ {fun(&parser::ChaiScript_Parser::parse), "parse"},
{fun(&parser::ChaiScript_Parser::ast), "ast"} }
);
return m;
} }
}; };
} } // namespace chaiscript::bootstrap
}
#endif #endif

View File

@ -1,15 +1,17 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) // Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
/// \file /// \file
/// This file contains utility functions for registration of STL container /// This file contains utility functions for registration of STL container
/// classes. The methodology used is based on the SGI STL concepts. /// classes. The methodology used is based on the SGI STL concepts.
/// http://www.sgi.com/tech/stl/table_of_contents.html /// http://www.sgi.com/tech/stl/table_of_contents.html
#ifndef CHAISCRIPT_BOOTSTRAP_STL_HPP_ #ifndef CHAISCRIPT_BOOTSTRAP_STL_HPP_
#define CHAISCRIPT_BOOTSTRAP_STL_HPP_ #define CHAISCRIPT_BOOTSTRAP_STL_HPP_
@ -27,183 +29,94 @@
#include "register_function.hpp" #include "register_function.hpp"
#include "type_info.hpp" #include "type_info.hpp"
namespace chaiscript namespace chaiscript::bootstrap::standard_library {
{
namespace bootstrap
{
namespace standard_library
{
/// Bidir_Range, based on the D concept of ranges. /// Bidir_Range, based on the D concept of ranges.
/// \todo Update the Range code to base its capabilities on /// \todo Update the Range code to base its capabilities on
/// the user_typetraits of the iterator passed in /// the user_typetraits of the iterator passed in
template<typename Container> template<typename Container, typename IterType>
struct Bidir_Range struct Bidir_Range {
{ using container_type = Container;
typedef Container container_type;
typedef typename std::iterator_traits<typename Container::iterator>::reference reference_type;
Bidir_Range(Container &c) constexpr Bidir_Range(Container &c)
: m_begin(c.begin()), m_end(c.end()) : m_begin(c.begin())
{ , m_end(c.end()) {
} }
bool empty() const constexpr bool empty() const noexcept { return m_begin == m_end; }
{
return m_begin == m_end;
}
void pop_front() constexpr void pop_front() {
{ if (empty()) {
if (empty())
{
throw std::range_error("Range empty"); throw std::range_error("Range empty");
} }
++m_begin; ++m_begin;
} }
void pop_back() constexpr void pop_back() {
{ if (empty()) {
if (empty())
{
throw std::range_error("Range empty"); throw std::range_error("Range empty");
} }
--m_end; --m_end;
} }
reference_type front() const constexpr decltype(auto) front() const {
{ if (empty()) {
if (empty())
{
throw std::range_error("Range empty"); throw std::range_error("Range empty");
} }
return *m_begin; return (*m_begin);
} }
reference_type back() const constexpr decltype(auto) back() const {
{ if (empty()) {
if (empty())
{
throw std::range_error("Range empty"); throw std::range_error("Range empty");
} }
typename Container::iterator pos = m_end; auto pos = m_end;
--pos; --pos;
return *(pos); return (*(pos));
} }
typename Container::iterator m_begin; IterType m_begin;
typename Container::iterator m_end; IterType m_end;
};
template<typename Container>
struct Const_Bidir_Range
{
typedef const Container container_type;
typedef typename std::iterator_traits<typename Container::const_iterator>::reference const_reference_type;
Const_Bidir_Range(const Container &c)
: m_begin(c.begin()), m_end(c.end())
{
}
bool empty() const
{
return m_begin == m_end;
}
void pop_front()
{
if (empty())
{
throw std::range_error("Range empty");
}
++m_begin;
}
void pop_back()
{
if (empty())
{
throw std::range_error("Range empty");
}
--m_end;
}
const_reference_type front() const
{
if (empty())
{
throw std::range_error("Range empty");
}
return *m_begin;
}
const_reference_type back() const
{
if (empty())
{
throw std::range_error("Range empty");
}
typename Container::const_iterator pos = m_end;
--pos;
return *(pos);
}
typename Container::const_iterator m_begin;
typename Container::const_iterator m_end;
}; };
namespace detail { namespace detail {
template<typename T> template<typename T>
size_t count(const T &t_target, const typename T::key_type &t_key) size_t count(const T &t_target, const typename T::key_type &t_key) {
{
return t_target.count(t_key); return t_target.count(t_key);
} }
template<typename T> template<typename T>
void insert(T &t_target, const T &t_other) void insert(T &t_target, const T &t_other) {
{
t_target.insert(t_other.begin(), t_other.end()); t_target.insert(t_other.begin(), t_other.end());
} }
template<typename T> template<typename T>
void insert_ref(T &t_target, const typename T::value_type &t_val) void insert_ref(T &t_target, const typename T::value_type &t_val) {
{
t_target.insert(t_val); t_target.insert(t_val);
} }
/// Add Bidir_Range support for the given ContainerType /// Add Bidir_Range support for the given ContainerType
template<typename Bidir_Type> template<typename Bidir_Type>
ModulePtr input_range_type_impl(const std::string &type, ModulePtr m = std::make_shared<Module>()) void input_range_type_impl(const std::string &type, Module &m) {
{ m.add(user_type<Bidir_Type>(), type + "_Range");
m->add(user_type<Bidir_Type>(), type + "_Range");
copy_constructor<Bidir_Type>(type + "_Range", m); copy_constructor<Bidir_Type>(type + "_Range", m);
m->add(constructor<Bidir_Type (typename Bidir_Type::container_type &)>(), "range_internal"); m.add(constructor<Bidir_Type(typename Bidir_Type::container_type &)>(), "range_internal");
m->add(fun(&Bidir_Type::empty), "empty"); m.add(fun(&Bidir_Type::empty), "empty");
m->add(fun(&Bidir_Type::pop_front), "pop_front"); m.add(fun(&Bidir_Type::pop_front), "pop_front");
m->add(fun(&Bidir_Type::front), "front"); m.add(fun(&Bidir_Type::front), "front");
m->add(fun(&Bidir_Type::pop_back), "pop_back"); m.add(fun(&Bidir_Type::pop_back), "pop_back");
m->add(fun(&Bidir_Type::back), "back"); m.add(fun(&Bidir_Type::back), "back");
return m;
} }
/// Algorithm for inserting at a specific position into a container /// Algorithm for inserting at a specific position into a container
template<typename Type> template<typename Type>
void insert_at(Type &container, int pos, const typename Type::value_type &v) void insert_at(Type &container, int pos, const typename Type::value_type &v) {
{
auto itr = container.begin(); auto itr = container.begin();
auto end = container.end(); auto end = container.end();
if (pos < 0 || std::distance(itr, end) < pos) if (pos < 0 || std::distance(itr, end) < pos) {
{
throw std::range_error("Cannot insert past end of range"); throw std::range_error("Cannot insert past end of range");
} }
@ -211,98 +124,96 @@ namespace chaiscript
container.insert(itr, v); container.insert(itr, v);
} }
/// Algorithm for erasing a specific position from a container /// Algorithm for erasing a specific position from a container
template<typename Type> template<typename Type>
void erase_at(Type &container, int pos) void erase_at(Type &container, int pos) {
{
auto itr = container.begin(); auto itr = container.begin();
auto end = container.end(); auto end = container.end();
if (pos < 0 || std::distance(itr, end) < (pos-1)) if (pos < 0 || std::distance(itr, end) <= pos) {
{
throw std::range_error("Cannot erase past end of range"); throw std::range_error("Cannot erase past end of range");
} }
std::advance(itr, pos); std::advance(itr, pos);
container.erase(itr); container.erase(itr);
} }
} } // namespace detail
template<typename ContainerType> template<typename ContainerType>
ModulePtr input_range_type(const std::string &type, ModulePtr m = std::make_shared<Module>()) void input_range_type(const std::string &type, Module &m) {
{ detail::input_range_type_impl<Bidir_Range<ContainerType, typename ContainerType::iterator>>(type, m);
detail::input_range_type_impl<Bidir_Range<ContainerType> >(type,m); detail::input_range_type_impl<Bidir_Range<const ContainerType, typename ContainerType::const_iterator>>("Const_" + type, m);
detail::input_range_type_impl<Const_Bidir_Range<ContainerType> >("Const_" + type, m);
return m;
} }
/// Add random_access_container concept to the given ContainerType /// Add random_access_container concept to the given ContainerType
/// http://www.sgi.com/tech/stl/RandomAccessContainer.html /// http://www.sgi.com/tech/stl/RandomAccessContainer.html
template<typename ContainerType> template<typename ContainerType>
ModulePtr random_access_container_type(const std::string &/*type*/, ModulePtr m = std::make_shared<Module>()) void random_access_container_type(const std::string & /*type*/, Module &m) {
{ // In the interest of runtime safety for the m, we prefer the at() method for [] access,
//In the interest of runtime safety for the m, we prefer the at() method for [] access, // to throw an exception in an out of bounds condition.
//to throw an exception in an out of bounds condition. m.add(fun([](ContainerType &c, int index) -> typename ContainerType::reference {
m->add( /// \todo we are preferring to keep the key as 'int' to avoid runtime conversions
fun( /// during dispatch. reevaluate
[](ContainerType &c, int index) -> typename ContainerType::reference { return c.at(static_cast<typename ContainerType::size_type>(index));
return c.at(index); }),
}), "[]"); "[]");
m->add( m.add(fun([](const ContainerType &c, int index) -> typename ContainerType::const_reference {
fun( /// \todo we are preferring to keep the key as 'int' to avoid runtime conversions
[](const ContainerType &c, int index) -> typename ContainerType::const_reference { /// during dispatch. reevaluate
return c.at(index); return c.at(static_cast<typename ContainerType::size_type>(index));
}), "[]"); }),
"[]");
return m;
} }
/// Add assignable concept to the given ContainerType /// Add assignable concept to the given ContainerType
/// http://www.sgi.com/tech/stl/Assignable.html /// http://www.sgi.com/tech/stl/Assignable.html
template<typename ContainerType> template<typename ContainerType>
ModulePtr assignable_type(const std::string &type, ModulePtr m = std::make_shared<Module>()) void assignable_type(const std::string &type, Module &m) {
{
copy_constructor<ContainerType>(type, m); copy_constructor<ContainerType>(type, m);
operators::assign<ContainerType>(m); operators::assign<ContainerType>(m);
return m;
} }
/// Add container resize concept to the given ContainerType
/// http://www.cplusplus.com/reference/stl/
template<typename ContainerType>
void resizable_type(const std::string & /*type*/, Module &m) {
m.add(fun([](ContainerType *a, typename ContainerType::size_type n, const typename ContainerType::value_type &val) {
return a->resize(n, val);
}),
"resize");
m.add(fun([](ContainerType *a, typename ContainerType::size_type n) { return a->resize(n); }), "resize");
}
/// Add container reserve concept to the given ContainerType
/// http://www.cplusplus.com/reference/stl/
template<typename ContainerType>
void reservable_type(const std::string & /*type*/, Module &m) {
m.add(fun([](ContainerType *a, typename ContainerType::size_type n) { return a->reserve(n); }), "reserve");
m.add(fun([](const ContainerType *a) { return a->capacity(); }), "capacity");
}
/// Add container concept to the given ContainerType /// Add container concept to the given ContainerType
/// http://www.sgi.com/tech/stl/Container.html /// http://www.sgi.com/tech/stl/Container.html
template<typename ContainerType> template<typename ContainerType>
ModulePtr container_type(const std::string &/*type*/, ModulePtr m = std::make_shared<Module>()) void container_type(const std::string & /*type*/, Module &m) {
{ m.add(fun([](const ContainerType *a) { return a->size(); }), "size");
m->add(fun([](const ContainerType *a) { return a->size(); } ), "size"); m.add(fun([](const ContainerType *a) { return a->empty(); }), "empty");
m->add(fun([](const ContainerType *a) { return a->empty(); } ), "empty"); m.add(fun([](ContainerType *a) { a->clear(); }), "clear");
m->add(fun([](ContainerType *a) { a->clear(); } ), "clear");
return m;
} }
/// Add default constructable concept to the given Type /// Add default constructable concept to the given Type
/// http://www.sgi.com/tech/stl/DefaultConstructible.html /// http://www.sgi.com/tech/stl/DefaultConstructible.html
template<typename Type> template<typename Type>
ModulePtr default_constructible_type(const std::string &type, ModulePtr m = std::make_shared<Module>()) void default_constructible_type(const std::string &type, Module &m) {
{ m.add(constructor<Type()>(), type);
m->add(constructor<Type ()>(), type);
return m;
} }
/// Add sequence concept to the given ContainerType /// Add sequence concept to the given ContainerType
/// http://www.sgi.com/tech/stl/Sequence.html /// http://www.sgi.com/tech/stl/Sequence.html
template<typename ContainerType> template<typename ContainerType>
ModulePtr sequence_type(const std::string &/*type*/, ModulePtr m = std::make_shared<Module>()) void sequence_type(const std::string & /*type*/, Module &m) {
{ m.add(fun(&detail::insert_at<ContainerType>), []() -> std::string {
m->add(fun(&detail::insert_at<ContainerType>),
[]()->std::string{
if (typeid(typename ContainerType::value_type) == typeid(Boxed_Value)) { if (typeid(typename ContainerType::value_type) == typeid(Boxed_Value)) {
return "insert_ref_at"; return "insert_ref_at";
} else { } else {
@ -310,29 +221,37 @@ namespace chaiscript
} }
}()); }());
m->add(fun(&detail::erase_at<ContainerType>), "erase_at"); m.add(fun(&detail::erase_at<ContainerType>), "erase_at");
return m;
} }
/// Add back insertion sequence concept to the given ContainerType /// Add back insertion sequence concept to the given ContainerType
/// http://www.sgi.com/tech/stl/BackInsertionSequence.html /// http://www.sgi.com/tech/stl/BackInsertionSequence.html
template<typename ContainerType> template<typename ContainerType>
ModulePtr back_insertion_sequence_type(const std::string &type, ModulePtr m = std::make_shared<Module>()) void back_insertion_sequence_type(const std::string &type, Module &m) {
{ m.add(fun([](ContainerType &container) -> decltype(auto) {
typedef typename ContainerType::reference (ContainerType::*backptr)(); if (container.empty()) {
throw std::range_error("Container empty");
} else {
return (container.back());
}
}),
"back");
m.add(fun([](const ContainerType &container) -> decltype(auto) {
if (container.empty()) {
throw std::range_error("Container empty");
} else {
return (container.back());
}
}),
"back");
m->add(fun(static_cast<backptr>(&ContainerType::back)), "back"); using push_back = void (ContainerType::*)(const typename ContainerType::value_type &);
m.add(fun(static_cast<push_back>(&ContainerType::push_back)), [&]() -> std::string {
typedef void (ContainerType::*push_back)(const typename ContainerType::value_type &);
m->add(fun(static_cast<push_back>(&ContainerType::push_back)),
[&]()->std::string{
if (typeid(typename ContainerType::value_type) == typeid(Boxed_Value)) { if (typeid(typename ContainerType::value_type) == typeid(Boxed_Value)) {
m->eval( m.eval("# Pushes the second value onto the container while making a clone of the value\n"
"# Pushes the second value onto the container while making a clone of the value\n" "def push_back("
"def push_back(" + type + " container, x)\n" + type
+ " container, x)\n"
"{ \n" "{ \n"
" if (x.is_var_return_value()) {\n" " if (x.is_var_return_value()) {\n"
" x.reset_var_return_value() \n" " x.reset_var_return_value() \n"
@ -340,8 +259,7 @@ namespace chaiscript
" } else { \n" " } else { \n"
" container.push_back_ref(clone(x)); \n" " container.push_back_ref(clone(x)); \n"
" }\n" " }\n"
"} \n" "} \n");
);
return "push_back_ref"; return "push_back_ref";
} else { } else {
@ -349,31 +267,40 @@ namespace chaiscript
} }
}()); }());
m->add(fun(&ContainerType::pop_back), "pop_back"); m.add(fun(&ContainerType::pop_back), "pop_back");
return m;
} }
/// Front insertion sequence /// Front insertion sequence
/// http://www.sgi.com/tech/stl/FrontInsertionSequence.html /// http://www.sgi.com/tech/stl/FrontInsertionSequence.html
template<typename ContainerType> template<typename ContainerType>
ModulePtr front_insertion_sequence_type(const std::string &type, ModulePtr m = std::make_shared<Module>()) void front_insertion_sequence_type(const std::string &type, Module &m) {
{ using push_ptr = void (ContainerType::*)(typename ContainerType::const_reference);
typedef typename ContainerType::reference (ContainerType::*front_ptr)(); using pop_ptr = void (ContainerType::*)();
typedef typename ContainerType::const_reference (ContainerType::*const_front_ptr)() const;
typedef void (ContainerType::*push_ptr)(typename ContainerType::const_reference);
typedef void (ContainerType::*pop_ptr)();
m->add(fun(static_cast<front_ptr>(&ContainerType::front)), "front"); m.add(fun([](ContainerType &container) -> decltype(auto) {
m->add(fun(static_cast<const_front_ptr>(&ContainerType::front)), "front"); if (container.empty()) {
throw std::range_error("Container empty");
} else {
return (container.front());
}
}),
"front");
m->add(fun(static_cast<push_ptr>(&ContainerType::push_front)), m.add(fun([](const ContainerType &container) -> decltype(auto) {
[&]()->std::string{ if (container.empty()) {
throw std::range_error("Container empty");
} else {
return (container.front());
}
}),
"front");
m.add(fun(static_cast<push_ptr>(&ContainerType::push_front)), [&]() -> std::string {
if (typeid(typename ContainerType::value_type) == typeid(Boxed_Value)) { if (typeid(typename ContainerType::value_type) == typeid(Boxed_Value)) {
m->eval( m.eval("# Pushes the second value onto the front of container while making a clone of the value\n"
"# Pushes the second value onto the front of container while making a clone of the value\n" "def push_front("
"def push_front(" + type + " container, x)\n" + type
+ " container, x)\n"
"{ \n" "{ \n"
" if (x.is_var_return_value()) {\n" " if (x.is_var_return_value()) {\n"
" x.reset_var_return_value() \n" " x.reset_var_return_value() \n"
@ -381,98 +308,74 @@ namespace chaiscript
" } else { \n" " } else { \n"
" container.push_front_ref(clone(x)); \n" " container.push_front_ref(clone(x)); \n"
" }\n" " }\n"
"} \n" "} \n");
);
return "push_front_ref"; return "push_front_ref";
} else { } else {
return "push_front"; return "push_front";
} }
}()); }());
m->add(fun(static_cast<pop_ptr>(&ContainerType::pop_front)), "pop_front"); m.add(fun(static_cast<pop_ptr>(&ContainerType::pop_front)), "pop_front");
return m;
} }
/// bootstrap a given PairType /// bootstrap a given PairType
/// http://www.sgi.com/tech/stl/pair.html /// http://www.sgi.com/tech/stl/pair.html
template<typename PairType> template<typename PairType>
ModulePtr pair_type(const std::string &type, ModulePtr m = std::make_shared<Module>()) void pair_type(const std::string &type, Module &m) {
{ m.add(user_type<PairType>(), type);
m->add(user_type<PairType>(), type);
m.add(fun(&PairType::first), "first");
typename PairType::first_type PairType::* f = &PairType::first; m.add(fun(&PairType::second), "second");
typename PairType::second_type PairType::* s = &PairType::second;
m->add(fun(f), "first");
m->add(fun(s), "second");
basic_constructors<PairType>(type, m); basic_constructors<PairType>(type, m);
m->add(constructor<PairType (const typename PairType::first_type &, const typename PairType::second_type &)>(), type); m.add(constructor<PairType(const typename PairType::first_type &, const typename PairType::second_type &)>(), type);
return m;
} }
/// Add pair associative container concept to the given ContainerType /// Add pair associative container concept to the given ContainerType
/// http://www.sgi.com/tech/stl/PairAssociativeContainer.html /// http://www.sgi.com/tech/stl/PairAssociativeContainer.html
template<typename ContainerType> template<typename ContainerType>
ModulePtr pair_associative_container_type(const std::string &type, ModulePtr m = std::make_shared<Module>()) void pair_associative_container_type(const std::string &type, Module &m) {
{
pair_type<typename ContainerType::value_type>(type + "_Pair", m); pair_type<typename ContainerType::value_type>(type + "_Pair", m);
return m;
} }
/// Add unique associative container concept to the given ContainerType /// Add unique associative container concept to the given ContainerType
/// http://www.sgi.com/tech/stl/UniqueAssociativeContainer.html /// http://www.sgi.com/tech/stl/UniqueAssociativeContainer.html
template<typename ContainerType> template<typename ContainerType>
ModulePtr unique_associative_container_type(const std::string &/*type*/, ModulePtr m = std::make_shared<Module>()) void unique_associative_container_type(const std::string & /*type*/, Module &m) {
{ m.add(fun(detail::count<ContainerType>), "count");
m->add(fun(detail::count<ContainerType>), "count");
typedef size_t (ContainerType::*erase_ptr)(const typename ContainerType::key_type &); using erase_ptr = size_t (ContainerType::*)(const typename ContainerType::key_type &);
m->add(fun(static_cast<erase_ptr>(&ContainerType::erase)), "erase"); m.add(fun(static_cast<erase_ptr>(&ContainerType::erase)), "erase");
m->add(fun(&detail::insert<ContainerType>), "insert"); m.add(fun(&detail::insert<ContainerType>), "insert");
m->add(fun(&detail::insert_ref<ContainerType>), m.add(fun(&detail::insert_ref<ContainerType>), []() -> std::string {
[]()->std::string{
if (typeid(typename ContainerType::mapped_type) == typeid(Boxed_Value)) { if (typeid(typename ContainerType::mapped_type) == typeid(Boxed_Value)) {
return "insert_ref"; return "insert_ref";
} else { } else {
return "insert"; return "insert";
} }
}()); }());
return m;
} }
/// Add a MapType container /// Add a MapType container
/// http://www.sgi.com/tech/stl/Map.html /// http://www.sgi.com/tech/stl/Map.html
template<typename MapType> template<typename MapType>
ModulePtr map_type(const std::string &type, ModulePtr m = std::make_shared<Module>()) void map_type(const std::string &type, Module &m) {
{ m.add(user_type<MapType>(), type);
m->add(user_type<MapType>(), type);
typedef typename MapType::mapped_type &(MapType::*elem_access)(const typename MapType::key_type &); using elem_access = typename MapType::mapped_type &(MapType::*)(const typename MapType::key_type &);
typedef const typename MapType::mapped_type &(MapType::*const_elem_access)(const typename MapType::key_type &) const; using const_elem_access = const typename MapType::mapped_type &(MapType::*)(const typename MapType::key_type &) const;
m->add(fun(static_cast<elem_access>(&MapType::operator[])), "[]"); m.add(fun(static_cast<elem_access>(&MapType::operator[])), "[]");
m->add(fun(static_cast<elem_access>(&MapType::at)), "at"); m.add(fun(static_cast<elem_access>(&MapType::at)), "at");
m->add(fun(static_cast<const_elem_access>(&MapType::at)), "at"); m.add(fun(static_cast<const_elem_access>(&MapType::at)), "at");
if (typeid(MapType) == typeid(std::map<std::string, Boxed_Value>)) if (typeid(MapType) == typeid(std::map<std::string, Boxed_Value>)) {
{ m.eval(R"(
m->eval(R"(
def Map::`==`(Map rhs) { def Map::`==`(Map rhs) {
if ( rhs.size() != this.size() ) { if ( rhs.size() != this.size() ) {
return false; return false;
@ -490,8 +393,7 @@ namespace chaiscript
} }
true; true;
} }
} )" } )");
);
} }
container_type<MapType>(type, m); container_type<MapType>(type, m);
@ -500,55 +402,59 @@ namespace chaiscript
unique_associative_container_type<MapType>(type, m); unique_associative_container_type<MapType>(type, m);
pair_associative_container_type<MapType>(type, m); pair_associative_container_type<MapType>(type, m);
input_range_type<MapType>(type, m); input_range_type<MapType>(type, m);
return m;
} }
/// hopefully working List type
/// http://www.sgi.com/tech/stl/List.html /// http://www.sgi.com/tech/stl/List.html
template<typename ListType> template<typename ListType>
ModulePtr list_type(const std::string &type, ModulePtr m = std::make_shared<Module>()) void list_type(const std::string &type, Module &m) {
{ m.add(user_type<ListType>(), type);
m->add(user_type<ListType>(), type);
front_insertion_sequence_type<ListType>(type, m); front_insertion_sequence_type<ListType>(type, m);
back_insertion_sequence_type<ListType>(type, m); back_insertion_sequence_type<ListType>(type, m);
sequence_type<ListType>(type, m); sequence_type<ListType>(type, m);
resizable_type<ListType>(type, m);
container_type<ListType>(type, m); container_type<ListType>(type, m);
default_constructible_type<ListType>(type, m); default_constructible_type<ListType>(type, m);
assignable_type<ListType>(type, m); assignable_type<ListType>(type, m);
input_range_type<ListType>(type, m); input_range_type<ListType>(type, m);
return m;
} }
/// Create a vector type with associated concepts /// Create a vector type with associated concepts
/// http://www.sgi.com/tech/stl/Vector.html /// http://www.sgi.com/tech/stl/Vector.html
template<typename VectorType> template<typename VectorType>
ModulePtr vector_type(const std::string &type, ModulePtr m = std::make_shared<Module>()) void vector_type(const std::string &type, Module &m) {
{ m.add(user_type<VectorType>(), type);
m->add(user_type<VectorType>(), type);
typedef typename VectorType::reference (VectorType::*frontptr)(); m.add(fun([](VectorType &container) -> decltype(auto) {
typedef typename VectorType::const_reference (VectorType::*constfrontptr)() const; if (container.empty()) {
throw std::range_error("Container empty");
m->add(fun(static_cast<frontptr>(&VectorType::front)), "front"); } else {
m->add(fun(static_cast<constfrontptr>(&VectorType::front)), "front"); return (container.front());
}
}),
"front");
m.add(fun([](const VectorType &container) -> decltype(auto) {
if (container.empty()) {
throw std::range_error("Container empty");
} else {
return (container.front());
}
}),
"front");
back_insertion_sequence_type<VectorType>(type, m); back_insertion_sequence_type<VectorType>(type, m);
sequence_type<VectorType>(type, m); sequence_type<VectorType>(type, m);
random_access_container_type<VectorType>(type, m); random_access_container_type<VectorType>(type, m);
resizable_type<VectorType>(type, m);
reservable_type<VectorType>(type, m);
container_type<VectorType>(type, m); container_type<VectorType>(type, m);
default_constructible_type<VectorType>(type, m); default_constructible_type<VectorType>(type, m);
assignable_type<VectorType>(type, m); assignable_type<VectorType>(type, m);
input_range_type<VectorType>(type, m); input_range_type<VectorType>(type, m);
if (typeid(VectorType) == typeid(std::vector<Boxed_Value>)) if (typeid(VectorType) == typeid(std::vector<Boxed_Value>)) {
{ m.eval(R"(
m->eval(R"(
def Vector::`==`(Vector rhs) { def Vector::`==`(Vector rhs) {
if ( rhs.size() != this.size() ) { if ( rhs.size() != this.size() ) {
return false; return false;
@ -566,19 +472,15 @@ namespace chaiscript
} }
true; true;
} }
} )" } )");
);
} }
return m;
} }
/// Add a String container /// Add a String container
/// http://www.sgi.com/tech/stl/basic_string.html /// http://www.sgi.com/tech/stl/basic_string.html
template<typename String> template<typename String>
ModulePtr string_type(const std::string &type, ModulePtr m = std::make_shared<Module>()) void string_type(const std::string &type, Module &m) {
{ m.add(user_type<String>(), type);
m->add(user_type<String>(), type);
operators::addition<String>(m); operators::addition<String>(m);
operators::assign_sum<String>(m); operators::assign_sum<String>(m);
opers_comparison<String>(m); opers_comparison<String>(m);
@ -589,9 +491,8 @@ namespace chaiscript
assignable_type<String>(type, m); assignable_type<String>(type, m);
input_range_type<String>(type, m); input_range_type<String>(type, m);
//Special case: add push_back to string (which doesn't support other back_insertion operations // Special case: add push_back to string (which doesn't support other back_insertion operations
m->add(fun(&String::push_back), m.add(fun(&String::push_back), []() -> std::string {
[]()->std::string{
if (typeid(typename String::value_type) == typeid(Boxed_Value)) { if (typeid(typename String::value_type) == typeid(Boxed_Value)) {
return "push_back_ref"; return "push_back_ref";
} else { } else {
@ -599,45 +500,34 @@ namespace chaiscript
} }
}()); }());
m.add(fun([](const String *s, const String &f, size_t pos) { return s->find(f, pos); }), "find");
m.add(fun([](const String *s, const String &f, size_t pos) { return s->rfind(f, pos); }), "rfind");
m.add(fun([](const String *s, const String &f, size_t pos) { return s->find_first_of(f, pos); }), "find_first_of");
m.add(fun([](const String *s, const String &f, size_t pos) { return s->find_last_of(f, pos); }), "find_last_of");
m.add(fun([](const String *s, const String &f, size_t pos) { return s->find_last_not_of(f, pos); }), "find_last_not_of");
m.add(fun([](const String *s, const String &f, size_t pos) { return s->find_first_not_of(f, pos); }), "find_first_not_of");
m->add(fun([](const String *s, const String &f, size_t pos) { return s->find(f, pos); } ), "find"); m.add(fun([](String *s, typename String::value_type c) -> decltype(auto) { return (*s += c); }), "+=");
m->add(fun([](const String *s, const String &f, size_t pos) { return s->rfind(f, pos); } ), "rfind");
m->add(fun([](const String *s, const String &f, size_t pos) { return s->find_first_of(f, pos); } ), "find_first_of");
m->add(fun([](const String *s, const String &f, size_t pos) { return s->find_last_of(f, pos); } ), "find_last_of");
m->add(fun([](const String *s, const String &f, size_t pos) { return s->find_last_not_of(f, pos); } ), "find_last_not_of");
m->add(fun([](const String *s, const String &f, size_t pos) { return s->find_first_not_of(f, pos); } ), "find_first_not_of");
m->add(fun([](String *s) { s->clear(); } ), "clear"); m.add(fun([](String *s) { s->clear(); }), "clear");
m->add(fun([](const String *s) { return s->empty(); } ), "empty"); m.add(fun([](const String *s) { return s->empty(); }), "empty");
m->add(fun([](const String *s) { return s->size(); } ), "size"); m.add(fun([](const String *s) { return s->size(); }), "size");
m->add(fun([](const String *s) { return s->c_str(); } ), "c_str"); m.add(fun([](const String *s) { return s->c_str(); }), "c_str");
m->add(fun([](const String *s) { return s->data(); } ), "data"); m.add(fun([](const String *s) { return s->data(); }), "data");
m->add(fun([](const String *s, size_t pos, size_t len) { return s->substr(pos, len); } ), "substr"); m.add(fun([](const String *s, size_t pos, size_t len) { return s->substr(pos, len); }), "substr");
return m;
} }
/// Add a MapType container /// Add a MapType container
/// http://www.sgi.com/tech/stl/Map.html /// http://www.sgi.com/tech/stl/Map.html
template<typename FutureType> template<typename FutureType>
ModulePtr future_type(const std::string &type, ModulePtr m = std::make_shared<Module>()) void future_type(const std::string &type, Module &m) {
{ m.add(user_type<FutureType>(), type);
m->add(user_type<FutureType>(), type);
m->add(fun([](const FutureType &t) { return t.valid(); }), "valid"); m.add(fun([](const FutureType &t) { return t.valid(); }), "valid");
m->add(fun(&FutureType::get), "get"); m.add(fun([](FutureType &t) { return t.get(); }), "get");
m->add(fun(&FutureType::wait), "wait"); m.add(fun(&FutureType::wait), "wait");
return m;
} }
} } // namespace chaiscript::bootstrap::standard_library
}
}
#endif #endif

View File

@ -1,9 +1,12 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) // Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.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_ #ifndef CHAISCRIPT_BOXED_CAST_HPP_
#define CHAISCRIPT_BOXED_CAST_HPP_ #define CHAISCRIPT_BOXED_CAST_HPP_
@ -15,17 +18,13 @@
#include "type_info.hpp" #include "type_info.hpp"
namespace chaiscript { namespace chaiscript {
class Type_Conversions; class Type_Conversions;
namespace detail { }
namespace exception { namespace chaiscript::detail::exception {
class bad_any_cast; class bad_any_cast;
} // namespace exception } // namespace chaiscript::detail::exception
} // namespace detail
} // namespace chaiscript
namespace chaiscript
{
namespace chaiscript {
/// \brief Function for extracting a value stored in a Boxed_Value object /// \brief Function for extracting a value stored in a Boxed_Value object
/// \tparam Type The type to extract from the Boxed_Value /// \tparam Type The type to extract from the Boxed_Value
/// \param[in] bv The Boxed_Value to extract a typed value from /// \param[in] bv The Boxed_Value to extract a typed value from
@ -69,43 +68,35 @@ namespace chaiscript
/// assert(i == 5); /// assert(i == 5);
/// \endcode /// \endcode
template<typename Type> template<typename Type>
typename detail::Cast_Helper<Type>::Result_Type boxed_cast(const Boxed_Value &bv, const Type_Conversions *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>())) {
if (!t_conversions || bv.get_type_info().bare_equal(user_type<Type>()) || (t_conversions && !t_conversions->convertable_type<Type>())) {
try { 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 &) { } 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 { try {
// std::cout << "trying an up conversion " << typeid(Type).name() << '\n';
// We will not catch any bad_boxed_dynamic_cast that is thrown, let the user get it // We will not catch any bad_boxed_dynamic_cast that is thrown, let the user get it
// either way, we are not responsible if it doesn't work // either way, we are not responsible if it doesn't work
return detail::Cast_Helper<Type>::cast(t_conversions->boxed_type_conversion<Type>(bv), t_conversions); return (detail::Cast_Helper<Type>::cast((*t_conversions)->boxed_type_conversion<Type>(t_conversions->saves(), bv), t_conversions));
} catch (...) { } catch (...) {
try { try {
// std::cout << "trying a down conversion " << typeid(Type).name() << '\n'; // try going the other way
// try going the other way - down the inheritance graph return (detail::Cast_Helper<Type>::cast((*t_conversions)->boxed_type_down_conversion<Type>(t_conversions->saves(), bv),
return detail::Cast_Helper<Type>::cast(t_conversions->boxed_type_down_conversion<Type>(bv), t_conversions); t_conversions));
} catch (const chaiscript::detail::exception::bad_any_cast &) { } catch (const chaiscript::detail::exception::bad_any_cast &) {
throw exception::bad_boxed_cast(bv.get_type_info(), typeid(Type)); throw exception::bad_boxed_cast(bv.get_type_info(), typeid(Type));
} }
} }
} else { } else {
// If it's not polymorphic, just throw the error, don't waste the time on the // If it's not convertable, just throw the error, don't waste the time on the
// attempted dynamic_cast // attempted dynamic_cast
throw exception::bad_boxed_cast(bv.get_type_info(), typeid(Type)); throw exception::bad_boxed_cast(bv.get_type_info(), typeid(Type));
} }
} }
} } // namespace chaiscript
#endif #endif

View File

@ -1,9 +1,12 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) // Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.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_ #ifndef CHAISCRIPT_BOXED_CAST_HELPER_HPP_
#define CHAISCRIPT_BOXED_CAST_HELPER_HPP_ #define CHAISCRIPT_BOXED_CAST_HELPER_HPP_
@ -13,236 +16,245 @@
#include "boxed_value.hpp" #include "boxed_value.hpp"
#include "type_info.hpp" #include "type_info.hpp"
namespace chaiscript {
class Type_Conversions_State;
namespace chaiscript namespace detail {
{
class Type_Conversions;
namespace detail
{
// Cast_Helper_Inner helper classes // Cast_Helper_Inner helper classes
template<typename T> template<typename T>
T* throw_if_null(T *t) constexpr T *throw_if_null(T *t) {
{ if (t) {
if (t) return t; return t;
}
throw std::runtime_error("Attempted to dereference null Boxed_Value"); throw std::runtime_error("Attempted to dereference null Boxed_Value");
} }
template<typename T>
static const T *verify_type_no_throw(const Boxed_Value &ob, const std::type_info &ti, const T *ptr) {
if (ob.get_type_info() == ti) {
return ptr;
} else {
throw chaiscript::detail::exception::bad_any_cast();
}
}
template<typename T>
static T *verify_type_no_throw(const Boxed_Value &ob, const std::type_info &ti, T *ptr) {
if (!ob.is_const() && ob.get_type_info() == ti) {
return ptr;
} else {
throw chaiscript::detail::exception::bad_any_cast();
}
}
template<typename T>
static const T *verify_type(const Boxed_Value &ob, const std::type_info &ti, const T *ptr) {
if (ob.get_type_info().bare_equal_type_info(ti)) {
return throw_if_null(ptr);
} else {
throw chaiscript::detail::exception::bad_any_cast();
}
}
template<typename T>
static T *verify_type(const Boxed_Value &ob, const std::type_info &ti, T *ptr) {
if (!ob.is_const() && ob.get_type_info().bare_equal_type_info(ti)) {
return throw_if_null(ptr);
} else {
throw chaiscript::detail::exception::bad_any_cast();
}
}
/// Generic Cast_Helper_Inner, for casting to any type /// Generic Cast_Helper_Inner, for casting to any type
template<typename Result> template<typename Result>
struct Cast_Helper_Inner struct Cast_Helper_Inner {
{ static Result cast(const Boxed_Value &ob, const Type_Conversions_State *) {
typedef std::reference_wrapper<typename std::add_const<Result>::type > Result_Type; return *static_cast<const Result *>(verify_type(ob, typeid(Result), ob.get_const_ptr()));
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *)
{
if (ob.get_type_info().bare_equal_type_info(typeid(Result)))
{
auto p = throw_if_null(ob.get_const_ptr());
return std::cref(*static_cast<const Result *>(p));
} else {
throw chaiscript::detail::exception::bad_any_cast();
}
} }
}; };
template<typename Result> template<typename Result>
struct Cast_Helper_Inner<const Result> : Cast_Helper_Inner<Result> struct Cast_Helper_Inner<const Result> : Cast_Helper_Inner<Result> {
{
}; };
/// Cast_Helper_Inner for casting to a const & type
template<typename Result>
struct Cast_Helper_Inner<const Result &> : Cast_Helper_Inner<Result>
{
};
/// Cast_Helper_Inner for casting to a const * type /// Cast_Helper_Inner for casting to a const * type
template<typename Result> template<typename Result>
struct Cast_Helper_Inner<const Result *> struct Cast_Helper_Inner<const Result *> {
{ static const Result *cast(const Boxed_Value &ob, const Type_Conversions_State *) {
typedef const Result * Result_Type; return static_cast<const Result *>(verify_type_no_throw(ob, typeid(Result), ob.get_const_ptr()));
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *)
{
if (ob.get_type_info().bare_equal_type_info(typeid(Result)))
{
return static_cast<const Result *>(throw_if_null(ob.get_const_ptr()));
} else {
throw chaiscript::detail::exception::bad_any_cast();
}
} }
}; };
/// Cast_Helper_Inner for casting to a * type /// Cast_Helper_Inner for casting to a * type
template<typename Result> template<typename Result>
struct Cast_Helper_Inner<Result *> struct Cast_Helper_Inner<Result *> {
{ static Result *cast(const Boxed_Value &ob, const Type_Conversions_State *) {
typedef Result * Result_Type; return static_cast<Result *>(verify_type_no_throw(ob, typeid(Result), ob.get_ptr()));
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *)
{
if (!ob.get_type_info().is_const() && ob.get_type_info() == typeid(Result))
{
return static_cast<Result *>(throw_if_null(ob.get_ptr()));
} else {
throw chaiscript::detail::exception::bad_any_cast();
}
} }
}; };
template<typename Result>
struct Cast_Helper_Inner<Result *const &> : public Cast_Helper_Inner<Result *> {
};
template<typename Result>
struct Cast_Helper_Inner<const Result *const &> : public Cast_Helper_Inner<const Result *> {
};
/// Cast_Helper_Inner for casting to a & type /// Cast_Helper_Inner for casting to a & type
template<typename Result> template<typename Result>
struct Cast_Helper_Inner<Result &> struct Cast_Helper_Inner<const Result &> {
{ static const Result &cast(const Boxed_Value &ob, const Type_Conversions_State *) {
typedef Result& Result_Type; return *static_cast<const Result *>(verify_type(ob, typeid(Result), ob.get_const_ptr()));
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *)
{
if (!ob.get_type_info().is_const() && ob.get_type_info().bare_equal_type_info(typeid(Result)))
{
return *(static_cast<Result *>(throw_if_null(ob.get_ptr())));
} else {
throw chaiscript::detail::exception::bad_any_cast();
} }
};
/// 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()));
}
};
/// Cast_Helper_Inner for casting to a && type
template<typename Result>
struct Cast_Helper_Inner<Result &&> {
static Result &&cast(const Boxed_Value &ob, const Type_Conversions_State *) {
return std::move(*static_cast<Result *>(verify_type(ob, typeid(Result), ob.get_ptr())));
}
};
/// Cast_Helper_Inner for casting to a std::unique_ptr<> && type
/// \todo Fix the fact that this has to be in a shared_ptr for now
template<typename Result>
struct Cast_Helper_Inner<std::unique_ptr<Result> &&> {
static std::unique_ptr<Result> &&cast(const Boxed_Value &ob, const Type_Conversions_State *) {
return std::move(*(ob.get().cast<std::shared_ptr<std::unique_ptr<Result>>>()));
}
};
/// Cast_Helper_Inner for casting to a std::unique_ptr<> & type
/// \todo Fix the fact that this has to be in a shared_ptr for now
template<typename Result>
struct Cast_Helper_Inner<std::unique_ptr<Result> &> {
static std::unique_ptr<Result> &cast(const Boxed_Value &ob, const Type_Conversions_State *) {
return *(ob.get().cast<std::shared_ptr<std::unique_ptr<Result>>>());
}
};
/// Cast_Helper_Inner for casting to a std::unique_ptr<> & type
/// \todo Fix the fact that this has to be in a shared_ptr for now
template<typename Result>
struct Cast_Helper_Inner<const std::unique_ptr<Result> &> {
static std::unique_ptr<Result> &cast(const Boxed_Value &ob, const Type_Conversions_State *) {
return *(ob.get().cast<std::shared_ptr<std::unique_ptr<Result>>>());
} }
}; };
/// Cast_Helper_Inner for casting to a std::shared_ptr<> type /// Cast_Helper_Inner for casting to a std::shared_ptr<> type
template<typename Result> template<typename Result>
struct Cast_Helper_Inner<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>>(); }
typedef std::shared_ptr<Result> Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *)
{
return ob.get().cast<std::shared_ptr<Result> >();
}
}; };
/// Cast_Helper_Inner for casting to a std::shared_ptr<const> type /// Cast_Helper_Inner for casting to a std::shared_ptr<const> type
template<typename Result> template<typename Result>
struct Cast_Helper_Inner<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 *) {
typedef std::shared_ptr<const Result> Result_Type; if (!ob.get_type_info().is_const()) {
return std::const_pointer_cast<const Result>(ob.get().cast<std::shared_ptr<Result>>());
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *)
{
if (!ob.get_type_info().is_const())
{
return std::const_pointer_cast<const Result>(ob.get().cast<std::shared_ptr<Result> >());
} else { } else {
return ob.get().cast<std::shared_ptr<const Result> >(); return ob.get().cast<std::shared_ptr<const Result>>();
} }
} }
}; };
/// Cast_Helper_Inner for casting to a const std::shared_ptr<> & type /// Cast_Helper_Inner for casting to a const std::shared_ptr<> & type
template<typename Result> template<typename Result>
struct Cast_Helper_Inner<const std::shared_ptr<Result> > : Cast_Helper_Inner<std::shared_ptr<Result> > struct Cast_Helper_Inner<const std::shared_ptr<Result>> : Cast_Helper_Inner<std::shared_ptr<Result>> {
{
}; };
template<typename Result> template<typename Result>
struct Cast_Helper_Inner<const std::shared_ptr<Result> &> : Cast_Helper_Inner<std::shared_ptr<Result> > struct Cast_Helper_Inner<const std::shared_ptr<Result> &> : Cast_Helper_Inner<std::shared_ptr<Result>> {
{ };
template<typename Result>
struct Cast_Helper_Inner<std::shared_ptr<Result> &> {
static_assert(!std::is_const<Result>::value, "Non-const reference to std::shared_ptr<const T> is not supported");
static auto cast(const Boxed_Value &ob, const Type_Conversions_State *) {
std::shared_ptr<Result> &res = ob.get().cast<std::shared_ptr<Result>>();
return ob.pointer_sentinel(res);
}
}; };
/// Cast_Helper_Inner for casting to a const std::shared_ptr<const> & type /// Cast_Helper_Inner for casting to a const std::shared_ptr<const> & type
template<typename Result> template<typename Result>
struct Cast_Helper_Inner<const std::shared_ptr<const Result> > : Cast_Helper_Inner<std::shared_ptr<const Result> > struct Cast_Helper_Inner<const std::shared_ptr<const Result>> : Cast_Helper_Inner<std::shared_ptr<const Result>> {
{
}; };
template<typename Result> template<typename Result>
struct Cast_Helper_Inner<const std::shared_ptr<const Result> &> : Cast_Helper_Inner<std::shared_ptr<const Result> > struct Cast_Helper_Inner<const std::shared_ptr<const Result> &> : Cast_Helper_Inner<std::shared_ptr<const Result>> {
{
}; };
/// Cast_Helper_Inner for casting to a Boxed_Value type /// Cast_Helper_Inner for casting to a Boxed_Value type
template<> template<>
struct Cast_Helper_Inner<Boxed_Value> struct Cast_Helper_Inner<Boxed_Value> {
{ static Boxed_Value cast(const Boxed_Value &ob, const Type_Conversions_State *) { return ob; }
typedef Boxed_Value Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *)
{
return ob;
}
}; };
/// Cast_Helper_Inner for casting to a Boxed_Value & type /// Cast_Helper_Inner for casting to a Boxed_Value & type
template<> template<>
struct Cast_Helper_Inner<Boxed_Value &> struct Cast_Helper_Inner<Boxed_Value &> {
{ static std::reference_wrapper<Boxed_Value> cast(const Boxed_Value &ob, const Type_Conversions_State *) {
typedef std::reference_wrapper<Boxed_Value> Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *)
{
return std::ref(const_cast<Boxed_Value &>(ob)); return std::ref(const_cast<Boxed_Value &>(ob));
} }
}; };
/// Cast_Helper_Inner for casting to a const Boxed_Value & type /// Cast_Helper_Inner for casting to a const Boxed_Value & type
template<> template<>
struct Cast_Helper_Inner<const Boxed_Value> : Cast_Helper_Inner<Boxed_Value> struct Cast_Helper_Inner<const Boxed_Value> : Cast_Helper_Inner<Boxed_Value> {
{
}; };
template<> template<>
struct Cast_Helper_Inner<const Boxed_Value &> : Cast_Helper_Inner<Boxed_Value> struct Cast_Helper_Inner<const Boxed_Value &> : Cast_Helper_Inner<Boxed_Value> {
{
}; };
/// Cast_Helper_Inner for casting to a std::reference_wrapper type /// Cast_Helper_Inner for casting to a std::reference_wrapper type
template<typename Result> template<typename Result>
struct Cast_Helper_Inner<std::reference_wrapper<Result> > : Cast_Helper_Inner<Result &> struct Cast_Helper_Inner<std::reference_wrapper<Result>> : Cast_Helper_Inner<Result &> {
{
}; };
template<typename 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> 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> 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> 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> 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 /// The exposed Cast_Helper object that by default just calls the Cast_Helper_Inner
template<typename T> template<typename T>
struct Cast_Helper struct Cast_Helper {
{ static decltype(auto) cast(const Boxed_Value &ob, const Type_Conversions_State *t_conversions) {
typedef typename Cast_Helper_Inner<T>::Result_Type Result_Type; return (Cast_Helper_Inner<T>::cast(ob, t_conversions));
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *t_conversions)
{
return Cast_Helper_Inner<T>::cast(ob, t_conversions);
} }
}; };
} } // namespace detail
} } // namespace chaiscript
#endif #endif

File diff suppressed because it is too large Load Diff

View File

@ -1,9 +1,12 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) // Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.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_ #ifndef CHAISCRIPT_BOXED_VALUE_HPP_
#define CHAISCRIPT_BOXED_VALUE_HPP_ #define CHAISCRIPT_BOXED_VALUE_HPP_
@ -15,36 +18,29 @@
#include "any.hpp" #include "any.hpp"
#include "type_info.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 /// \brief A wrapper for holding any valid C++ type. All types in ChaiScript are Boxed_Value objects
/// \sa chaiscript::boxed_cast /// \sa chaiscript::boxed_cast
class Boxed_Value class Boxed_Value {
{
public: public:
/// used for explicitly creating a "void" object /// used for explicitly creating a "void" object
struct Void_Type struct Void_Type {
{
}; };
private: private:
/// structure which holds the internal state of a Boxed_Value /// structure which holds the internal state of a Boxed_Value
/// \todo Get rid of Any and merge it with this, reducing an allocation in the process /// \todo Get rid of Any and merge it with this, reducing an allocation in the process
struct Data struct Data {
{ Data(const Type_Info &ti, chaiscript::detail::Any to, bool is_ref, const void *t_void_ptr, bool t_return_value) noexcept
Data(const Type_Info &ti, : m_type_info(ti)
chaiscript::detail::Any to, , m_obj(std::move(to))
bool tr, , m_data_ptr(ti.is_const() ? nullptr : const_cast<void *>(t_void_ptr))
const void *t_void_ptr, , m_const_data_ptr(t_void_ptr)
bool t_return_value) , m_is_ref(is_ref)
: 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_return_value(t_return_value) {
m_is_ref(tr), m_return_value(t_return_value)
{
} }
Data &operator=(const Data &rhs) Data &operator=(const Data &rhs) {
{
m_type_info = rhs.m_type_info; m_type_info = rhs.m_type_info;
m_obj = rhs.m_obj; m_obj = rhs.m_obj;
m_is_ref = rhs.m_is_ref; m_is_ref = rhs.m_is_ref;
@ -52,9 +48,8 @@ namespace chaiscript
m_const_data_ptr = rhs.m_const_data_ptr; m_const_data_ptr = rhs.m_const_data_ptr;
m_return_value = rhs.m_return_value; m_return_value = rhs.m_return_value;
if (rhs.m_attrs) if (rhs.m_attrs) {
{ m_attrs = std::make_unique<std::map<std::string, std::shared_ptr<Data>>>(*rhs.m_attrs);
m_attrs = std::unique_ptr<std::map<std::string, std::shared_ptr<Data>>>(new std::map<std::string, std::shared_ptr<Data>>(*rhs.m_attrs));
} }
return *this; return *this;
@ -62,11 +57,8 @@ namespace chaiscript
Data(const Data &) = delete; Data(const Data &) = delete;
#if !defined(__APPLE__) && (!defined(_MSC_VER) || _MSC_VER != 1800)
Data(Data &&) = default; Data(Data &&) = default;
Data &operator=(Data &&rhs) = default; Data &operator=(Data &&rhs) = default;
#endif
Type_Info m_type_info; Type_Info m_type_info;
chaiscript::detail::Any m_obj; chaiscript::detail::Any m_obj;
@ -77,252 +69,187 @@ namespace chaiscript
bool m_return_value; bool m_return_value;
}; };
struct Object_Data struct Object_Data {
{ static auto get(Boxed_Value::Void_Type, bool t_return_value) {
static std::shared_ptr<Data> 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);
{
return std::make_shared<Data>(
detail::Get_Type_Info<void>::get(),
chaiscript::detail::Any(),
false,
nullptr,
t_return_value)
;
} }
template<typename T> template<typename T>
static std::shared_ptr<Data> get(const std::shared_ptr<T> *obj, bool t_return_value) static auto get(const std::shared_ptr<T> *obj, bool t_return_value) {
{
return get(*obj, t_return_value); return get(*obj, t_return_value);
} }
template<typename T> template<typename T>
static std::shared_ptr<Data> get(const std::shared_ptr<T> &obj, bool t_return_value) 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);
return std::make_shared<Data>(
detail::Get_Type_Info<T>::get(),
chaiscript::detail::Any(obj),
false,
obj.get(),
t_return_value
);
} }
template<typename T> template<typename T>
static std::shared_ptr<Data> get(std::shared_ptr<T> &&obj, bool t_return_value) static auto get(std::shared_ptr<T> &&obj, bool t_return_value) {
{
auto ptr = obj.get(); auto ptr = obj.get();
return std::make_shared<Data>( return std::make_shared<Data>(detail::Get_Type_Info<T>::get(), chaiscript::detail::Any(std::move(obj)), false, ptr, t_return_value);
detail::Get_Type_Info<T>::get(),
chaiscript::detail::Any(std::move(obj)),
false,
ptr,
t_return_value
);
} }
template<typename T> template<typename T>
static std::shared_ptr<Data> get(T *t, bool t_return_value) static auto get(T *t, bool t_return_value) {
{
return get(std::ref(*t), t_return_value); return get(std::ref(*t), t_return_value);
} }
template<typename T> template<typename T>
static std::shared_ptr<Data> get(const T *t, bool t_return_value) static auto get(const T *t, bool t_return_value) {
{
return get(std::cref(*t), t_return_value); return get(std::cref(*t), t_return_value);
} }
template<typename T> template<typename T>
static std::shared_ptr<Data> get(std::reference_wrapper<T> obj, bool t_return_value) static auto get(std::reference_wrapper<T> obj, bool t_return_value) {
{
auto p = &obj.get(); auto p = &obj.get();
return std::make_shared<Data>( return std::make_shared<Data>(detail::Get_Type_Info<T>::get(), chaiscript::detail::Any(std::move(obj)), true, p, t_return_value);
detail::Get_Type_Info<T>::get(),
chaiscript::detail::Any(std::move(obj)),
true,
p,
t_return_value
);
} }
template<typename T> template<typename T>
static std::shared_ptr<Data> get(T t, bool t_return_value) 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 p = std::make_shared<T>(std::move(t));
auto ptr = p.get(); auto ptr = p.get();
return std::make_shared<Data>( return std::make_shared<Data>(detail::Get_Type_Info<T>::get(), chaiscript::detail::Any(std::move(p)), false, ptr, t_return_value);
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
);
} }
static std::shared_ptr<Data> get() { return std::make_shared<Data>(Type_Info(), chaiscript::detail::Any(), false, nullptr, false); }
}; };
public: public:
/// Basic Boxed_Value constructor /// Basic Boxed_Value constructor
template<typename T, template<typename T, typename = std::enable_if_t<!std::is_same_v<Boxed_Value, std::decay_t<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) explicit Boxed_Value(T &&t, bool t_return_value = false)
: m_data(Object_Data::get(std::forward<T>(t), t_return_value)) : m_data(Object_Data::get(std::forward<T>(t), t_return_value)) {
{
} }
/// Unknown-type constructor /// Unknown-type constructor
Boxed_Value() Boxed_Value() = default;
: m_data(Object_Data::get())
{
}
#if !defined(_MSC_VER) || _MSC_VER != 1800 Boxed_Value(Boxed_Value &&) = default;
Boxed_Value(Boxed_Value&&) = default; Boxed_Value &operator=(Boxed_Value &&) = default;
Boxed_Value& operator=(Boxed_Value&&) = default; Boxed_Value(const Boxed_Value &) = default;
#endif Boxed_Value &operator=(const Boxed_Value &) = default;
Boxed_Value(const Boxed_Value&) = default; void swap(Boxed_Value &rhs) noexcept { std::swap(m_data, rhs.m_data); }
Boxed_Value& operator=(const Boxed_Value&) = default;
void swap(Boxed_Value &rhs)
{
std::swap(m_data, rhs.m_data);
}
/// Copy the values stored in rhs.m_data to m_data. /// Copy the values stored in rhs.m_data to m_data.
/// m_data pointers are not shared in this case /// m_data pointers are not shared in this case
Boxed_Value assign(const Boxed_Value &rhs) Boxed_Value assign(const Boxed_Value &rhs) noexcept {
{
(*m_data) = (*rhs.m_data); (*m_data) = (*rhs.m_data);
return *this; return *this;
} }
const Type_Info &get_type_info() const CHAISCRIPT_NOEXCEPT const Type_Info &get_type_info() const noexcept { return m_data->m_type_info; }
{
return m_data->m_type_info;
}
/// return true if the object is uninitialized /// return true if the object is uninitialized
bool is_undef() const CHAISCRIPT_NOEXCEPT bool is_undef() const noexcept { return m_data->m_type_info.is_undef(); }
{
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) {
} }
bool is_const() const CHAISCRIPT_NOEXCEPT ~Sentinel() {
{ // save new pointer data
return m_data->m_type_info.is_const(); const auto ptr_ = m_ptr.get().get();
m_data.get().m_data_ptr = ptr_;
m_data.get().m_const_data_ptr = ptr_;
} }
bool is_type(const Type_Info &ti) const CHAISCRIPT_NOEXCEPT Sentinel &operator=(Sentinel &&s) = default;
{ Sentinel(Sentinel &&s) = default;
return m_data->m_type_info.bare_equal(ti);
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 CHAISCRIPT_NOEXCEPT bool is_null() const noexcept { return (m_data->m_data_ptr == nullptr && m_data->m_const_data_ptr == nullptr); }
{
return (m_data->m_data_ptr == nullptr && m_data->m_const_data_ptr == nullptr);
}
const chaiscript::detail::Any & get() const CHAISCRIPT_NOEXCEPT const chaiscript::detail::Any &get() const noexcept { return m_data->m_obj; }
{
return m_data->m_obj;
}
bool is_ref() const CHAISCRIPT_NOEXCEPT bool is_ref() const noexcept { return m_data->m_is_ref; }
{
return m_data->m_is_ref;
}
bool is_return_value() const CHAISCRIPT_NOEXCEPT bool is_return_value() const noexcept { return m_data->m_return_value; }
{
return m_data->m_return_value;
}
void reset_return_value() const CHAISCRIPT_NOEXCEPT void reset_return_value() const noexcept { m_data->m_return_value = false; }
{
m_data->m_return_value = false;
}
bool is_pointer() const CHAISCRIPT_NOEXCEPT bool is_pointer() const noexcept { return !is_ref(); }
{
return !is_ref();
}
void *get_ptr() const CHAISCRIPT_NOEXCEPT void *get_ptr() const noexcept { return m_data->m_data_ptr; }
{
return m_data->m_data_ptr;
}
const void *get_const_ptr() const CHAISCRIPT_NOEXCEPT const void *get_const_ptr() const noexcept { return m_data->m_const_data_ptr; }
{
return m_data->m_const_data_ptr;
}
Boxed_Value get_attr(const std::string &t_name) Boxed_Value get_attr(const std::string &t_name) {
{ if (!m_data->m_attrs) {
if (!m_data->m_attrs) m_data->m_attrs = std::make_unique<std::map<std::string, std::shared_ptr<Data>>>();
{
m_data->m_attrs = std::unique_ptr<std::map<std::string, std::shared_ptr<Data>>>(new std::map<std::string, std::shared_ptr<Data>>());
} }
auto &attr = (*m_data->m_attrs)[t_name]; auto &attr = (*m_data->m_attrs)[t_name];
if (attr) { if (attr) {
return Boxed_Value(attr, Internal_Construction()); return Boxed_Value(attr, Internal_Construction());
} else { } else {
Boxed_Value bv; //default construct a new one Boxed_Value bv; // default construct a new one
attr = bv.m_data; attr = bv.m_data;
return bv; return bv;
} }
} }
Boxed_Value &copy_attrs(const Boxed_Value &t_obj) Boxed_Value &copy_attrs(const Boxed_Value &t_obj) {
{ if (t_obj.m_data->m_attrs) {
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);
{
m_data->m_attrs = std::unique_ptr<std::map<std::string, std::shared_ptr<Data>>>(new std::map<std::string, std::shared_ptr<Data>>(*t_obj.m_data->m_attrs));
} }
return *this; return *this;
} }
Boxed_Value &clone_attrs(const Boxed_Value &t_obj) Boxed_Value &clone_attrs(const Boxed_Value &t_obj) {
{
copy_attrs(t_obj); copy_attrs(t_obj);
reset_return_value(); reset_return_value();
return *this; return *this;
} }
/// \returns true if the two Boxed_Values share the same internal type /// \returns true if the two Boxed_Values share the same internal type
static bool type_match(const Boxed_Value &l, const Boxed_Value &r) CHAISCRIPT_NOEXCEPT static bool type_match(const Boxed_Value &l, const Boxed_Value &r) noexcept { return l.get_type_info() == r.get_type_info(); }
{
return l.get_type_info() == r.get_type_info();
}
private: private:
// necessary to avoid hitting the templated && constructor of Boxed_Value // necessary to avoid hitting the templated && constructor of Boxed_Value
struct Internal_Construction{}; struct Internal_Construction {
Boxed_Value(const std::shared_ptr<Data> &t_data, Internal_Construction)
: m_data(t_data) {
}
std::shared_ptr<Data> m_data;
}; };
/// @brief Creates a Boxed_Value. If the object passed in is a value type, it is copied. If it is a pointer, std::shared_ptr, or std::reference_type Boxed_Value(std::shared_ptr<Data> t_data, Internal_Construction)
: m_data(std::move(t_data)) {
}
std::shared_ptr<Data> m_data = Object_Data::get();
};
/// @brief Creates a Boxed_Value. If the object passed in is a value type, it is copied. If it is a pointer, std::shared_ptr, or
/// std::reference_type
/// a copy is not made. /// a copy is not made.
/// @param t The value to box /// @param t The value to box
/// ///
@ -337,8 +264,7 @@ namespace chaiscript
/// ///
/// @sa @ref adding_objects /// @sa @ref adding_objects
template<typename T> template<typename T>
Boxed_Value var(T &&t) Boxed_Value var(T &&t) {
{
return Boxed_Value(std::forward<T>(t)); return Boxed_Value(std::forward<T>(t));
} }
@ -348,9 +274,8 @@ namespace chaiscript
/// \returns Immutable Boxed_Value /// \returns Immutable Boxed_Value
/// \sa Boxed_Value::is_const /// \sa Boxed_Value::is_const
template<typename T> template<typename T>
Boxed_Value const_var_impl(const T &t) Boxed_Value const_var_impl(const T &t) {
{ return Boxed_Value(std::make_shared<typename std::add_const<T>::type>(t));
return Boxed_Value(std::make_shared<typename std::add_const<T>::type >(t));
} }
/// \brief Takes a pointer to a value, adds const to the pointed to type and returns an immutable Boxed_Value. /// \brief Takes a pointer to a value, adds const to the pointed to type and returns an immutable Boxed_Value.
@ -359,9 +284,8 @@ namespace chaiscript
/// \returns Immutable Boxed_Value /// \returns Immutable Boxed_Value
/// \sa Boxed_Value::is_const /// \sa Boxed_Value::is_const
template<typename T> template<typename T>
Boxed_Value const_var_impl(T *t) Boxed_Value const_var_impl(T *t) {
{ return Boxed_Value(const_cast<typename std::add_const<T>::type *>(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. /// \brief Takes a std::shared_ptr to a value, adds const to the pointed to type and returns an immutable Boxed_Value.
@ -370,9 +294,8 @@ namespace chaiscript
/// \returns Immutable Boxed_Value /// \returns Immutable Boxed_Value
/// \sa Boxed_Value::is_const /// \sa Boxed_Value::is_const
template<typename T> template<typename T>
Boxed_Value const_var_impl(const std::shared_ptr<T> &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));
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. /// \brief Takes a std::reference_wrapper value, adds const to the referenced type and returns an immutable Boxed_Value.
@ -381,11 +304,10 @@ namespace chaiscript
/// \returns Immutable Boxed_Value /// \returns Immutable Boxed_Value
/// \sa Boxed_Value::is_const /// \sa Boxed_Value::is_const
template<typename T> template<typename T>
Boxed_Value const_var_impl(const std::reference_wrapper<T> &t) Boxed_Value const_var_impl(const std::reference_wrapper<T> &t) {
{ return Boxed_Value(std::cref(t.get()));
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 /// \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. /// the value is not copied. If it is an object type, it is copied.
@ -411,15 +333,18 @@ namespace chaiscript
/// \todo support C++11 strongly typed enums /// \todo support C++11 strongly typed enums
/// \sa \ref adding_objects /// \sa \ref adding_objects
template<typename T> template<typename T>
Boxed_Value const_var(const T &t) Boxed_Value const_var(const T &t) {
{
return detail::const_var_impl(t); return detail::const_var_impl(t);
} }
#ifdef CHAISCRIPT_HAS_MAGIC_STATICS inline Boxed_Value void_var() {
static const auto v = Boxed_Value(Boxed_Value::Void_Type());
return v;
}
inline Boxed_Value const_var(bool b) { inline Boxed_Value const_var(bool b) {
static auto t = detail::const_var_impl(true); static const auto t = detail::const_var_impl(true);
static auto f = detail::const_var_impl(false); static const auto f = detail::const_var_impl(false);
if (b) { if (b) {
return t; return t;
@ -427,9 +352,7 @@ namespace chaiscript
return f; return f;
} }
} }
#endif
} } // namespace chaiscript
#endif #endif

View File

@ -1,7 +1,7 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) // Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
#ifndef CHAISCRIPT_CALLABLE_TRAITS_HPP_ #ifndef CHAISCRIPT_CALLABLE_TRAITS_HPP_
@ -12,49 +12,50 @@
namespace chaiscript { namespace chaiscript {
namespace dispatch { namespace dispatch {
namespace detail { namespace detail {
template<typename Class, typename... Param>
template<typename Class, typename ... Param> struct Constructor {
struct Constructor template<typename... Inner>
{ std::shared_ptr<Class> operator()(Inner &&...inner) const {
template<typename ... Inner>
std::shared_ptr<Class> operator()(Inner&& ... inner) const {
return std::make_shared<Class>(std::forward<Inner>(inner)...); return std::make_shared<Class>(std::forward<Inner>(inner)...);
} }
}; };
template<typename Ret, typename Class, typename ... Param> template<typename Ret, typename Class, typename... Param>
struct Const_Caller struct Const_Caller {
{ explicit Const_Caller(Ret (Class::*t_func)(Param...) const)
Const_Caller(Ret (Class::*t_func)(Param...) const) : m_func(t_func) {} : m_func(t_func) {
}
template<typename ... Inner> template<typename... Inner>
Ret operator()(const Class &o, Inner&& ... inner) const { Ret operator()(const Class &o, Inner &&...inner) const {
return (o.*m_func)(std::forward<Inner>(inner)...); return (o.*m_func)(std::forward<Inner>(inner)...);
} }
Ret (Class::*m_func)(Param...) const; Ret (Class::*m_func)(Param...) const;
}; };
template<typename Ret, typename ... Param> template<typename Ret, typename... Param>
struct Fun_Caller struct Fun_Caller {
{ explicit Fun_Caller(Ret (*t_func)(Param...))
Fun_Caller(Ret( * t_func)(Param...) ) : m_func(t_func) {} : m_func(t_func) {
}
template<typename ... Inner> template<typename... Inner>
Ret operator()(Inner&& ... inner) const { Ret operator()(Inner &&...inner) const {
return (m_func)(std::forward<Inner>(inner)...); return (m_func)(std::forward<Inner>(inner)...);
} }
Ret(*m_func)(Param...); Ret (*m_func)(Param...);
}; };
template<typename Ret, typename Class, typename ... Param> template<typename Ret, typename Class, typename... Param>
struct Caller struct Caller {
{ explicit Caller(Ret (Class::*t_func)(Param...))
Caller(Ret (Class::*t_func)(Param...)) : m_func(t_func) {} : m_func(t_func) {
}
template<typename ... Inner> template<typename... Inner>
Ret operator()(Class &o, Inner&& ... inner) const { Ret operator()(Class &o, Inner &&...inner) const {
return (o.*m_func)(std::forward<Inner>(inner)...); return (o.*m_func)(std::forward<Inner>(inner)...);
} }
@ -62,46 +63,37 @@ namespace chaiscript {
}; };
template<typename T> template<typename T>
struct Arity struct Arity {
{
}; };
template<typename Ret, typename ... Params> template<typename Ret, typename... Params>
struct Arity<Ret (Params...)> struct Arity<Ret(Params...)> {
{
static const size_t arity = sizeof...(Params); static const size_t arity = sizeof...(Params);
}; };
template<typename T>
struct Function_Signature {
};
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> template<typename T>
struct Function_Signature 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
template<typename Ret, typename ... Params> } // namespace dispatch
struct Function_Signature<Ret (Params...)> } // namespace chaiscript
{
typedef Ret Return_Type;
typedef Ret (Signature)(Params...);
};
template<typename Ret, typename T, typename ... Params>
struct Function_Signature<Ret (T::*)(Params...) const>
{
typedef Ret Return_Type;
typedef Ret (Signature)(Params...);
};
template<typename T>
struct Callable_Traits
{
typedef typename Function_Signature<decltype(&T::operator())>::Signature Signature;
typedef typename Function_Signature<decltype(&T::operator())>::Return_Type Return_Type;
};
}
}
}
#endif #endif

File diff suppressed because it is too large Load Diff

View File

@ -1,9 +1,12 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) // Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.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_ #ifndef CHAISCRIPT_DYNAMIC_OBJECT_HPP_
#define CHAISCRIPT_DYNAMIC_OBJECT_HPP_ #define CHAISCRIPT_DYNAMIC_OBJECT_HPP_
@ -14,65 +17,44 @@
#include "boxed_value.hpp" #include "boxed_value.hpp"
namespace chaiscript { namespace chaiscript {
class Type_Conversions; class Type_Conversions;
namespace dispatch { namespace dispatch {
class Proxy_Function_Base; class Proxy_Function_Base;
} // namespace dispatch } // namespace dispatch
} // namespace chaiscript } // namespace chaiscript
namespace chaiscript namespace chaiscript {
{ namespace dispatch {
namespace dispatch
{
struct option_explicit_set : std::runtime_error { struct option_explicit_set : std::runtime_error {
option_explicit_set(const std::string &t_param_name) 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") {
{
} }
virtual ~option_explicit_set() CHAISCRIPT_NOEXCEPT {} option_explicit_set(const option_explicit_set &) = default;
~option_explicit_set() noexcept override = default;
}; };
class Dynamic_Object class Dynamic_Object {
{
public: public:
Dynamic_Object(std::string t_type_name) explicit Dynamic_Object(std::string t_type_name)
: m_type_name(std::move(t_type_name)), m_option_explicit(false) : m_type_name(std::move(t_type_name))
{ , m_option_explicit(false) {
} }
Dynamic_Object() : m_type_name(""), m_option_explicit(false) Dynamic_Object() = default;
{
}
bool is_explicit() const bool is_explicit() const noexcept { return m_option_explicit; }
{
return m_option_explicit;
}
void set_explicit(const bool t_explicit) void set_explicit(const bool t_explicit) noexcept { m_option_explicit = t_explicit; }
{
m_option_explicit = t_explicit;
}
std::string get_type_name() const const std::string &get_type_name() const noexcept { return m_type_name; }
{
return m_type_name;
}
const Boxed_Value &operator[](const std::string &t_attr_name) const const Boxed_Value &operator[](const std::string &t_attr_name) const { return get_attr(t_attr_name); }
{
return get_attr(t_attr_name);
}
Boxed_Value &operator[](const std::string &t_attr_name) Boxed_Value &operator[](const std::string &t_attr_name) { return get_attr(t_attr_name); }
{
return get_attr(t_attr_name);
}
const Boxed_Value &get_attr(const std::string &t_attr_name) const const Boxed_Value &get_attr(const std::string &t_attr_name) const {
{
auto a = m_attrs.find(t_attr_name); auto a = m_attrs.find(t_attr_name);
if (a != m_attrs.end()) { if (a != m_attrs.end()) {
@ -82,13 +64,11 @@ namespace chaiscript
} }
} }
Boxed_Value &get_attr(const std::string &t_attr_name) bool has_attr(const std::string &t_attr_name) const { return m_attrs.find(t_attr_name) != m_attrs.end(); }
{
return m_attrs[t_attr_name];
}
Boxed_Value &method_missing(const std::string &t_method_name) 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()) { if (m_option_explicit && m_attrs.find(t_method_name) == m_attrs.end()) {
throw option_explicit_set(t_method_name); throw option_explicit_set(t_method_name);
} }
@ -96,8 +76,7 @@ namespace chaiscript
return get_attr(t_method_name); return get_attr(t_method_name);
} }
const Boxed_Value &method_missing(const std::string &t_method_name) const 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()) { if (m_option_explicit && m_attrs.find(t_method_name) == m_attrs.end()) {
throw option_explicit_set(t_method_name); throw option_explicit_set(t_method_name);
} }
@ -105,20 +84,15 @@ namespace chaiscript
return get_attr(t_method_name); return get_attr(t_method_name);
} }
std::map<std::string, Boxed_Value> get_attrs() const { return m_attrs; }
std::map<std::string, Boxed_Value> get_attrs() const
{
return m_attrs;
}
private: private:
std::string m_type_name; const std::string m_type_name = "";
bool m_option_explicit; 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 #endif

View File

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

View File

@ -1,9 +1,12 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) // Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.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_ #ifndef CHAISCRIPT_EXCEPTION_SPECIFICATION_HPP_
#define CHAISCRIPT_EXCEPTION_SPECIFICATION_HPP_ #define CHAISCRIPT_EXCEPTION_SPECIFICATION_HPP_
@ -13,93 +16,28 @@
#include "boxed_cast.hpp" #include "boxed_cast.hpp"
namespace chaiscript { namespace chaiscript {
class Boxed_Value; namespace detail {
namespace exception { struct Exception_Handler_Base {
class bad_boxed_cast;
} // namespace exception
} // namespace chaiscript
namespace chaiscript
{
namespace detail
{
/// \todo make this a variadic template
struct Exception_Handler_Base
{
virtual void handle(const Boxed_Value &bv, const Dispatch_Engine &t_engine) = 0; virtual void handle(const Boxed_Value &bv, const Dispatch_Engine &t_engine) = 0;
virtual ~Exception_Handler_Base() {} virtual ~Exception_Handler_Base() = default;
protected: protected:
template<typename T> template<typename T>
void throw_type(const Boxed_Value &bv, const Dispatch_Engine &t_engine) static void throw_type(const Boxed_Value &bv, const Dispatch_Engine &t_engine) {
{ try {
try { T t = t_engine.boxed_cast<T>(bv); throw t; } catch (const chaiscript::exception::bad_boxed_cast &) {} T t = t_engine.boxed_cast<T>(bv);
throw t;
} catch (const chaiscript::exception::bad_boxed_cast &) {
}
} }
}; };
template<typename T1> template<typename... T>
struct Exception_Handler_Impl1 : Exception_Handler_Base 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), ...); }
virtual ~Exception_Handler_Impl1() {}
virtual void handle(const Boxed_Value &bv, const Dispatch_Engine &t_engine) CHAISCRIPT_OVERRIDE
{
throw_type<T1>(bv, t_engine);
}
}; };
template<typename T1, typename T2> } // namespace detail
struct Exception_Handler_Impl2 : Exception_Handler_Base
{
virtual ~Exception_Handler_Impl2() {}
virtual void handle(const Boxed_Value &bv, const Dispatch_Engine &t_engine) CHAISCRIPT_OVERRIDE
{
throw_type<T1>(bv, t_engine);
throw_type<T2>(bv, t_engine);
}
};
template<typename T1, typename T2, typename T3>
struct Exception_Handler_Impl3 : Exception_Handler_Base
{
virtual ~Exception_Handler_Impl3() {}
virtual void handle(const Boxed_Value &bv, const Dispatch_Engine &t_engine) CHAISCRIPT_OVERRIDE
{
throw_type<T1>(bv, t_engine);
throw_type<T2>(bv, t_engine);
throw_type<T3>(bv, t_engine);
}
};
template<typename T1, typename T2, typename T3, typename T4>
struct Exception_Handler_Impl4 : Exception_Handler_Base
{
virtual ~Exception_Handler_Impl4() {}
virtual void handle(const Boxed_Value &bv, const Dispatch_Engine &t_engine) CHAISCRIPT_OVERRIDE
{
throw_type<T1>(bv, t_engine);
throw_type<T2>(bv, t_engine);
throw_type<T3>(bv, t_engine);
throw_type<T4>(bv, t_engine);
}
};
template<typename T1, typename T2, typename T3, typename T4, typename T5>
struct Exception_Handler_Impl5 : Exception_Handler_Base
{
virtual ~Exception_Handler_Impl5() {}
virtual void handle(const Boxed_Value &bv, const Dispatch_Engine &t_engine) CHAISCRIPT_OVERRIDE
{
throw_type<T1>(bv, t_engine);
throw_type<T2>(bv, t_engine);
throw_type<T3>(bv, t_engine);
throw_type<T4>(bv, t_engine);
throw_type<T5>(bv, t_engine);
}
};
}
/// \brief Used in the automatic unboxing of exceptions thrown during script evaluation /// \brief Used in the automatic unboxing of exceptions thrown during script evaluation
/// ///
@ -111,7 +49,8 @@ namespace chaiscript
/// chaiscript::ChaiScript chai; /// chaiscript::ChaiScript chai;
/// ///
/// try { /// try {
/// chai.eval("throw(runtime_error(\"error\"))", chaiscript::exception_specification<int, double, float, const std::string &, const std::exception &>()); /// chai.eval("throw(runtime_error(\"error\"))", chaiscript::exception_specification<int, double, float, const std::string &, const
/// std::exception &>());
/// } catch (const double e) { /// } catch (const double e) {
/// } catch (int) { /// } catch (int) {
/// } catch (float) { /// } catch (float) {
@ -151,49 +90,14 @@ namespace chaiscript
/// ///
/// \sa chaiscript::exception_specification for creation of chaiscript::Exception_Handler objects /// \sa chaiscript::exception_specification for creation of chaiscript::Exception_Handler objects
/// \sa \ref exceptions /// \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 /// \brief creates a chaiscript::Exception_Handler which handles one type of exception unboxing
/// \sa \ref exceptions /// \sa \ref exceptions
template<typename T1> template<typename... T>
Exception_Handler exception_specification() Exception_Handler exception_specification() {
{ return std::make_shared<detail::Exception_Handler_Impl<T...>>();
return Exception_Handler(new detail::Exception_Handler_Impl1<T1>());
} }
} // namespace chaiscript
/// \brief creates a chaiscript::Exception_Handler which handles two types of exception unboxing
/// \sa \ref exceptions
template<typename T1, typename T2>
Exception_Handler exception_specification()
{
return Exception_Handler(new detail::Exception_Handler_Impl2<T1, T2>());
}
/// \brief creates a chaiscript::Exception_Handler which handles three types of exception unboxing
/// \sa \ref exceptions
template<typename T1, typename T2, typename T3>
Exception_Handler exception_specification()
{
return Exception_Handler(new detail::Exception_Handler_Impl3<T1, T2, T3>());
}
/// \brief creates a chaiscript::Exception_Handler which handles four types of exception unboxing
/// \sa \ref exceptions
template<typename T1, typename T2, typename T3, typename T4>
Exception_Handler exception_specification()
{
return Exception_Handler(new detail::Exception_Handler_Impl4<T1, T2, T3, T4>());
}
/// \brief creates a chaiscript::Exception_Handler which handles five types of exception unboxing
/// \sa \ref exceptions
template<typename T1, typename T2, typename T3, typename T4, typename T5>
Exception_Handler exception_specification()
{
return Exception_Handler(new detail::Exception_Handler_Impl5<T1, T2, T3, T4, T5>());
}
}
#endif #endif

View File

@ -1,9 +1,12 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) // Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.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_ #ifndef CHAISCRIPT_FUNCTION_CALL_HPP_
#define CHAISCRIPT_FUNCTION_CALL_HPP_ #define CHAISCRIPT_FUNCTION_CALL_HPP_
@ -14,20 +17,25 @@
#include "boxed_cast.hpp" #include "boxed_cast.hpp"
#include "function_call_detail.hpp" #include "function_call_detail.hpp"
#include "proxy_functions.hpp" #include "proxy_functions.hpp"
#include "callable_traits.hpp"
namespace chaiscript { namespace chaiscript {
class Boxed_Value; class Boxed_Value;
class Type_Conversions; class Type_Conversions_State;
namespace detail { namespace detail {
template <typename T> struct Cast_Helper; template<typename T>
} // namespace detail struct Cast_Helper;
} // namespace detail
} // namespace chaiscript } // namespace chaiscript
namespace chaiscript namespace chaiscript {
{ namespace dispatch {
namespace dispatch namespace detail {
{ template<typename Ret, typename... Param>
constexpr auto arity(Ret (*)(Param...)) noexcept {
return sizeof...(Param);
}
} // namespace detail
/// Build a function caller that knows how to dispatch on a set of functions /// Build a function caller that knows how to dispatch on a set of functions
/// example: /// example:
/// std::function<void (int)> f = /// std::function<void (int)> f =
@ -35,19 +43,16 @@ namespace chaiscript
/// \returns A std::function object for dispatching /// \returns A std::function object for dispatching
/// \param[in] funcs the set of functions to dispatch on. /// \param[in] funcs the set of functions to dispatch on.
template<typename FunctionType> template<typename FunctionType>
std::function<FunctionType> std::function<FunctionType> functor(const std::vector<Const_Proxy_Function> &funcs, const Type_Conversions_State *t_conversions) {
functor(const std::vector<Const_Proxy_Function> &funcs, const Type_Conversions *t_conversions) const bool has_arity_match = std::any_of(funcs.begin(), funcs.end(), [](const Const_Proxy_Function &f) {
{ return f->get_arity() == -1 || size_t(f->get_arity()) == detail::arity(static_cast<FunctionType *>(nullptr));
const bool has_arity_match = std::any_of(funcs.begin(), funcs.end(),
[](const Const_Proxy_Function &f) {
return f->get_arity() == -1 || size_t(f->get_arity()) == chaiscript::dispatch::detail::Arity<FunctionType>::arity;
}); });
if (!has_arity_match) { if (!has_arity_match) {
throw exception::bad_boxed_cast(user_type<Const_Proxy_Function>(), typeid(std::function<FunctionType>)); throw exception::bad_boxed_cast(user_type<Const_Proxy_Function>(), typeid(std::function<FunctionType>));
} }
FunctionType *p=nullptr; FunctionType *p = nullptr;
return detail::build_function_caller_helper(p, funcs, t_conversions); return detail::build_function_caller_helper(p, funcs, t_conversions);
} }
@ -63,33 +68,24 @@ namespace chaiscript
/// \returns A std::function object for dispatching /// \returns A std::function object for dispatching
/// \param[in] func A function to execute. /// \param[in] func A function to execute.
template<typename FunctionType> template<typename FunctionType>
std::function<FunctionType> std::function<FunctionType> functor(Const_Proxy_Function func, const Type_Conversions_State *t_conversions) {
functor(Const_Proxy_Function func, const Type_Conversions *t_conversions)
{
return functor<FunctionType>(std::vector<Const_Proxy_Function>({std::move(func)}), 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 /// Helper for automatically unboxing a Boxed_Value that contains a function object
/// and creating a typesafe C++ function caller from it. /// and creating a typesafe C++ function caller from it.
template<typename FunctionType> template<typename FunctionType>
std::function<FunctionType> std::function<FunctionType> functor(const Boxed_Value &bv, const Type_Conversions_State *t_conversions) {
functor(const Boxed_Value &bv, const Type_Conversions *t_conversions) return functor<FunctionType>(boxed_cast<Const_Proxy_Function>(bv, t_conversions), t_conversions);
{
return functor<FunctionType>(boxed_cast<Const_Proxy_Function >(bv, t_conversions), t_conversions);
}
} }
} // namespace dispatch
namespace detail{ namespace detail {
/// Cast helper to handle automatic casting to const std::function & /// Cast helper to handle automatic casting to const std::function &
template<typename Signature> template<typename Signature>
struct Cast_Helper<const std::function<Signature> &> struct Cast_Helper<const std::function<Signature> &> {
{ static std::function<Signature> cast(const Boxed_Value &ob, const Type_Conversions_State *t_conversions) {
typedef std::function<Signature> Result_Type; if (ob.get_type_info().bare_equal(user_type<Const_Proxy_Function>())) {
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *t_conversions)
{
if (ob.get_type_info().bare_equal(user_type<Const_Proxy_Function>()))
{
return dispatch::functor<Signature>(ob, t_conversions); return dispatch::functor<Signature>(ob, t_conversions);
} else { } else {
return Cast_Helper_Inner<const std::function<Signature> &>::cast(ob, t_conversions); return Cast_Helper_Inner<const std::function<Signature> &>::cast(ob, t_conversions);
@ -99,39 +95,28 @@ namespace chaiscript
/// Cast helper to handle automatic casting to std::function /// Cast helper to handle automatic casting to std::function
template<typename Signature> template<typename Signature>
struct Cast_Helper<std::function<Signature> > struct Cast_Helper<std::function<Signature>> {
{ static std::function<Signature> cast(const Boxed_Value &ob, const Type_Conversions_State *t_conversions) {
typedef std::function<Signature> Result_Type; if (ob.get_type_info().bare_equal(user_type<Const_Proxy_Function>())) {
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *t_conversions)
{
if (ob.get_type_info().bare_equal(user_type<Const_Proxy_Function>()))
{
return dispatch::functor<Signature>(ob, t_conversions); return dispatch::functor<Signature>(ob, t_conversions);
} else { } else {
return Cast_Helper_Inner<std::function<Signature> >::cast(ob, t_conversions); return Cast_Helper_Inner<std::function<Signature>>::cast(ob, t_conversions);
} }
} }
}; };
/// Cast helper to handle automatic casting to const std::function /// Cast helper to handle automatic casting to const std::function
template<typename Signature> template<typename Signature>
struct Cast_Helper<const std::function<Signature> > struct Cast_Helper<const std::function<Signature>> {
{ static std::function<Signature> cast(const Boxed_Value &ob, const Type_Conversions_State *t_conversions) {
typedef std::function<Signature> Result_Type; if (ob.get_type_info().bare_equal(user_type<Const_Proxy_Function>())) {
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *t_conversions)
{
if (ob.get_type_info().bare_equal(user_type<Const_Proxy_Function>()))
{
return dispatch::functor<Signature>(ob, t_conversions); return dispatch::functor<Signature>(ob, t_conversions);
} else { } else {
return Cast_Helper_Inner<const std::function<Signature> >::cast(ob, t_conversions); return Cast_Helper_Inner<const std::function<Signature>>::cast(ob, t_conversions);
} }
} }
}; };
} } // namespace detail
} } // namespace chaiscript
#endif #endif

View File

@ -1,9 +1,12 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) // Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.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_ #ifndef CHAISCRIPT_FUNCTION_CALL_DETAIL_HPP_
#define CHAISCRIPT_FUNCTION_CALL_DETAIL_HPP_ #define CHAISCRIPT_FUNCTION_CALL_DETAIL_HPP_
@ -16,106 +19,61 @@
#include "boxed_cast.hpp" #include "boxed_cast.hpp"
#include "boxed_number.hpp" #include "boxed_number.hpp"
#include "boxed_value.hpp" #include "boxed_value.hpp"
#include "type_conversions.hpp"
#include "proxy_functions.hpp" #include "proxy_functions.hpp"
#include "type_conversions.hpp"
namespace chaiscript namespace chaiscript::dispatch::detail {
{ /// used internally for unwrapping a function call's types
namespace dispatch template<typename Ret, typename... Param>
{ struct Build_Function_Caller_Helper {
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 *t_conversions)
{
return boxed_cast<Ret>(dispatch::dispatch(t_funcs, params, t_conversions?*t_conversions:Type_Conversions()), t_conversions);
}
};
/**
* Specialization for arithmetic return types
*/
template<typename Ret>
struct Function_Caller_Ret<Ret, true>
{
static Ret call(const std::vector<Const_Proxy_Function> &t_funcs,
const std::vector<Boxed_Value> &params, const Type_Conversions *t_conversions)
{
return Boxed_Number(dispatch::dispatch(t_funcs, params, t_conversions?*t_conversions:Type_Conversions())).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 *t_conversions)
{
dispatch::dispatch(t_funcs, params, t_conversions?*t_conversions:Type_Conversions());
}
};
/**
* 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) Build_Function_Caller_Helper(std::vector<Const_Proxy_Function> t_funcs, const Type_Conversions *t_conversions)
: m_funcs(std::move(t_funcs)), : m_funcs(std::move(t_funcs))
m_conversions(t_conversions) , m_conversions(t_conversions) {
{
} }
template<typename ... P> Ret call(const chaiscript::Function_Params &params, const Type_Conversions_State &t_state) {
Ret operator()(P&& ... param) 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>();
return Function_Caller_Ret<Ret, std::is_arithmetic<Ret>::value && !std::is_same<Ret, bool>::value>::call(m_funcs, { } else if constexpr (std::is_same_v<void, Ret>) {
box<P>(std::forward<P>(param))... dispatch::dispatch(m_funcs, params, t_state);
}, m_conversions } 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> 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 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))); return Boxed_Value(std::ref(std::forward<Q>(q)));
} } else {
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)); 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; std::vector<Const_Proxy_Function> m_funcs;
const Type_Conversions *m_conversions; const Type_Conversions *m_conversions;
}; };
/// \todo what happens if t_conversions is deleted out from under us?! /// \todo what happens if t_conversions is deleted out from under us?!
template<typename Ret, typename ... Params> template<typename Ret, typename... Params>
std::function<Ret (Params...)> build_function_caller_helper(Ret (Params...), const std::vector<Const_Proxy_Function> &funcs, const Type_Conversions *t_conversions) std::function<Ret(Params...)>
{ build_function_caller_helper(Ret(Params...), const std::vector<Const_Proxy_Function> &funcs, const Type_Conversions_State *t_conversions) {
/* /*
if (funcs.size() == 1) if (funcs.size() == 1)
{ {
@ -130,13 +88,10 @@ namespace chaiscript
// looks like this either wasn't a Proxy_Function_Impl or the types didn't match // 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 // 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)); return std::function<Ret(Params...)>(Build_Function_Caller_Helper<Ret, Params...>(funcs, t_conversions ? t_conversions->get() : nullptr));
} }
} } // namespace chaiscript::dispatch::detail
}
}
#endif #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,9 +1,12 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) // Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.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_ #ifndef CHAISCRIPT_HANDLE_RETURN_HPP_
#define CHAISCRIPT_HANDLE_RETURN_HPP_ #define CHAISCRIPT_HANDLE_RETURN_HPP_
@ -15,264 +18,178 @@
#include "boxed_value.hpp" #include "boxed_value.hpp"
namespace chaiscript { namespace chaiscript {
class Boxed_Number; class Boxed_Number;
} // namespace chaiscript } // namespace chaiscript
namespace chaiscript namespace chaiscript {
{ namespace dispatch {
namespace dispatch template<class T, class U>
{ class Proxy_Function_Callable_Impl;
template<class T, class U> class Proxy_Function_Callable_Impl; template<class T>
template<class T> class Assignable_Proxy_Function_Impl; class Assignable_Proxy_Function_Impl;
namespace detail namespace detail {
{ /// Used internally for handling a return value from a Proxy_Function call
/**
* Used internally for handling a return value from a Proxy_Function call
*/
template<typename Ret> template<typename Ret>
struct Handle_Return struct Handle_Return {
{ template<typename T, typename = typename std::enable_if_t<std::is_trivial_v<typename std::decay_t<T>>>>
template<typename T, static Boxed_Value handle(T r) {
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); return Boxed_Value(std::move(r), true);
} }
template<typename T, template<typename T, typename = typename std::enable_if_t<!(std::is_trivial_v<typename std::decay_t<T>>)>>
typename = typename std::enable_if<!std::is_pod<typename std::decay<T>::type>::value>::type> static Boxed_Value handle(T &&r) {
static Boxed_Value handle(T &&r)
{
return Boxed_Value(std::make_shared<T>(std::forward<T>(r)), true); return Boxed_Value(std::make_shared<T>(std::forward<T>(r)), true);
} }
}; };
template<typename Ret> template<typename Ret>
struct Handle_Return<const std::function<Ret> &> struct Handle_Return<const std::function<Ret> &> {
{
static Boxed_Value handle(const std::function<Ret> &f) { static Boxed_Value handle(const std::function<Ret> &f) {
return Boxed_Value( return Boxed_Value(
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Ret, std::function<Ret>>>(f) chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Ret, std::function<Ret>>>(f));
);
} }
}; };
template<typename Ret> template<typename Ret>
struct Handle_Return<std::function<Ret>> struct Handle_Return<std::function<Ret>> : 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> template<typename Ret>
struct Handle_Return<const std::shared_ptr<std::function<Ret>>> struct Handle_Return<const std::shared_ptr<std::function<Ret>>> {
{
static Boxed_Value handle(const std::shared_ptr<std::function<Ret>> &f) { static Boxed_Value handle(const std::shared_ptr<std::function<Ret>> &f) {
return Boxed_Value( return Boxed_Value(
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Assignable_Proxy_Function_Impl<Ret>>(std::ref(*f),f) chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Assignable_Proxy_Function_Impl<Ret>>(std::ref(*f), f));
);
} }
}; };
template<typename Ret> template<typename Ret>
struct 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>>> {
{
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> template<typename Ret>
struct Handle_Return<std::shared_ptr<std::function<Ret>>> struct Handle_Return<std::shared_ptr<std::function<Ret>>> : 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> template<typename Ret>
struct Handle_Return<std::function<Ret> &> struct Handle_Return<std::function<Ret> &> {
{
static Boxed_Value handle(std::function<Ret> &f) { static Boxed_Value handle(std::function<Ret> &f) {
return Boxed_Value( return Boxed_Value(chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Assignable_Proxy_Function_Impl<Ret>>(
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Assignable_Proxy_Function_Impl<Ret>>(std::ref(f), std::ref(f), std::shared_ptr<std::function<Ret>>()));
std::shared_ptr<std::function<Ret>>())
);
} }
static Boxed_Value handle(const std::function<Ret> &f) { static Boxed_Value handle(const std::function<Ret> &f) {
return Boxed_Value( return Boxed_Value(
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Ret, std::function<Ret>>>(f) chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Ret, std::function<Ret>>>(f));
);
} }
}; };
template<typename Ret> template<typename Ret>
struct Handle_Return<Ret *> struct Handle_Return<Ret *&> {
{ static Boxed_Value handle(Ret *p) { return Boxed_Value(p, true); }
static Boxed_Value handle(Ret *p)
{
return Boxed_Value(p, true);
}
}; };
template<typename Ret> template<typename Ret>
struct Handle_Return<const Ret *> struct Handle_Return<const Ret *&> {
{ static Boxed_Value handle(const Ret *p) { return Boxed_Value(p, true); }
static Boxed_Value handle(const Ret *p)
{
return Boxed_Value(p, true);
}
}; };
template<typename Ret> template<typename Ret>
struct Handle_Return<std::shared_ptr<Ret> &> struct Handle_Return<Ret *> {
{ static Boxed_Value handle(Ret *p) { return Boxed_Value(p, true); }
static Boxed_Value handle(const std::shared_ptr<Ret> &r)
{
return Boxed_Value(r, true);
}
}; };
template<typename Ret> template<typename Ret>
struct Handle_Return<std::shared_ptr<Ret> > struct Handle_Return<const Ret *> {
{ static Boxed_Value handle(const Ret *p) { return Boxed_Value(p, true); }
static Boxed_Value handle(const std::shared_ptr<Ret> &r)
{
return Boxed_Value(r, true);
}
}; };
template<typename Ret> template<typename Ret>
struct Handle_Return<const std::shared_ptr<Ret> &> struct Handle_Return<std::shared_ptr<Ret> &> {
{ static Boxed_Value handle(const std::shared_ptr<Ret> &r) { return Boxed_Value(r, true); }
static Boxed_Value handle(const std::shared_ptr<Ret> &r)
{
return Boxed_Value(r, true);
}
}; };
template<typename Ret> template<typename Ret>
struct Handle_Return<const Ret &> struct Handle_Return<std::shared_ptr<Ret>> : Handle_Return<std::shared_ptr<Ret> &> {
{ };
static Boxed_Value handle(const Ret &r)
{ template<typename 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); }
};
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); return Boxed_Value(std::cref(r), true);
} }
}; };
/**
* Used internally for handling a return value from a Proxy_Function call
*/
template<typename Ret> template<typename Ret>
struct Handle_Return<Ret &> struct Handle_Return_Ref<Ret, true> {
{ template<typename T>
static Boxed_Value handle(Ret &r) static Boxed_Value handle(T &&r) {
{ return Boxed_Value(typename std::remove_reference<decltype(r)>::type{r}, true);
return Boxed_Value(std::ref(r));
} }
};
static Boxed_Value handle(const Ret &r) template<typename Ret>
{ struct Handle_Return<const Ret &> : Handle_Return_Ref<const Ret &, std::is_pointer<typename std::remove_reference<const Ret &>::type>::value> {
return Boxed_Value(std::cref(r)); };
}
template<typename Ret>
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) noexcept { return r; }
};
template<>
struct Handle_Return<const Boxed_Value> : Handle_Return<Boxed_Value> {
};
template<>
struct Handle_Return<Boxed_Value &> : Handle_Return<Boxed_Value> {
};
template<>
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<> template<>
struct Handle_Return<Boxed_Value> struct Handle_Return<Boxed_Number> {
{ static Boxed_Value handle(const Boxed_Number &r) noexcept { return r.bv; }
static Boxed_Value handle(const Boxed_Value &r) };
{
return r; template<>
} 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<> template<>
struct Handle_Return<const Boxed_Value> struct Handle_Return<void> {
{ static Boxed_Value handle() { return void_var(); }
static Boxed_Value handle(const Boxed_Value &r)
{
return r;
}
}; };
} // namespace detail
/** } // namespace dispatch
* Used internally for handling a return value from a Proxy_Function call } // namespace chaiscript
*/
template<>
struct Handle_Return<Boxed_Value &>
{
static Boxed_Value handle(const Boxed_Value &r)
{
return r;
}
};
/**
* Used internally for handling a return value from a Proxy_Function call
*/
template<>
struct Handle_Return<const Boxed_Value &>
{
static Boxed_Value handle(const Boxed_Value &r)
{
return r;
}
};
/**
* Used internally for handling a return value from a Proxy_Function call
*/
template<>
struct Handle_Return<Boxed_Number>
{
static Boxed_Value handle(const Boxed_Number &r)
{
return r.bv;
}
};
/**
* Used internally for handling a return value from a Proxy_Function call
*/
template<>
struct Handle_Return<const Boxed_Number>
{
static Boxed_Value handle(const Boxed_Number &r)
{
return r.bv;
}
};
/**
* Used internally for handling a return value from a Proxy_Function call
*/
template<>
struct Handle_Return<void>
{
static Boxed_Value handle()
{
return Boxed_Value(Boxed_Value::Void_Type());
}
};
}
}
}
#endif #endif

View File

@ -1,465 +1,184 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) // Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.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_ #ifndef CHAISCRIPT_OPERATORS_HPP_
#define CHAISCRIPT_OPERATORS_HPP_ #define CHAISCRIPT_OPERATORS_HPP_
#include "../chaiscript_defines.hpp" #include "../chaiscript_defines.hpp"
#include "../dispatchkit/dispatchkit.hpp"
#include "register_function.hpp" #include "register_function.hpp"
namespace chaiscript namespace chaiscript::bootstrap::operators {
{
namespace bootstrap
{
namespace operators
{
namespace detail
{
/// \todo make this return a decltype once we drop gcc 4.6
template<typename L, typename R>
auto assign(L l, R r) -> L&
{
return (l = r);
}
template<typename L, typename R>
auto assign_bitwise_and(L l, R r) -> decltype((l &= r))
{
return (l &= r);
}
template<typename L, typename R>
auto assign_xor(L l, R r) -> decltype((l^=r))
{
return (l ^= r);
}
template<typename L, typename R>
auto assign_bitwise_or(L l, R r) -> decltype((l |= r))
{
return (l |= r);
}
template<typename L, typename R>
auto assign_difference(L l, R r) -> decltype(( l -= r))
{
return (l -= r);
}
template<typename L, typename R>
auto assign_left_shift(L l, R r) -> decltype(( l <<= r))
{
return (l <<= r);
}
template<typename L, typename R>
auto assign_product(L l, R r) -> decltype(( l *= r ))
{
return (l *= r);
}
template<typename L, typename R>
auto assign_quotient(L l, R r) -> decltype(( l /= r ))
{
return (l /= r);
}
template<typename L, typename R>
auto assign_remainder(L l, R r) -> decltype(( l %= r ))
{
return (l %= r);
}
template<typename L, typename R>
auto assign_right_shift(L l, R r) -> decltype(( l >>= r))
{
return (l >>= r);
}
/// \todo make this return a decltype once we drop gcc 4.6
template<typename L, typename R>
auto assign_sum(L l, R r) -> L&
{
return (l += r);
}
template<typename L>
auto prefix_decrement(L l) -> decltype(( --l ))
{
return (--l);
}
template<typename L>
auto prefix_increment(L l) -> decltype(( ++l ))
{
return (++l);
}
template<typename L, typename R>
auto equal(L l, R r) -> decltype(( l == r ))
{
return (l == r);
}
template<typename L, typename R>
auto greater_than(L l, R r) -> decltype(( l > r ))
{
return (l > r);
}
template<typename L, typename R>
auto greater_than_equal(L l, R r) -> decltype(( l >= r ))
{
return (l >= r);
}
template<typename L, typename R>
auto less_than(L l, R r) -> decltype(( l < r ))
{
return (l < r);
}
template<typename L, typename R>
auto less_than_equal(L l, R r) -> decltype(( l <= r ))
{
return (l <= r);
}
template<typename L>
auto logical_compliment(L l) -> decltype(( !l ))
{
return (!l);
}
template<typename L, typename R>
auto not_equal(L l, R r) -> decltype(( l != r ))
{
return (l != r);
}
template<typename L, typename R>
auto addition(L l, R r) -> decltype(( l + r ))
{
return (l + r);
}
template<typename L>
auto unary_plus(L l) -> decltype(( +l ))
{
return (+l);
}
template<typename L, typename R>
auto subtraction(L l, R r) -> decltype(( l - r ))
{
return (l - r);
}
template<typename L>
auto unary_minus(L l) -> decltype(( -l ))
{
#ifdef CHAISCRIPT_MSVC
#pragma warning(push)
#pragma warning(disable : 4146)
return (-l);
#pragma warning(pop)
#else
return (-l);
#endif
}
template<typename L, typename R>
auto bitwise_and(L l, R r) -> decltype(( l & r ))
{
return (l & r);
}
template<typename L>
auto bitwise_compliment(L l) -> decltype(( ~l ))
{
return (~l);
}
template<typename L, typename R>
auto bitwise_xor(L l, R r) -> decltype(( l ^ r ))
{
return (l ^ r);
}
template<typename L, typename R>
auto bitwise_or(L l, R r) -> decltype(( l | r ))
{
return (l | r);
}
template<typename L, typename R>
auto division(L l, R r) -> decltype(( l / r ))
{
return (l / r);
}
template<typename L, typename R>
auto left_shift(L l, R r) -> decltype(( l << r ))
{
return l << r;
}
template<typename L, typename R>
auto multiplication(L l, R r) -> decltype(( l * r ))
{
return l * r;
}
template<typename L, typename R>
auto remainder(L l, R r) -> decltype(( l % r ))
{
return (l % r);
}
template<typename L, typename R>
auto right_shift(L l, R r) -> decltype(( l >> r ))
{
return (l >> r);
}
}
template<typename T> template<typename T>
ModulePtr assign(ModulePtr m = std::make_shared<Module>()) void assign(Module &m) {
{ m.add(chaiscript::fun([](T &lhs, const T &rhs) -> T & { return lhs = rhs; }), "=");
m->add(chaiscript::fun(&detail::assign<T &, const T&>), "=");
return m;
} }
template<typename T> template<typename T>
ModulePtr assign_bitwise_and(ModulePtr m = std::make_shared<Module>()) void assign_bitwise_and(Module &m) {
{ m.add(chaiscript::fun([](T &lhs, const T &rhs) -> T & { return lhs &= rhs; }), "&=");
m->add(chaiscript::fun(&detail::assign_bitwise_and<T &, const T&>), "&=");
return m;
} }
template<typename T> template<typename T>
ModulePtr assign_xor(ModulePtr m = std::make_shared<Module>()) void assign_xor(Module &m) {
{ m.add(chaiscript::fun([](T &lhs, const T &rhs) -> T & { return lhs ^= rhs; }), "^=");
m->add(chaiscript::fun(&detail::assign_xor<T &, const T&>), "^=");
return m;
} }
template<typename T> template<typename T>
ModulePtr assign_bitwise_or(ModulePtr m = std::make_shared<Module>()) void assign_bitwise_or(Module &m) {
{ m.add(chaiscript::fun([](T &lhs, const T &rhs) -> T & { return lhs |= rhs; }), "|=");
m->add(chaiscript::fun(&detail::assign_bitwise_or<T &, const T&>), "|=");
return m;
} }
template<typename T> template<typename T>
ModulePtr assign_difference(ModulePtr m = std::make_shared<Module>()) void assign_difference(Module &m) {
{ m.add(chaiscript::fun([](T &lhs, const T &rhs) -> T & { return lhs -= rhs; }), "-=");
m->add(chaiscript::fun(&detail::assign_difference<T &, const T&>), "-=");
return m;
} }
template<typename T> template<typename T>
ModulePtr assign_left_shift(ModulePtr m = std::make_shared<Module>()) void assign_left_shift(Module &m) {
{ m.add(chaiscript::fun([](T &lhs, const T &rhs) -> T & { return lhs <<= rhs; }), "<<=");
m->add(chaiscript::fun(&detail::assign_left_shift<T &, const T&>), "<<=");
return m;
} }
template<typename T> template<typename T>
ModulePtr assign_product(ModulePtr m = std::make_shared<Module>()) void assign_product(Module &m) {
{ m.add(chaiscript::fun([](T &lhs, const T &rhs) -> T & { return lhs <<= rhs; }), "*=");
m->add(chaiscript::fun(&detail::assign_product<T &, const T&>), "*=");
return m;
} }
template<typename T> template<typename T>
ModulePtr assign_quotient(ModulePtr m = std::make_shared<Module>()) void assign_quotient(Module &m) {
{ m.add(chaiscript::fun([](T &lhs, const T &rhs) -> T & { return lhs /= rhs; }), "/=");
m->add(chaiscript::fun(&detail::assign_quotient<T &, const T&>), "/=");
return m;
} }
template<typename T> template<typename T>
ModulePtr assign_remainder(ModulePtr m = std::make_shared<Module>()) void assign_remainder(Module &m) {
{ m.add(chaiscript::fun([](T &lhs, const T &rhs) -> T & { return lhs %= rhs; }), "%=");
m->add(chaiscript::fun(&detail::assign_remainder<T &, const T&>), "%=");
return m;
} }
template<typename T> template<typename T>
ModulePtr assign_right_shift(ModulePtr m = std::make_shared<Module>()) void assign_right_shift(Module &m) {
{ m.add(chaiscript::fun([](T &lhs, const T &rhs) -> T & { return lhs >>= rhs; }), ">>=");
m->add(chaiscript::fun(&detail::assign_right_shift<T &, const T&>), ">>=");
return m;
} }
template<typename T> template<typename T>
ModulePtr assign_sum(ModulePtr m = std::make_shared<Module>()) void assign_sum(Module &m) {
{ m.add(chaiscript::fun([](T &lhs, const T &rhs) -> T & { return lhs += rhs; }), "+=");
m->add(chaiscript::fun(&detail::assign_sum<T &, const T&>), "+=");
return m;
} }
template<typename T> template<typename T>
ModulePtr prefix_decrement(ModulePtr m = std::make_shared<Module>()) void prefix_decrement(Module &m) {
{ m.add(chaiscript::fun([](T &lhs) -> T & { return --lhs; }), "--");
m->add(chaiscript::fun(&detail::prefix_decrement<T &>), "--");
return m;
} }
template<typename T> template<typename T>
ModulePtr prefix_increment(ModulePtr m = std::make_shared<Module>()) void prefix_increment(Module &m) {
{ m.add(chaiscript::fun([](T &lhs) -> T & { return ++lhs; }), "++");
m->add(chaiscript::fun(&detail::prefix_increment<T &>), "++");
return m;
} }
template<typename T> template<typename T>
ModulePtr equal(ModulePtr m = std::make_shared<Module>()) void equal(Module &m) {
{ m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs == rhs; }), "==");
m->add(chaiscript::fun(&detail::equal<const T&, const T&>), "==");
return m;
} }
template<typename T> template<typename T>
ModulePtr greater_than(ModulePtr m = std::make_shared<Module>()) void greater_than(Module &m) {
{ m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs > rhs; }), ">");
m->add(chaiscript::fun(&detail::greater_than<const T&, const T&>), ">");
return m;
} }
template<typename T> template<typename T>
ModulePtr greater_than_equal(ModulePtr m = std::make_shared<Module>()) void greater_than_equal(Module &m) {
{ m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs >= rhs; }), ">=");
m->add(chaiscript::fun(&detail::greater_than_equal<const T&, const T&>), ">=");
return m;
} }
template<typename T> template<typename T>
ModulePtr less_than(ModulePtr m = std::make_shared<Module>()) void less_than(Module &m) {
{ m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs < rhs; }), "<");
m->add(chaiscript::fun(&detail::less_than<const T&, const T&>), "<");
return m;
} }
template<typename T> template<typename T>
ModulePtr less_than_equal(ModulePtr m = std::make_shared<Module>()) void less_than_equal(Module &m) {
{ m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs <= rhs; }), "<=");
m->add(chaiscript::fun(&detail::less_than_equal<const T&, const T&>), "<=");
return m;
} }
template<typename T> template<typename T>
ModulePtr logical_compliment(ModulePtr m = std::make_shared<Module>()) void logical_compliment(Module &m) {
{ m.add(chaiscript::fun([](const T &lhs) { return !lhs; }), "!");
m->add(chaiscript::fun(&detail::logical_compliment<const T &>), "!");
return m;
} }
template<typename T> template<typename T>
ModulePtr not_equal(ModulePtr m = std::make_shared<Module>()) void not_equal(Module &m) {
{ m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs != rhs; }), "!=");
m->add(chaiscript::fun(&detail::not_equal<const T &, const T &>), "!=");
return m;
} }
template<typename T> template<typename T>
ModulePtr addition(ModulePtr m = std::make_shared<Module>()) void addition(Module &m) {
{ m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs + rhs; }), "+");
m->add(chaiscript::fun(&detail::addition<const T &, const T &>), "+");
return m;
} }
template<typename T> template<typename T>
ModulePtr unary_plus(ModulePtr m = std::make_shared<Module>()) void unary_plus(Module &m) {
{ m.add(chaiscript::fun([](const T &lhs) { return +lhs; }), "+");
m->add(chaiscript::fun(&detail::unary_plus<const T &>), "+");
return m;
} }
template<typename T> template<typename T>
ModulePtr subtraction(ModulePtr m = std::make_shared<Module>()) void subtraction(Module &m) {
{ m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs - rhs; }), "-");
m->add(chaiscript::fun(&detail::subtraction<const T &, const T &>), "-");
return m;
} }
template<typename T> template<typename T>
ModulePtr unary_minus(ModulePtr m = std::make_shared<Module>()) void unary_minus(Module &m) {
{ m.add(chaiscript::fun([](const T &lhs) { return -lhs; }), "-");
m->add(chaiscript::fun(&detail::unary_minus<const T &>), "-");
return m;
} }
template<typename T> template<typename T>
ModulePtr bitwise_and(ModulePtr m = std::make_shared<Module>()) void bitwise_and(Module &m) {
{ m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs & rhs; }), "&");
m->add(chaiscript::fun(&detail::bitwise_and<const T &, const T &>), "&");
return m;
} }
template<typename T> template<typename T>
ModulePtr bitwise_compliment(ModulePtr m = std::make_shared<Module>()) void bitwise_compliment(Module &m) {
{ m.add(chaiscript::fun([](const T &lhs) { return ~lhs; }), "~");
m->add(chaiscript::fun(&detail::bitwise_compliment<const T &>), "~");
return m;
} }
template<typename T> template<typename T>
ModulePtr bitwise_xor(ModulePtr m = std::make_shared<Module>()) void bitwise_xor(Module &m) {
{ m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs ^ rhs; }), "^");
m->add(chaiscript::fun(&detail::bitwise_xor<const T &, const T &>), "^");
return m;
} }
template<typename T> template<typename T>
ModulePtr bitwise_or(ModulePtr m = std::make_shared<Module>()) void bitwise_or(Module &m) {
{ m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs | rhs; }), "|");
m->add(chaiscript::fun(&detail::bitwise_or<const T &, const T &>), "|");
return m;
} }
template<typename T> template<typename T>
ModulePtr division(ModulePtr m = std::make_shared<Module>()) void division(Module &m) {
{ m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs / rhs; }), "/");
m->add(chaiscript::fun(&detail::division<const T &, const T &>), "/");
return m;
} }
template<typename T> template<typename T>
ModulePtr left_shift(ModulePtr m = std::make_shared<Module>()) void left_shift(Module &m) {
{ m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs << rhs; }), "<<");
m->add(chaiscript::fun(&detail::left_shift<const T &, const T &>), "<<");
return m;
} }
template<typename T> template<typename T>
ModulePtr multiplication(ModulePtr m = std::make_shared<Module>()) void multiplication(Module &m) {
{ m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs * rhs; }), "*");
m->add(chaiscript::fun(&detail::multiplication<const T &, const T &>), "*");
return m;
} }
template<typename T> template<typename T>
ModulePtr remainder(ModulePtr m = std::make_shared<Module>()) void remainder(Module &m) {
{ m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs % rhs; }), "%");
m->add(chaiscript::fun(&detail::remainder<const T &, const T &>), "%");
return m;
} }
template<typename T> template<typename T>
ModulePtr right_shift(ModulePtr m = std::make_shared<Module>()) void right_shift(Module &m) {
{ m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs >> rhs; }), ">>");
m->add(chaiscript::fun(&detail::right_shift<const T &, const T &>), ">>");
return m;
} }
} } // namespace chaiscript::bootstrap::operators
}
}
#endif #endif

View File

@ -1,34 +1,37 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) // Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.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_ #ifndef CHAISCRIPT_PROXY_CONSTRUCTORS_HPP_
#define CHAISCRIPT_PROXY_CONSTRUCTORS_HPP_ #define CHAISCRIPT_PROXY_CONSTRUCTORS_HPP_
#include "proxy_functions.hpp" #include "proxy_functions.hpp"
namespace chaiscript namespace chaiscript::dispatch::detail {
{ template<typename Class, typename... Params>
namespace dispatch Proxy_Function build_constructor_(Class (*)(Params...)) {
{ if constexpr (!std::is_copy_constructible_v<Class>) {
namespace detail 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( return Proxy_Function(
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<std::shared_ptr<Class> (Params...), decltype(call)>>(call)); 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<Class(Params...), decltype(call)>>(
call));
}
}
} // namespace chaiscript::dispatch::detail
namespace chaiscript {
/// \brief Generates a constructor function for use with 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, ...) /// \tparam T The signature of the constructor to generate. In the form of: ClassType (ParamType1, ParamType2, ...)
@ -41,13 +44,10 @@ namespace chaiscript
/// chai.add(constructor<MyClass (int, float)>(), "MyClass"); /// chai.add(constructor<MyClass (int, float)>(), "MyClass");
/// \endcode /// \endcode
template<typename T> template<typename T>
Proxy_Function constructor() Proxy_Function constructor() {
{
T *f = nullptr; T *f = nullptr;
return (dispatch::detail::build_constructor_(f)); return (dispatch::detail::build_constructor_(f));
} }
} // namespace chaiscript
}
#endif #endif

File diff suppressed because it is too large Load Diff

View File

@ -1,12 +1,16 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) // Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.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_ #ifndef CHAISCRIPT_PROXY_FUNCTIONS_DETAIL_HPP_
#define CHAISCRIPT_PROXY_FUNCTIONS_DETAIL_HPP_ #define CHAISCRIPT_PROXY_FUNCTIONS_DETAIL_HPP_
#include <array>
#include <functional> #include <functional>
#include <stdexcept> #include <stdexcept>
#include <vector> #include <vector>
@ -14,262 +18,94 @@
#include "../chaiscript_defines.hpp" #include "../chaiscript_defines.hpp"
#include "boxed_cast.hpp" #include "boxed_cast.hpp"
#include "boxed_value.hpp" #include "boxed_value.hpp"
#include "function_params.hpp"
#include "handle_return.hpp" #include "handle_return.hpp"
#include "type_info.hpp" #include "type_info.hpp"
#include "callable_traits.hpp"
namespace chaiscript { namespace chaiscript {
class Type_Conversions; class Type_Conversions_State;
namespace exception { namespace exception {
class bad_boxed_cast; class bad_boxed_cast;
} // namespace exception } // namespace exception
} // namespace chaiscript } // namespace chaiscript
namespace chaiscript namespace chaiscript {
{ namespace exception {
namespace exception
{
/** /**
* Exception thrown when there is a mismatch in number of * Exception thrown when there is a mismatch in number of
* parameters during Proxy_Function execution * parameters during Proxy_Function execution
*/ */
struct arity_error : std::range_error struct arity_error : std::range_error {
{
arity_error(int t_got, int t_expected) arity_error(int t_got, int t_expected)
: std::range_error("Function dispatch arity mismatch"), : std::range_error("Function dispatch arity mismatch")
got(t_got), expected(t_expected) , got(t_got)
{ , expected(t_expected) {
} }
arity_error(const arity_error &) = default; arity_error(const arity_error &) = default;
virtual ~arity_error() CHAISCRIPT_NOEXCEPT {} ~arity_error() noexcept override = default;
int got; int got;
int expected; int expected;
}; };
} } // namespace exception
namespace dispatch namespace dispatch {
{ namespace detail {
namespace detail
{
/** /**
* Used by Proxy_Function_Impl to return a list of all param types * Used by Proxy_Function_Impl to return a list of all param types
* it contains. * it contains.
*/ */
template<typename Ret, typename ... Params> template<typename Ret, typename... Params>
std::vector<Type_Info> build_param_type_list(Ret (*)(Params...)) std::vector<Type_Info> build_param_type_list(Ret (*)(Params...)) {
{
/// \note somehow this is responsible for a large part of the code generation /// \note somehow this is responsible for a large part of the code generation
return { user_type<Ret>(), user_type<Params>()... }; return {user_type<Ret>(), user_type<Params>()...};
} }
#ifdef CHAISCRIPT_GCC_4_6
/// \todo REMOVE THIS WHEN WE DROP G++4.6
// Forward declaration
template<typename ... Rest>
struct Try_Cast;
template<typename Param, typename ... Rest>
struct Try_Cast<Param, Rest...>
{
static void do_try(const std::vector<Boxed_Value> &params, size_t generation, const Type_Conversions &t_conversions)
{
boxed_cast<Param>(params[generation], &t_conversions);
Try_Cast<Rest...>::do_try(params, generation+1, t_conversions);
}
};
// 0th case
template<>
struct Try_Cast<>
{
static void do_try(const std::vector<Boxed_Value> &, size_t, const Type_Conversions &)
{
}
};
/** /**
* Used by Proxy_Function_Impl to determine if it is equivalent to another * Used by Proxy_Function_Impl to determine if it is equivalent to another
* Proxy_Function_Impl object. This function is primarily used to prevent * Proxy_Function_Impl object. This function is primarily used to prevent
* registration of two functions with the exact same signatures * registration of two functions with the exact same signatures
*/ */
template<typename Ret, typename ... Params> template<typename Ret, typename... Params>
bool compare_types_cast(Ret (*)(Params...), bool compare_types_cast(Ret (*)(Params...), const chaiscript::Function_Params &params, const Type_Conversions_State &t_conversions) noexcept {
const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions)
{
try { try {
Try_Cast<Params...>::do_try(params, 0, t_conversions); std::vector<Boxed_Value>::size_type i = 0;
} catch (const exception::bad_boxed_cast &) { (boxed_cast<Params>(params[i++], &t_conversions), ...);
return false;
}
return true;
}
template<typename Ret, int count, typename ... Params>
struct Call_Func
{
template<typename Callable, typename ... InnerParams>
static Ret do_call(const Callable &f,
const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions, InnerParams &&... innerparams)
{
return Call_Func<Ret, count - 1, Params...>::do_call(f, params, t_conversions, std::forward<InnerParams>(innerparams)..., params[sizeof...(Params) - count]);
}
};
template<typename Ret, typename ... Params>
struct Call_Func<Ret, 0, Params...>
{
#ifdef CHAISCRIPT_MSVC
#pragma warning(push)
#pragma warning(disable : 4100) /// Disable unreferenced formal parameter warning, which only shows up in MSVC I don't think there's any way around it \todo evaluate this
#endif
template<typename Callable, typename ... InnerParams>
static Ret do_call(const Callable &f,
const std::vector<Boxed_Value> &, const Type_Conversions &t_conversions, InnerParams &&... innerparams)
{
return f(boxed_cast<Params>(std::forward<InnerParams>(innerparams), &t_conversions)...);
}
#ifdef CHAISCRIPT_MSVC
#pragma warning(pop)
#endif
};
/**
* Used by Proxy_Function_Impl to perform typesafe execution of a function.
* The function attempts to unbox each parameter to the expected type.
* if any unboxing fails the execution of the function fails and
* the bad_boxed_cast is passed up to the caller.
*/
template<typename Callable, typename Ret, typename ... Params>
Ret call_func(const chaiscript::dispatch::detail::Function_Signature<Ret (Params...)> &, const Callable &f,
const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions)
{
if (params.size() == sizeof...(Params))
{
return Call_Func<Ret, sizeof...(Params), Params...>::do_call(f, params, t_conversions);
}
throw exception::arity_error(static_cast<int>(params.size()), sizeof...(Params));
}
#else
template<size_t ... I>
struct Indexes
{
};
template<size_t S, size_t ... I>
struct Make_Indexes
{
typedef typename Make_Indexes<S-1, I..., sizeof...(I)>::indexes indexes;
};
template<size_t ... I>
struct Make_Indexes<0, I...>
{
typedef Indexes<I...> indexes;
};
/**
* Used by Proxy_Function_Impl to determine if it is equivalent to another
* Proxy_Function_Impl object. This function is primarily used to prevent
* registration of two functions with the exact same signatures
*/
template<typename Ret, typename ... Params, size_t ... I>
bool compare_types_cast(Indexes<I...>, Ret (*)(Params...),
const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions)
{
try {
(void)params; (void)t_conversions;
(void)std::initializer_list<int>{(boxed_cast<Params>(params[I], &t_conversions), 0)...};
return true; return true;
} catch (const exception::bad_boxed_cast &) { } catch (const exception::bad_boxed_cast &) {
return false; return false;
} }
} }
template<typename Ret, typename ... Params> template<typename Callable, typename Ret, typename... Params, size_t... I>
bool compare_types_cast(Ret (*f)(Params...), Ret call_func(Ret (*)(Params...),
const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions) std::index_sequence<I...>,
{ const Callable &f,
typedef typename Make_Indexes<sizeof...(Params)>::indexes indexes; [[maybe_unused]] const chaiscript::Function_Params &params,
return compare_types_cast(indexes(), f, params, t_conversions); [[maybe_unused]] const Type_Conversions_State &t_conversions) {
}
template<typename Callable, typename Ret, typename ... Params, size_t ... I>
Ret call_func(const chaiscript::dispatch::detail::Function_Signature<Ret (Params...)> &, Indexes<I...>, const Callable &f,
const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions)
{
(void)params; (void)t_conversions;
return f(boxed_cast<Params>(params[I], &t_conversions)...); 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.
* Used by Proxy_Function_Impl to perform typesafe execution of a function. /// if any unboxing fails the execution of the function fails and
* The function attempts to unbox each parameter to the expected type. /// the bad_boxed_cast is passed up to the caller.
* if any unboxing fails the execution of the function fails and template<typename Callable, typename Ret, typename... Params>
* the bad_boxed_cast is passed up to the caller. Boxed_Value
*/ call_func(Ret (*sig)(Params...), const Callable &f, const chaiscript::Function_Params &params, const Type_Conversions_State &t_conversions) {
template<typename Callable, typename Ret, typename ... Params> if constexpr (std::is_same_v<Ret, void>) {
Ret call_func(const chaiscript::dispatch::detail::Function_Signature<Ret (Params...)> &sig, const Callable &f, call_func(sig, std::index_sequence_for<Params...>{}, f, params, t_conversions);
const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions)
{
typedef typename Make_Indexes<sizeof...(Params)>::indexes indexes;
return call_func(sig, indexes(), f, params, t_conversions);
}
#endif
}
}
}
namespace chaiscript
{
namespace dispatch
{
namespace detail
{
template<typename Ret>
struct Do_Call
{
template<typename Signature, typename Callable>
static Boxed_Value go(const Callable &fun, const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions)
{
return Handle_Return<Ret>::handle(call_func(Function_Signature<Signature>(), fun, params, t_conversions));
}
};
template<>
struct Do_Call<void>
{
template<typename Signature, typename Callable>
static Boxed_Value go(const Callable &fun, const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions)
{
call_func(Function_Signature<Signature>(), fun, params, t_conversions);
return Handle_Return<void>::handle(); return Handle_Return<void>::handle();
} } else {
}; return Handle_Return<Ret>::handle(call_func(sig, std::index_sequence_for<Params...>{}, f, params, t_conversions));
} }
} }
}
} // namespace detail
} // namespace dispatch
} // namespace chaiscript
#endif #endif

View File

@ -1,19 +1,61 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) // Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.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_ #ifndef CHAISCRIPT_REGISTER_FUNCTION_HPP_
#define CHAISCRIPT_REGISTER_FUNCTION_HPP_ #define CHAISCRIPT_REGISTER_FUNCTION_HPP_
#include <type_traits> #include <type_traits>
#include "bind_first.hpp" #include "bind_first.hpp"
#include "function_signature.hpp"
#include "proxy_functions.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 /// \brief Creates a new Proxy_Function object from a free function, member function or data member
/// \param[in] t Function / member to expose /// \param[in] t Function / member to expose
@ -36,53 +78,10 @@ namespace chaiscript
/// ///
/// \sa \ref adding_functions /// \sa \ref adding_functions
template<typename T> template<typename T>
Proxy_Function fun(const T &t) Proxy_Function fun(T &&t) {
{ return dispatch::detail::make_callable(std::forward<T>(t), dispatch::detail::function_signature(t));
typedef typename dispatch::detail::Callable_Traits<T>::Signature Signature;
return Proxy_Function(
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Signature, T>>(t));
} }
template<typename Ret, typename ... Param>
Proxy_Function fun(Ret (*func)(Param...))
{
auto fun_call = dispatch::detail::Fun_Caller<Ret, Param...>(func);
return Proxy_Function(
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Ret (Param...), decltype(fun_call)>>(fun_call));
}
template<typename Ret, typename Class, typename ... Param>
Proxy_Function fun(Ret (Class::*t_func)(Param...) const)
{
auto call = dispatch::detail::Const_Caller<Ret, Class, Param...>(t_func);
return Proxy_Function(
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Ret (const Class &, Param...), decltype(call)>>(call));
}
template<typename Ret, typename Class, typename ... Param>
Proxy_Function fun(Ret (Class::*t_func)(Param...))
{
auto call = dispatch::detail::Caller<Ret, Class, Param...>(t_func);
return Proxy_Function(
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Ret (Class &, Param...), decltype(call)>>(call));
}
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 /// \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] t Function / member to expose
/// \param[in] q Value to bind to first parameter /// \param[in] q Value to bind to first parameter
@ -102,39 +101,10 @@ namespace chaiscript
/// ///
/// \sa \ref adding_functions /// \sa \ref adding_functions
template<typename T, typename Q> template<typename T, typename Q>
Proxy_Function fun(T &&t, const Q &q) Proxy_Function fun(T &&t, const Q &q) {
{
return fun(detail::bind_first(std::forward<T>(t), q)); return fun(detail::bind_first(std::forward<T>(t), q));
} }
/// \brief Creates a new Proxy_Function object from a free function or member function and binds the first and second parameters of it } // namespace chaiscript
/// \param[in] t Function / member to expose
/// \param[in] q Value to bind to first parameter
/// \param[in] r Value to bind to second parameter
///
/// \b Example:
/// \code
/// struct MyClass
/// {
/// void memberfunction(int);
/// };
///
/// MyClass obj;
/// chaiscript::ChaiScript chai;
/// // Add function taking only no arguments, and permanently bound to "obj" and "1"
/// // memberfunction() will be equivalent to obj.memberfunction(1)
/// chai.add(fun(&MyClass::memberfunction, std::ref(obj), 1), "memberfunction");
/// \endcode
///
/// \sa \ref adding_functions
template<typename T, typename Q, typename R>
Proxy_Function fun(T &&t, Q &&q, R &&r)
{
return fun(detail::bind_first(detail::bind_first(std::forward<T>(t), std::forward<Q>(q)), std::forward<R>(r)));
}
}
#endif #endif

View File

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

View File

@ -1,12 +1,16 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) // Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_DYNAMIC_CAST_CONVERSION_HPP_ #ifndef CHAISCRIPT_DYNAMIC_CAST_CONVERSION_HPP_
#define CHAISCRIPT_DYNAMIC_CAST_CONVERSION_HPP_ #define CHAISCRIPT_DYNAMIC_CAST_CONVERSION_HPP_
#include <algorithm>
#include <atomic> #include <atomic>
#include <memory> #include <memory>
#include <set> #include <set>
@ -16,141 +20,116 @@
#include <typeinfo> #include <typeinfo>
#include "../chaiscript_threading.hpp" #include "../chaiscript_threading.hpp"
#include "../utility/static_string.hpp"
#include "bad_boxed_cast.hpp" #include "bad_boxed_cast.hpp"
#include "boxed_cast_helper.hpp" #include "boxed_cast_helper.hpp"
#include "boxed_value.hpp" #include "boxed_value.hpp"
#include "type_info.hpp" #include "type_info.hpp"
namespace chaiscript namespace chaiscript {
{ namespace exception {
namespace exception /// \brief Error thrown when there's a problem with type conversion
{ class conversion_error : public bad_boxed_cast {
class bad_boxed_dynamic_cast : public bad_boxed_cast
{
public: public:
bad_boxed_dynamic_cast(const Type_Info &t_from, const std::type_info &t_to, conversion_error(const Type_Info t_to, const Type_Info t_from, const utility::Static_String what) noexcept
const std::string &t_what) CHAISCRIPT_NOEXCEPT : bad_boxed_cast(t_from, (*t_to.bare_type_info()), what)
: bad_boxed_cast(t_from, t_to, t_what) , type_to(t_to) {
{
} }
bad_boxed_dynamic_cast(const Type_Info &t_from, const std::type_info &t_to) CHAISCRIPT_NOEXCEPT Type_Info type_to;
: bad_boxed_cast(t_from, t_to) };
{
class bad_boxed_dynamic_cast : public bad_boxed_cast {
public:
bad_boxed_dynamic_cast(const Type_Info &t_from, const std::type_info &t_to, const utility::Static_String &t_what) noexcept
: bad_boxed_cast(t_from, t_to, t_what) {
} }
bad_boxed_dynamic_cast(const std::string &w) CHAISCRIPT_NOEXCEPT bad_boxed_dynamic_cast(const Type_Info &t_from, const std::type_info &t_to) noexcept
: bad_boxed_cast(w) : bad_boxed_cast(t_from, t_to) {
{ }
explicit bad_boxed_dynamic_cast(const utility::Static_String &w) noexcept
: bad_boxed_cast(w) {
} }
bad_boxed_dynamic_cast(const bad_boxed_dynamic_cast &) = default; bad_boxed_dynamic_cast(const bad_boxed_dynamic_cast &) = default;
virtual ~bad_boxed_dynamic_cast() CHAISCRIPT_NOEXCEPT {} ~bad_boxed_dynamic_cast() noexcept override = default;
}; };
class bad_boxed_type_cast : public bad_boxed_cast class bad_boxed_type_cast : public bad_boxed_cast {
{
public: public:
bad_boxed_type_cast(const Type_Info &t_from, const std::type_info &t_to, bad_boxed_type_cast(const Type_Info &t_from, const std::type_info &t_to, const utility::Static_String &t_what) noexcept
const std::string &t_what) CHAISCRIPT_NOEXCEPT : bad_boxed_cast(t_from, t_to, t_what) {
: bad_boxed_cast(t_from, t_to, t_what)
{
} }
bad_boxed_type_cast(const Type_Info &t_from, const std::type_info &t_to) CHAISCRIPT_NOEXCEPT bad_boxed_type_cast(const Type_Info &t_from, const std::type_info &t_to) noexcept
: bad_boxed_cast(t_from, t_to) : bad_boxed_cast(t_from, t_to) {
{
} }
bad_boxed_type_cast(const std::string &w) CHAISCRIPT_NOEXCEPT explicit bad_boxed_type_cast(const utility::Static_String &w) noexcept
: bad_boxed_cast(w) : bad_boxed_cast(w) {
{
} }
bad_boxed_type_cast(const bad_boxed_type_cast &) = default; bad_boxed_type_cast(const bad_boxed_type_cast &) = default;
virtual ~bad_boxed_type_cast() CHAISCRIPT_NOEXCEPT {} ~bad_boxed_type_cast() noexcept override = default;
}; };
} } // namespace exception
namespace detail {
namespace detail class Type_Conversion_Base {
{
class Type_Conversion_Base
{
public: public:
virtual Boxed_Value convert(const Boxed_Value &from) const = 0; virtual Boxed_Value convert(const Boxed_Value &from) const = 0;
virtual Boxed_Value convert_down(const Boxed_Value &to) const = 0; virtual Boxed_Value convert_down(const Boxed_Value &to) const = 0;
const Type_Info &to() const const Type_Info &to() const noexcept { return m_to; }
{ const Type_Info &from() const noexcept { return m_from; }
return m_to;
}
const Type_Info &from() const
{
return m_from;
}
virtual bool bidir() const virtual bool bidir() const noexcept { return true; }
{
return true;
}
virtual ~Type_Conversion_Base() {} virtual ~Type_Conversion_Base() = default;
protected: protected:
Type_Conversion_Base(const Type_Info &t_to, const Type_Info &t_from) Type_Conversion_Base(Type_Info t_to, Type_Info t_from)
: m_to(t_to), m_from(t_from) : m_to(std::move(t_to))
{ , m_from(std::move(t_from)) {
} }
private: private:
Type_Info m_to; const Type_Info m_to;
Type_Info m_from; const Type_Info m_from;
}; };
template<typename From, typename To> template<typename From, typename To>
class Static_Caster class Static_Caster {
{
public: public:
static Boxed_Value cast(const Boxed_Value &t_from) static Boxed_Value cast(const Boxed_Value &t_from) {
{ if (t_from.get_type_info().bare_equal(chaiscript::user_type<From>())) {
if (t_from.get_type_info().bare_equal(chaiscript::user_type<From>())) if (t_from.is_pointer()) {
{
if (t_from.is_pointer())
{
// Dynamic cast out the contained boxed value, which we know is the type we want // Dynamic cast out the contained boxed value, which we know is the type we want
if (t_from.is_const()) if (t_from.is_const()) {
{ return Boxed_Value([&]() {
return Boxed_Value( if (auto data
[&]()->std::shared_ptr<const To>{ = std::static_pointer_cast<const To>(detail::Cast_Helper<std::shared_ptr<const From>>::cast(t_from, nullptr))) {
if (auto data = std::static_pointer_cast<const To>(detail::Cast_Helper<std::shared_ptr<const From> >::cast(t_from, nullptr)))
{
return data; return data;
} else { } else {
throw std::bad_cast(); throw std::bad_cast();
} }
}() }());
);
} else { } else {
return Boxed_Value( return Boxed_Value([&]() {
[&]()->std::shared_ptr<To>{ if (auto data = std::static_pointer_cast<To>(detail::Cast_Helper<std::shared_ptr<From>>::cast(t_from, nullptr))) {
if (auto data = std::static_pointer_cast<To>(detail::Cast_Helper<std::shared_ptr<From> >::cast(t_from, nullptr)))
{
return data; return data;
} else { } else {
throw std::bad_cast(); throw std::bad_cast();
} }
}() }());
);
} }
} else { } else {
// Pull the reference out of the contained boxed value, which we know is the type we want // Pull the reference out of the contained boxed value, which we know is the type we want
if (t_from.is_const()) if (t_from.is_const()) {
{
const From &d = detail::Cast_Helper<const From &>::cast(t_from, nullptr); const From &d = detail::Cast_Helper<const From &>::cast(t_from, nullptr);
const To &data = static_cast<const To &>(d); const To &data = static_cast<const To &>(d);
return Boxed_Value(std::cref(data)); return Boxed_Value(std::cref(data));
@ -164,44 +143,33 @@ namespace chaiscript
throw chaiscript::exception::bad_boxed_dynamic_cast(t_from.get_type_info(), typeid(To), "Unknown dynamic_cast_conversion"); throw chaiscript::exception::bad_boxed_dynamic_cast(t_from.get_type_info(), typeid(To), "Unknown dynamic_cast_conversion");
} }
} }
}; };
template<typename From, typename To> template<typename From, typename To>
class Dynamic_Caster class Dynamic_Caster {
{
public: public:
static Boxed_Value cast(const Boxed_Value &t_from) static Boxed_Value cast(const Boxed_Value &t_from) {
{ if (t_from.get_type_info().bare_equal(chaiscript::user_type<From>())) {
if (t_from.get_type_info().bare_equal(chaiscript::user_type<From>())) if (t_from.is_pointer()) {
{
if (t_from.is_pointer())
{
// Dynamic cast out the contained boxed value, which we know is the type we want // Dynamic cast out the contained boxed value, which we know is the type we want
if (t_from.is_const()) if (t_from.is_const()) {
{ return Boxed_Value([&]() {
return Boxed_Value( if (auto data
[&]()->std::shared_ptr<const To>{ = std::dynamic_pointer_cast<const To>(detail::Cast_Helper<std::shared_ptr<const From>>::cast(t_from, nullptr))) {
if (auto data = std::dynamic_pointer_cast<const To>(detail::Cast_Helper<std::shared_ptr<const From> >::cast(t_from, nullptr)))
{
return data; return data;
} else { } else {
throw std::bad_cast(); throw std::bad_cast();
} }
}() }());
);
} else { } else {
return Boxed_Value( return Boxed_Value([&]() {
[&]()->std::shared_ptr<To>{ if (auto data = std::dynamic_pointer_cast<To>(detail::Cast_Helper<std::shared_ptr<From>>::cast(t_from, nullptr))) {
if (auto data = std::dynamic_pointer_cast<To>(detail::Cast_Helper<std::shared_ptr<From> >::cast(t_from, nullptr)))
{
return data; return data;
} else { } else {
#ifdef CHAISCRIPT_LIBCPP #ifdef CHAISCRIPT_LIBCPP
/// \todo fix this someday after libc++ is fixed. /// \todo fix this someday after libc++ is fixed.
if (std::string(typeid(To).name()).find("Assignable_Proxy_Function") != std::string::npos) { if (std::string(typeid(To).name()).find("Assignable_Proxy_Function") != std::string::npos) {
auto from = detail::Cast_Helper<std::shared_ptr<From> >::cast(t_from, nullptr); auto from = detail::Cast_Helper<std::shared_ptr<From>>::cast(t_from, nullptr);
if (std::string(typeid(*from).name()).find("Assignable_Proxy_Function_Impl") != std::string::npos) { if (std::string(typeid(*from).name()).find("Assignable_Proxy_Function_Impl") != std::string::npos) {
return std::static_pointer_cast<To>(from); return std::static_pointer_cast<To>(from);
} }
@ -209,13 +177,11 @@ namespace chaiscript
#endif #endif
throw std::bad_cast(); throw std::bad_cast();
} }
}() }());
);
} }
} else { } else {
// Pull the reference out of the contained boxed value, which we know is the type we want // Pull the reference out of the contained boxed value, which we know is the type we want
if (t_from.is_const()) if (t_from.is_const()) {
{
const From &d = detail::Cast_Helper<const From &>::cast(t_from, nullptr); const From &d = detail::Cast_Helper<const From &>::cast(t_from, nullptr);
const To &data = dynamic_cast<const To &>(d); const To &data = dynamic_cast<const To &>(d);
return Boxed_Value(std::cref(data)); return Boxed_Value(std::cref(data));
@ -229,127 +195,91 @@ namespace chaiscript
throw chaiscript::exception::bad_boxed_dynamic_cast(t_from.get_type_info(), typeid(To), "Unknown dynamic_cast_conversion"); throw chaiscript::exception::bad_boxed_dynamic_cast(t_from.get_type_info(), typeid(To), "Unknown dynamic_cast_conversion");
} }
} }
}; };
template<typename Base, typename Derived> template<typename Base, typename Derived>
class Dynamic_Conversion_Impl : public Type_Conversion_Base class Dynamic_Conversion_Impl : public Type_Conversion_Base {
{
public: public:
Dynamic_Conversion_Impl() Dynamic_Conversion_Impl()
: Type_Conversion_Base(chaiscript::user_type<Base>(), chaiscript::user_type<Derived>()) : Type_Conversion_Base(chaiscript::user_type<Base>(), chaiscript::user_type<Derived>()) {
{
} }
virtual Boxed_Value convert_down(const Boxed_Value &t_base) const CHAISCRIPT_OVERRIDE Boxed_Value convert_down(const Boxed_Value &t_base) const override { return Dynamic_Caster<Base, Derived>::cast(t_base); }
{
return Dynamic_Caster<Base, Derived>::cast(t_base);
}
virtual Boxed_Value convert(const Boxed_Value &t_derived) const CHAISCRIPT_OVERRIDE Boxed_Value convert(const Boxed_Value &t_derived) const override { return Static_Caster<Derived, Base>::cast(t_derived); }
{
return Static_Caster<Derived, Base>::cast(t_derived);
}
}; };
template<typename Base, typename Derived> template<typename Base, typename Derived>
class Static_Conversion_Impl : public Type_Conversion_Base class Static_Conversion_Impl : public Type_Conversion_Base {
{
public: public:
Static_Conversion_Impl() Static_Conversion_Impl()
: Type_Conversion_Base(chaiscript::user_type<Base>(), chaiscript::user_type<Derived>()) : Type_Conversion_Base(chaiscript::user_type<Base>(), chaiscript::user_type<Derived>()) {
{
} }
virtual Boxed_Value convert_down(const Boxed_Value &t_base) const CHAISCRIPT_OVERRIDE Boxed_Value convert_down(const Boxed_Value &t_base) const override {
{ throw chaiscript::exception::bad_boxed_dynamic_cast(t_base.get_type_info(),
throw chaiscript::exception::bad_boxed_dynamic_cast(t_base.get_type_info(), typeid(Derived), "Unable to cast down inheritance hierarchy with non-polymorphic types"); typeid(Derived),
"Unable to cast down inheritance hierarchy with non-polymorphic types");
} }
virtual bool bidir() const CHAISCRIPT_OVERRIDE bool bidir() const noexcept override { return false; }
{
return false;
}
virtual Boxed_Value convert(const Boxed_Value &t_derived) const CHAISCRIPT_OVERRIDE Boxed_Value convert(const Boxed_Value &t_derived) const override { return Static_Caster<Derived, Base>::cast(t_derived); }
{
return Static_Caster<Derived, Base>::cast(t_derived);
}
}; };
template<typename Callable> template<typename Callable>
class Type_Conversion_Impl : public Type_Conversion_Base class Type_Conversion_Impl : public Type_Conversion_Base {
{
public: public:
Type_Conversion_Impl(Type_Info t_from, Type_Info t_to, Callable t_func) Type_Conversion_Impl(Type_Info t_from, Type_Info t_to, Callable t_func)
: Type_Conversion_Base(std::move(t_to), std::move(t_from)), : Type_Conversion_Base(t_to, t_from)
m_func(std::move(t_func)) , m_func(std::move(t_func)) {
{
} }
virtual Boxed_Value convert_down(const Boxed_Value &) const CHAISCRIPT_OVERRIDE Boxed_Value convert_down(const Boxed_Value &) const override {
{
throw chaiscript::exception::bad_boxed_type_cast("No conversion exists"); throw chaiscript::exception::bad_boxed_type_cast("No conversion exists");
} }
virtual Boxed_Value convert(const Boxed_Value &t_from) const CHAISCRIPT_OVERRIDE Boxed_Value convert(const Boxed_Value &t_from) const override {
{
/// \todo better handling of errors from the conversion function /// \todo better handling of errors from the conversion function
return m_func(t_from); return m_func(t_from);
} }
virtual bool bidir() const CHAISCRIPT_OVERRIDE bool bidir() const noexcept override { return false; }
{
return false;
}
private: private:
Callable m_func; Callable m_func;
}; };
} // namespace detail
} class Type_Conversions {
class Type_Conversions
{
public: public:
struct Less_Than struct Conversion_Saves {
{ bool enabled = false;
bool operator()(const std::type_info *t_lhs, const std::type_info *t_rhs) const std::vector<Boxed_Value> saves;
{ };
struct Less_Than {
bool operator()(const std::type_info *t_lhs, const std::type_info *t_rhs) const noexcept {
return *t_lhs != *t_rhs && t_lhs->before(*t_rhs); return *t_lhs != *t_rhs && t_lhs->before(*t_rhs);
} }
}; };
Type_Conversions() Type_Conversions()
: m_mutex(), : m_mutex()
m_conversions(), , m_conversions()
m_convertableTypes(), , m_convertableTypes()
m_num_types(0), , m_num_types(0) {
m_thread_cache(this),
m_conversion_saves(this)
{
} }
Type_Conversions(const Type_Conversions &t_other) Type_Conversions(const Type_Conversions &t_other) = delete;
: m_mutex(), Type_Conversions(Type_Conversions &&) = delete;
m_conversions(t_other.get_conversions()),
m_convertableTypes(t_other.m_convertableTypes),
m_num_types(m_conversions.size()),
m_thread_cache(this),
m_conversion_saves(this)
{ Type_Conversions &operator=(const Type_Conversions &) = delete;
} Type_Conversions &operator=(Type_Conversions &&) = delete;
const std::set<const std::type_info *, Less_Than> &thread_cache() const const std::set<const std::type_info *, Less_Than> &thread_cache() const {
{
auto &cache = *m_thread_cache; auto &cache = *m_thread_cache;
if (cache.size() != m_num_types) if (cache.size() != m_num_types) {
{
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex); chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
cache = m_convertableTypes; cache = m_convertableTypes;
} }
@ -357,142 +287,125 @@ namespace chaiscript
return cache; return cache;
} }
void add_conversion(const std::shared_ptr<detail::Type_Conversion_Base> &conversion) void add_conversion(const std::shared_ptr<detail::Type_Conversion_Base> &conversion) {
{
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex); chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
/// \todo error if a conversion already exists if (find_bidir(conversion->to(), conversion->from()) != m_conversions.end()) {
throw exception::conversion_error(conversion->to(), conversion->from(), "Trying to re-insert an existing conversion!");
}
m_conversions.insert(conversion); m_conversions.insert(conversion);
m_convertableTypes.insert({conversion->to().bare_type_info(), conversion->from().bare_type_info()}); m_convertableTypes.insert({conversion->to().bare_type_info(), conversion->from().bare_type_info()});
m_num_types = m_convertableTypes.size(); m_num_types = m_convertableTypes.size();
} }
template<typename T> template<typename T>
bool convertable_type() const bool convertable_type() const noexcept {
{ const auto type = user_type<T>().bare_type_info();
return thread_cache().count(user_type<T>().bare_type_info()) != 0; return thread_cache().count(type) != 0;
} }
template<typename To, typename From> template<typename To, typename From>
bool converts() const bool converts() const noexcept {
{
return converts(user_type<To>(), user_type<From>()); return converts(user_type<To>(), user_type<From>());
} }
bool converts(const Type_Info &to, const Type_Info &from) const bool converts(const Type_Info &to, const Type_Info &from) const noexcept {
{
const auto &types = thread_cache(); const auto &types = thread_cache();
if (types.count(to.bare_type_info()) != 0 && types.count(from.bare_type_info()) != 0) if (types.count(to.bare_type_info()) != 0 && types.count(from.bare_type_info()) != 0) {
{
return has_conversion(to, from); return has_conversion(to, from);
} else { } else {
return false; return false;
} }
} }
template<typename To> template<typename To>
Boxed_Value boxed_type_conversion(const Boxed_Value &from) const Boxed_Value boxed_type_conversion(Conversion_Saves &t_saves, const Boxed_Value &from) const {
{ return boxed_type_conversion(user_type<To>(), t_saves, from);
try {
Boxed_Value ret = get_conversion(user_type<To>(), from.get_type_info())->convert(from);
if (m_conversion_saves->enabled) m_conversion_saves->saves.push_back(ret);
return ret;
} catch (const std::out_of_range &) {
throw exception::bad_boxed_dynamic_cast(from.get_type_info(), typeid(To), "No known conversion");
} catch (const std::bad_cast &) {
throw exception::bad_boxed_dynamic_cast(from.get_type_info(), typeid(To), "Unable to perform dynamic_cast operation");
}
} }
template<typename From> template<typename From>
Boxed_Value boxed_type_down_conversion(const Boxed_Value &to) const Boxed_Value boxed_type_down_conversion(Conversion_Saves &t_saves, const Boxed_Value &to) const {
{ return boxed_type_down_conversion(user_type<From>(), t_saves, to);
}
Boxed_Value boxed_type_conversion(const Type_Info &to, Conversion_Saves &t_saves, const Boxed_Value &from) const {
try { try {
Boxed_Value ret = get_conversion(to.get_type_info(), user_type<From>())->convert_down(to); Boxed_Value ret = get_conversion(to, from.get_type_info())->convert(from);
if (m_conversion_saves->enabled) m_conversion_saves->saves.push_back(ret); if (t_saves.enabled) {
t_saves.saves.push_back(ret);
}
return ret; return ret;
} catch (const std::out_of_range &) { } catch (const std::out_of_range &) {
throw exception::bad_boxed_dynamic_cast(to.get_type_info(), typeid(From), "No known conversion"); throw exception::bad_boxed_dynamic_cast(from.get_type_info(), *to.bare_type_info(), "No known conversion");
} catch (const std::bad_cast &) { } catch (const std::bad_cast &) {
throw exception::bad_boxed_dynamic_cast(to.get_type_info(), typeid(From), "Unable to perform dynamic_cast operation"); throw exception::bad_boxed_dynamic_cast(from.get_type_info(), *to.bare_type_info(), "Unable to perform dynamic_cast operation");
} }
} }
void enable_conversion_saves(bool t_val) Boxed_Value boxed_type_down_conversion(const Type_Info &from, Conversion_Saves &t_saves, const Boxed_Value &to) const {
{ try {
m_conversion_saves->enabled = t_val; Boxed_Value ret = get_conversion(to.get_type_info(), from)->convert_down(to);
if (t_saves.enabled) {
t_saves.saves.push_back(ret);
}
return ret;
} catch (const std::out_of_range &) {
throw exception::bad_boxed_dynamic_cast(to.get_type_info(), *from.bare_type_info(), "No known conversion");
} catch (const std::bad_cast &) {
throw exception::bad_boxed_dynamic_cast(to.get_type_info(), *from.bare_type_info(), "Unable to perform dynamic_cast operation");
}
} }
std::vector<Boxed_Value> take_saves() static void enable_conversion_saves(Conversion_Saves &t_saves, bool t_val) { t_saves.enabled = t_val; }
{
std::vector<Boxed_Value> take_saves(Conversion_Saves &t_saves) {
std::vector<Boxed_Value> ret; std::vector<Boxed_Value> ret;
std::swap(ret, m_conversion_saves->saves); std::swap(ret, t_saves.saves);
return ret; return ret;
} }
bool has_conversion(const Type_Info &to, const Type_Info &from) const bool has_conversion(const Type_Info &to, const Type_Info &from) const {
{
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex); chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
return find_bidir(to, from) != m_conversions.end(); return find_bidir(to, from) != m_conversions.end();
} }
std::shared_ptr<detail::Type_Conversion_Base> get_conversion(const Type_Info &to, const Type_Info &from) const std::shared_ptr<detail::Type_Conversion_Base> get_conversion(const Type_Info &to, const Type_Info &from) const {
{
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex); chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
auto itr = find(to, from); const auto itr = find(to, from);
if (itr != m_conversions.end()) if (itr != m_conversions.end()) {
{
return *itr; return *itr;
} else { } else {
throw std::out_of_range("No such conversion exists from " + from.bare_name() + " to " + to.bare_name()); throw std::out_of_range(std::string("No such conversion exists from ") + from.bare_name() + " to " + to.bare_name());
} }
} }
Conversion_Saves &conversion_saves() const noexcept { return *m_conversion_saves; }
private: private:
std::set<std::shared_ptr<detail::Type_Conversion_Base> >::const_iterator find_bidir( std::set<std::shared_ptr<detail::Type_Conversion_Base>>::const_iterator find_bidir(const Type_Info &to, const Type_Info &from) const {
const Type_Info &to, const Type_Info &from) const return std::find_if(m_conversions.begin(),
{ m_conversions.end(),
return std::find_if(m_conversions.begin(), m_conversions.end(), [&to, &from](const std::shared_ptr<detail::Type_Conversion_Base> &conversion) -> bool {
[&to, &from](const std::shared_ptr<detail::Type_Conversion_Base> &conversion) -> bool
{
return (conversion->to().bare_equal(to) && conversion->from().bare_equal(from)) return (conversion->to().bare_equal(to) && conversion->from().bare_equal(from))
|| (conversion->bidir() && conversion->from().bare_equal(to) && conversion->to().bare_equal(from)); || (conversion->bidir() && conversion->from().bare_equal(to) && conversion->to().bare_equal(from));
; });
}
);
} }
std::set<std::shared_ptr<detail::Type_Conversion_Base> >::const_iterator find( std::set<std::shared_ptr<detail::Type_Conversion_Base>>::const_iterator find(const Type_Info &to, const Type_Info &from) const {
const Type_Info &to, const Type_Info &from) const return std::find_if(m_conversions.begin(),
{ m_conversions.end(),
return std::find_if(m_conversions.begin(), m_conversions.end(), [&to, &from](const std::shared_ptr<detail::Type_Conversion_Base> &conversion) {
[&to, &from](const std::shared_ptr<detail::Type_Conversion_Base> &conversion)
{
return conversion->to().bare_equal(to) && conversion->from().bare_equal(from); return conversion->to().bare_equal(to) && conversion->from().bare_equal(from);
} });
);
} }
std::set<std::shared_ptr<detail::Type_Conversion_Base>> get_conversions() const std::set<std::shared_ptr<detail::Type_Conversion_Base>> get_conversions() const {
{
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex); chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
return m_conversions; return m_conversions;
} }
struct Conversion_Saves
{
Conversion_Saves()
: enabled(false)
{}
bool enabled;
std::vector<Boxed_Value> saves;
};
mutable chaiscript::detail::threading::shared_mutex m_mutex; mutable chaiscript::detail::threading::shared_mutex m_mutex;
std::set<std::shared_ptr<detail::Type_Conversion_Base>> m_conversions; std::set<std::shared_ptr<detail::Type_Conversion_Base>> m_conversions;
std::set<const std::type_info *, Less_Than> m_convertableTypes; std::set<const std::type_info *, Less_Than> m_convertableTypes;
@ -501,7 +414,25 @@ namespace chaiscript
mutable chaiscript::detail::threading::Thread_Storage<Conversion_Saves> m_conversion_saves; mutable chaiscript::detail::threading::Thread_Storage<Conversion_Saves> m_conversion_saves;
}; };
typedef std::shared_ptr<chaiscript::detail::Type_Conversion_Base> Type_Conversion; class Type_Conversions_State {
public:
Type_Conversions_State(const Type_Conversions &t_conversions, Type_Conversions::Conversion_Saves &t_saves)
: m_conversions(t_conversions)
, m_saves(t_saves) {
}
const Type_Conversions *operator->() const noexcept { return &m_conversions.get(); }
const Type_Conversions *get() const noexcept { return &m_conversions.get(); }
Type_Conversions::Conversion_Saves &saves() const noexcept { return m_saves; }
private:
std::reference_wrapper<const Type_Conversions> m_conversions;
std::reference_wrapper<Type_Conversions::Conversion_Saves> m_saves;
};
using Type_Conversion = std::shared_ptr<chaiscript::detail::Type_Conversion_Base>;
/// \brief Used to register a to / parent class relationship with ChaiScript. Necessary if you /// \brief Used to register a to / parent class relationship with ChaiScript. Necessary if you
/// want automatic conversions up your inheritance hierarchy. /// want automatic conversions up your inheritance hierarchy.
@ -525,64 +456,55 @@ namespace chaiscript
/// \endcode /// \endcode
/// ///
template<typename Base, typename Derived> template<typename Base, typename Derived>
Type_Conversion base_class(typename std::enable_if<std::is_polymorphic<Base>::value && std::is_polymorphic<Derived>::value>::type* = nullptr) Type_Conversion base_class() {
{ // Can only be used with related polymorphic types
//Can only be used with related polymorphic types // may be expanded some day to support conversions other than child -> parent
//may be expanded some day to support conversions other than child -> parent static_assert(std::is_base_of<Base, Derived>::value, "Classes are not related by inheritance");
static_assert(std::is_base_of<Base,Derived>::value, "Classes are not related by inheritance");
if constexpr (std::is_polymorphic<Base>::value && std::is_polymorphic<Derived>::value) {
return chaiscript::make_shared<detail::Type_Conversion_Base, detail::Dynamic_Conversion_Impl<Base, Derived>>(); return chaiscript::make_shared<detail::Type_Conversion_Base, detail::Dynamic_Conversion_Impl<Base, Derived>>();
} } else {
template<typename Base, typename Derived>
Type_Conversion base_class(typename std::enable_if<!std::is_polymorphic<Base>::value || !std::is_polymorphic<Derived>::value>::type* = nullptr)
{
//Can only be used with related polymorphic types
//may be expanded some day to support conversions other than child -> parent
static_assert(std::is_base_of<Base,Derived>::value, "Classes are not related by inheritance");
return chaiscript::make_shared<detail::Type_Conversion_Base, detail::Static_Conversion_Impl<Base, Derived>>(); return chaiscript::make_shared<detail::Type_Conversion_Base, detail::Static_Conversion_Impl<Base, Derived>>();
} }
}
template<typename Callable> template<typename Callable>
Type_Conversion type_conversion(const Type_Info &t_from, const Type_Info &t_to, Type_Conversion type_conversion(const Type_Info &t_from, const Type_Info &t_to, const Callable &t_func) {
const Callable &t_func)
{
return chaiscript::make_shared<detail::Type_Conversion_Base, detail::Type_Conversion_Impl<Callable>>(t_from, t_to, t_func); return chaiscript::make_shared<detail::Type_Conversion_Base, detail::Type_Conversion_Impl<Callable>>(t_from, t_to, t_func);
} }
template<typename From, typename To, typename Callable> template<typename From, typename To, typename Callable>
Type_Conversion type_conversion(const Callable &t_function) Type_Conversion type_conversion(const Callable &t_function) {
{
auto func = [t_function](const Boxed_Value &t_bv) -> Boxed_Value { auto func = [t_function](const Boxed_Value &t_bv) -> Boxed_Value {
// not even attempting to call boxed_cast so that we don't get caught in some call recursion // not even attempting to call boxed_cast so that we don't get caught in some call recursion
return chaiscript::Boxed_Value(t_function(detail::Cast_Helper<const From &>::cast(t_bv, nullptr))); return chaiscript::Boxed_Value(t_function(detail::Cast_Helper<const From &>::cast(t_bv, nullptr)));
}; };
return chaiscript::make_shared<detail::Type_Conversion_Base, detail::Type_Conversion_Impl<decltype(func)>>(user_type<From>(), user_type<To>(), func); return chaiscript::make_shared<detail::Type_Conversion_Base, detail::Type_Conversion_Impl<decltype(func)>>(user_type<From>(),
user_type<To>(),
func);
} }
template<typename From, typename To> template<typename From, typename To>
Type_Conversion type_conversion() Type_Conversion type_conversion() {
{
static_assert(std::is_convertible<From, To>::value, "Types are not automatically convertible"); static_assert(std::is_convertible<From, To>::value, "Types are not automatically convertible");
auto func = [](const Boxed_Value &t_bv) -> Boxed_Value { auto func = [](const Boxed_Value &t_bv) -> Boxed_Value {
// not even attempting to call boxed_cast so that we don't get caught in some call recursion // not even attempting to call boxed_cast so that we don't get caught in some call recursion
return chaiscript::Boxed_Value(To(detail::Cast_Helper<From>::cast(t_bv, nullptr))); return chaiscript::Boxed_Value(To(detail::Cast_Helper<From>::cast(t_bv, nullptr)));
}; };
return chaiscript::make_shared<detail::Type_Conversion_Base, detail::Type_Conversion_Impl<decltype(func)>>(user_type<From>(), user_type<To>(), func); return chaiscript::make_shared<detail::Type_Conversion_Base, detail::Type_Conversion_Impl<decltype(func)>>(user_type<From>(),
user_type<To>(),
func);
} }
template<typename To> template<typename To>
Type_Conversion vector_conversion() Type_Conversion vector_conversion() {
{
auto func = [](const Boxed_Value &t_bv) -> Boxed_Value { auto func = [](const Boxed_Value &t_bv) -> Boxed_Value {
const std::vector<Boxed_Value> &from_vec = detail::Cast_Helper<const std::vector<Boxed_Value> &>::cast(t_bv, nullptr); const std::vector<Boxed_Value> &from_vec = detail::Cast_Helper<const std::vector<Boxed_Value> &>::cast(t_bv, nullptr);
To vec; To vec;
vec.reserve(from_vec.size());
for (const Boxed_Value &bv : from_vec) { for (const Boxed_Value &bv : from_vec) {
vec.push_back(detail::Cast_Helper<typename To::value_type>::cast(bv, nullptr)); vec.push_back(detail::Cast_Helper<typename To::value_type>::cast(bv, nullptr));
} }
@ -590,10 +512,28 @@ namespace chaiscript
return Boxed_Value(std::move(vec)); return Boxed_Value(std::move(vec));
}; };
return chaiscript::make_shared<detail::Type_Conversion_Base, detail::Type_Conversion_Impl<decltype(func)>>(user_type<std::vector<Boxed_Value>>(), user_type<To>(), func); return chaiscript::make_shared<detail::Type_Conversion_Base, detail::Type_Conversion_Impl<decltype(func)>>(user_type<std::vector<Boxed_Value>>(),
user_type<To>(),
func);
} }
} template<typename To>
Type_Conversion map_conversion() {
auto func = [](const Boxed_Value &t_bv) -> Boxed_Value {
const std::map<std::string, Boxed_Value> &from_map
= detail::Cast_Helper<const std::map<std::string, Boxed_Value> &>::cast(t_bv, nullptr);
To map;
for (const std::pair<const std::string, Boxed_Value> &p : from_map) {
map.insert(std::make_pair(p.first, detail::Cast_Helper<typename To::mapped_type>::cast(p.second, nullptr)));
}
return Boxed_Value(std::move(map));
};
return chaiscript::make_shared<detail::Type_Conversion_Base, detail::Type_Conversion_Impl<decltype(func)>>(
user_type<std::map<std::string, Boxed_Value>>(), user_type<To>(), func);
}
} // namespace chaiscript
#endif #endif

View File

@ -1,143 +1,113 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) // Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.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_ #ifndef CHAISCRIPT_TYPE_INFO_HPP_
#define CHAISCRIPT_TYPE_INFO_HPP_ #define CHAISCRIPT_TYPE_INFO_HPP_
#include <memory> #include <memory>
#include <string>
#include <type_traits> #include <type_traits>
#include <typeinfo> #include <typeinfo>
#include <string>
namespace chaiscript namespace chaiscript {
{ namespace detail {
namespace detail
{
template<typename T> template<typename T>
struct Bare_Type struct Bare_Type {
{ using type = typename std::remove_cv<typename std::remove_pointer<typename std::remove_reference<T>::type>::type>::type;
typedef typename std::remove_cv<typename std::remove_pointer<typename std::remove_reference<T>::type>::type>::type type;
}; };
} } // namespace detail
/// \brief Compile time deduced information about a type /// \brief Compile time deduced information about a type
class Type_Info class Type_Info {
{
public: public:
CHAISCRIPT_CONSTEXPR Type_Info(bool t_is_const, bool t_is_reference, bool t_is_pointer, bool t_is_void, constexpr Type_Info(const bool t_is_const,
bool t_is_arithmetic, const std::type_info *t_ti, const std::type_info *t_bare_ti) const bool t_is_reference,
: m_type_info(t_ti), m_bare_type_info(t_bare_ti), const bool t_is_pointer,
m_is_const(t_is_const), m_is_reference(t_is_reference), m_is_pointer(t_is_pointer), const bool t_is_void,
m_is_void(t_is_void), m_is_arithmetic(t_is_arithmetic), const bool t_is_arithmetic,
m_is_undef(false) 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)) {
} }
CHAISCRIPT_CONSTEXPR Type_Info() constexpr Type_Info() noexcept = default;
: m_type_info(nullptr), m_bare_type_info(nullptr),
m_is_const(false), m_is_reference(false), m_is_pointer(false), bool operator<(const Type_Info &ti) const noexcept { return m_type_info->before(*ti.m_type_info); }
m_is_void(false), m_is_arithmetic(false),
m_is_undef(true) 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;
} }
#if !defined(_MSC_VER) || _MSC_VER != 1800 constexpr bool operator==(const std::type_info &ti) const noexcept { return !is_undef() && (*m_type_info) == ti; }
Type_Info(Type_Info&&) = default;
Type_Info& operator=(Type_Info&&) = default;
#endif
Type_Info(const Type_Info&) = default; constexpr bool bare_equal(const Type_Info &ti) const noexcept {
Type_Info& operator=(const Type_Info&) = default; return ti.m_bare_type_info == m_bare_type_info || *ti.m_bare_type_info == *m_bare_type_info;
CHAISCRIPT_CONSTEXPR bool operator<(const Type_Info &ti) const CHAISCRIPT_NOEXCEPT
{
return m_type_info < ti.m_type_info;
} }
CHAISCRIPT_CONSTEXPR bool operator==(const Type_Info &ti) const CHAISCRIPT_NOEXCEPT constexpr bool bare_equal_type_info(const std::type_info &ti) const noexcept { return !is_undef() && (*m_bare_type_info) == ti; }
{
return ti.m_type_info == m_type_info
|| (ti.m_type_info && m_type_info && *ti.m_type_info == *m_type_info);
}
CHAISCRIPT_CONSTEXPR bool operator==(const std::type_info &ti) const CHAISCRIPT_NOEXCEPT 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; }
return m_type_info != nullptr && (*m_type_info) == ti; 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; }
CHAISCRIPT_CONSTEXPR bool bare_equal(const Type_Info &ti) const CHAISCRIPT_NOEXCEPT const char *name() const noexcept {
{ if (!is_undef()) {
return ti.m_bare_type_info == m_bare_type_info
|| (ti.m_bare_type_info && m_bare_type_info && *ti.m_bare_type_info == *m_bare_type_info);
}
CHAISCRIPT_CONSTEXPR bool bare_equal_type_info(const std::type_info &ti) const CHAISCRIPT_NOEXCEPT
{
return m_bare_type_info != nullptr
&& (*m_bare_type_info) == ti;
}
CHAISCRIPT_CONSTEXPR bool is_const() const CHAISCRIPT_NOEXCEPT { return m_is_const; }
CHAISCRIPT_CONSTEXPR bool is_reference() const CHAISCRIPT_NOEXCEPT { return m_is_reference; }
CHAISCRIPT_CONSTEXPR bool is_void() const CHAISCRIPT_NOEXCEPT { return m_is_void; }
CHAISCRIPT_CONSTEXPR bool is_arithmetic() const CHAISCRIPT_NOEXCEPT { return m_is_arithmetic; }
CHAISCRIPT_CONSTEXPR bool is_undef() const CHAISCRIPT_NOEXCEPT { return m_is_undef; }
CHAISCRIPT_CONSTEXPR bool is_pointer() const CHAISCRIPT_NOEXCEPT { return m_is_pointer; }
std::string name() const
{
if (m_type_info)
{
return m_type_info->name(); return m_type_info->name();
} else { } else {
return ""; return "";
} }
} }
std::string bare_name() const const char *bare_name() const noexcept {
{ if (!is_undef()) {
if (m_bare_type_info)
{
return m_bare_type_info->name(); return m_bare_type_info->name();
} else { } else {
return ""; return "";
} }
} }
CHAISCRIPT_CONSTEXPR const std::type_info *bare_type_info() const constexpr const std::type_info *bare_type_info() const noexcept { return m_bare_type_info; }
{
return m_bare_type_info;
}
private: private:
const std::type_info *m_type_info; struct Unknown_Type {
const std::type_info *m_bare_type_info;
bool m_is_const;
bool m_is_reference;
bool m_is_pointer;
bool m_is_void;
bool m_is_arithmetic;
bool m_is_undef;
}; };
namespace detail const std::type_info *m_type_info = &typeid(Unknown_Type);
{ const std::type_info *m_bare_type_info = &typeid(Unknown_Type);
static const int is_const_flag = 0;
static const int is_reference_flag = 1;
static const int is_pointer_flag = 2;
static const int is_void_flag = 3;
static const int is_arithmetic_flag = 4;
static const int is_undef_flag = 5;
unsigned int m_flags = (1 << is_undef_flag);
};
namespace detail {
/// Helper used to create a Type_Info object /// Helper used to create a Type_Info object
template<typename T> template<typename T>
struct Get_Type_Info struct Get_Type_Info {
{ constexpr static Type_Info get() noexcept {
typedef T type;
static Type_Info get()
{
return Type_Info(std::is_const<typename std::remove_pointer<typename std::remove_reference<T>::type>::type>::value, return Type_Info(std::is_const<typename std::remove_pointer<typename std::remove_reference<T>::type>::type>::value,
std::is_reference<T>::value, std::is_pointer<T>::value, std::is_reference<T>::value,
std::is_pointer<T>::value,
std::is_void<T>::value, std::is_void<T>::value,
(std::is_arithmetic<T>::value || std::is_arithmetic<typename std::remove_reference<T>::type>::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, && !std::is_same<typename std::remove_const<typename std::remove_reference<T>::type>::type, bool>::value,
@ -147,66 +117,66 @@ namespace chaiscript
}; };
template<typename T> template<typename T>
struct Get_Type_Info<std::shared_ptr<T> > struct Get_Type_Info<std::shared_ptr<T>> {
{ constexpr static Type_Info get() noexcept {
typedef T type; return Type_Info(std::is_const<T>::value,
std::is_reference<T>::value,
static Type_Info get() std::is_pointer<T>::value,
{
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_void<T>::value,
std::is_arithmetic<T>::value && !std::is_same<typename std::remove_const<typename std::remove_reference<T>::type>::type, bool>::value, std::is_arithmetic<T>::value
&typeid(std::shared_ptr<T> ), && !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)); &typeid(typename Bare_Type<T>::type));
} }
}; };
template<typename T> template<typename T>
struct Get_Type_Info<const std::shared_ptr<T> &> struct Get_Type_Info<std::shared_ptr<T> &> : Get_Type_Info<std::shared_ptr<T>> {
{ };
typedef T type;
static Type_Info get() template<typename T>
{ struct Get_Type_Info<const std::shared_ptr<T> &> {
return Type_Info(std::is_const<T>::value, std::is_reference<T>::value, std::is_pointer<T>::value, 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_void<T>::value,
std::is_arithmetic<T>::value && !std::is_same<typename std::remove_const<typename std::remove_reference<T>::type>::type, bool>::value, std::is_arithmetic<T>::value
&& !std::is_same<typename std::remove_const<typename std::remove_reference<T>::type>::type, bool>::value,
&typeid(const std::shared_ptr<T> &), &typeid(const std::shared_ptr<T> &),
&typeid(typename Bare_Type<T>::type)); &typeid(typename Bare_Type<T>::type));
} }
}; };
template<typename T> template<typename T>
struct Get_Type_Info<std::reference_wrapper<T> > struct Get_Type_Info<std::reference_wrapper<T>> {
{ constexpr static Type_Info get() noexcept {
typedef T type; return Type_Info(std::is_const<T>::value,
std::is_reference<T>::value,
static Type_Info get() std::is_pointer<T>::value,
{
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_void<T>::value,
std::is_arithmetic<T>::value && !std::is_same<typename std::remove_const<typename std::remove_reference<T>::type>::type, bool>::value, std::is_arithmetic<T>::value
&typeid(std::reference_wrapper<T> ), && !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)); &typeid(typename Bare_Type<T>::type));
} }
}; };
template<typename T> template<typename T>
struct Get_Type_Info<const std::reference_wrapper<T> &> struct Get_Type_Info<const std::reference_wrapper<T> &> {
{ constexpr static Type_Info get() noexcept {
typedef T type; return Type_Info(std::is_const<T>::value,
std::is_reference<T>::value,
static Type_Info get() std::is_pointer<T>::value,
{
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_void<T>::value,
std::is_arithmetic<T>::value && !std::is_same<typename std::remove_const<typename std::remove_reference<T>::type>::type, bool>::value, std::is_arithmetic<T>::value
&& !std::is_same<typename std::remove_const<typename std::remove_reference<T>::type>::type, bool>::value,
&typeid(const std::reference_wrapper<T> &), &typeid(const std::reference_wrapper<T> &),
&typeid(typename Bare_Type<T>::type)); &typeid(typename Bare_Type<T>::type));
} }
}; };
} } // namespace detail
/// \brief Creates a Type_Info object representing the type passed in /// \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 /// \tparam T Type of object to get a Type_Info for, derived from the passed in parameter
@ -218,12 +188,10 @@ namespace chaiscript
/// chaiscript::Type_Info ti = chaiscript::user_type(i); /// chaiscript::Type_Info ti = chaiscript::user_type(i);
/// \endcode /// \endcode
template<typename T> template<typename T>
Type_Info user_type(const T &/*t*/) constexpr Type_Info user_type(const T & /*t*/) noexcept {
{
return detail::Get_Type_Info<T>::get(); return detail::Get_Type_Info<T>::get();
} }
/// \brief Creates a Type_Info object representing the templated type /// \brief Creates a Type_Info object representing the templated type
/// \tparam T Type of object to get a Type_Info for /// \tparam T Type of object to get a Type_Info for
/// \return Type_Info for T /// \return Type_Info for T
@ -233,12 +201,10 @@ namespace chaiscript
/// chaiscript::Type_Info ti = chaiscript::user_type<int>(); /// chaiscript::Type_Info ti = chaiscript::user_type<int>();
/// \endcode /// \endcode
template<typename T> template<typename T>
Type_Info user_type() constexpr Type_Info user_type() noexcept {
{
return detail::Get_Type_Info<T>::get(); return detail::Get_Type_Info<T>::get();
} }
} } // namespace chaiscript
#endif #endif

View File

@ -1,130 +1,167 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) // Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.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_ #ifndef CHAISCRIPT_ALGEBRAIC_HPP_
#define CHAISCRIPT_ALGEBRAIC_HPP_ #define CHAISCRIPT_ALGEBRAIC_HPP_
#include "../utility/hash.hpp"
#include <string> #include <string>
namespace chaiscript namespace chaiscript {
{
struct Operators { struct Operators {
enum Opers enum class Opers {
{ equals,
boolean_flag, less_than,
equals, less_than, greater_than, less_than_equal, greater_than_equal, not_equal, greater_than,
non_const_flag, less_than_equal,
assign, pre_increment, pre_decrement, assign_product, assign_sum, greater_than_equal,
assign_quotient, assign_difference, not_equal,
non_const_int_flag, assign,
assign_bitwise_and, assign_bitwise_or, assign_shift_left, assign_shift_right, pre_increment,
assign_remainder, assign_bitwise_xor, pre_decrement,
const_int_flag, assign_product,
shift_left, shift_right, remainder, bitwise_and, bitwise_or, bitwise_xor, bitwise_complement, assign_sum,
const_flag, assign_quotient,
sum, quotient, product, difference, unary_plus, unary_minus, 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 invalid
}; };
static const char *to_string(Opers t_oper) { constexpr static const char *to_string(Opers t_oper) noexcept {
const char *opers[] = { constexpr const char *opers[]
"", = {"", "==", "<", ">", "<=", ">=", "!=", "", "=", "++", "--", "*=", "+=", "/=", "-=", "", "&=", "|=", "<<=", ">>=", "%=", "^=", "", "<<", ">>", "%", "&", "|", "^", "~", "", "+", "/", "*", "-", "+", "-", ""};
"==", "<", ">", "<=", ">=", "!=", return opers[static_cast<int>(t_oper)];
"",
"=", "++", "--", "*=", "+=",
"/=", "-=",
"",
"&=", "|=", "<<=", ">>=",
"%=", "^=",
"",
"<<", ">>", "%", "&", "|", "^", "~",
"",
"+", "/", "*", "-", "+", "-",
""
};
return opers[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
if (t_str == "==") #pragma warning(push)
{ #pragma warning(disable : 4307)
return equals; #endif
} else if (t_str == "<") {
return less_than;
} else if (t_str == ">") {
return greater_than;
} else if (t_str == "<=") {
return less_than_equal;
} else if (t_str == ">=") {
return greater_than_equal;
} else if (t_str == "!=") {
return not_equal;
} else if (t_str == "=") {
return assign;
} else if (t_str == "++") {
return pre_increment;
} else if (t_str == "--") {
return pre_decrement;
} else if (t_str == "*=") {
return assign_product;
} else if (t_str == "+=") {
return assign_sum;
} else if (t_str == "-=") {
return assign_difference;
} else if (t_str == "&=") {
return assign_bitwise_and;
} else if (t_str == "|=") {
return assign_bitwise_or;
} else if (t_str == "<<=") {
return assign_shift_left;
} else if (t_str == ">>=") {
return assign_shift_right;
} else if (t_str == "%=") {
return assign_remainder;
} else if (t_str == "^=") {
return assign_bitwise_xor;
} else if (t_str == "<<") {
return shift_left;
} else if (t_str == ">>") {
return shift_right;
} else if (t_str == "%") {
return remainder;
} else if (t_str == "&") {
return bitwise_and;
} else if (t_str == "|") {
return bitwise_or;
} else if (t_str == "^") {
return bitwise_xor;
} else if (t_str == "~") {
return bitwise_complement;
} else if (t_str == "+") {
if (t_is_unary) {
return unary_plus;
} else {
return sum;
}
} else if (t_str == "-") {
if (t_is_unary) {
return unary_minus;
} else {
return difference;
}
} else if (t_str == "/") {
return quotient;
} else if (t_str == "*") {
return product;
} else {
return invalid;
}
}
const auto op_hash = utility::hash(t_str);
switch (op_hash) {
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 */ #endif /* _CHAISCRIPT_ALGEBRAIC_HPP */

View File

@ -1,9 +1,12 @@
// This file is distributed under the BSD License. // This file is distributed under the BSD License.
// See "license.txt" for details. // See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) // Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_COMMON_HPP_ #ifndef CHAISCRIPT_COMMON_HPP_
#define CHAISCRIPT_COMMON_HPP_ #define CHAISCRIPT_COMMON_HPP_
@ -19,88 +22,280 @@
#include "../dispatchkit/dispatchkit.hpp" #include "../dispatchkit/dispatchkit.hpp"
#include "../dispatchkit/proxy_functions.hpp" #include "../dispatchkit/proxy_functions.hpp"
#include "../dispatchkit/type_info.hpp" #include "../dispatchkit/type_info.hpp"
#include <unordered_set>
namespace chaiscript { namespace chaiscript {
struct AST_Node; struct AST_Node;
struct AST_Node_Trace;
namespace exception {
struct eval_error;
}
} // namespace chaiscript } // namespace chaiscript
namespace chaiscript namespace chaiscript {
{ struct Name_Validator {
template<typename T>
static bool is_reserved_word(const T &s) noexcept {
const static std::unordered_set<std::uint32_t>
words{utility::hash("def"), utility::hash("fun"), utility::hash("while"), utility::hash("for"), utility::hash("if"), utility::hash("else"), utility::hash("&&"), utility::hash("||"), utility::hash(","), utility::hash("auto"), utility::hash("return"), utility::hash("break"), utility::hash("true"), utility::hash("false"), utility::hash("class"), utility::hash("attr"), utility::hash("var"), utility::hash("global"), utility::hash("GLOBAL"), utility::hash("_"), utility::hash("__LINE__"), utility::hash("__FILE__"), utility::hash("__FUNC__"), utility::hash("__CLASS__")};
return words.count(utility::hash(s)) == 1;
}
template<typename T>
static bool valid_object_name(const T &name) noexcept {
return name.find("::") == std::string::npos && !is_reserved_word(name);
}
template<typename T>
static void validate_object_name(const T &name) {
if (is_reserved_word(name)) {
throw exception::reserved_word_error(std::string(name));
}
if (name.find("::") != std::string::npos) {
throw exception::illegal_name_error(std::string(name));
}
}
};
/// Signature of module entry point that all binary loadable modules must implement. /// Signature of module entry point that all binary loadable modules must implement.
typedef ModulePtr (*Create_Module_Func)(); using Create_Module_Func = ModulePtr (*)();
/// Types of AST nodes available to the parser and eval /// Types of AST nodes available to the parser and eval
class AST_Node_Type { enum class AST_Node_Type {
public: Id,
enum Type { Error, Int, Float, Id, Char, Str, Eol, Fun_Call, Arg_List, Variable, Equation, Var_Decl, Fun_Call,
Comparison, Addition, Subtraction, Multiplication, Division, Modulus, Array_Call, Dot_Access, Quoted_String, Single_Quoted_String, Unused_Return_Fun_Call,
Lambda, Block, Def, While, If, For, Inline_Array, Inline_Map, Return, File, Prefix, Break, Continue, Map_Pair, Value_Range, Arg_List,
Inline_Range, Annotation, Try, Catch, Finally, Method, Attr_Decl, Shift, Equality, Bitwise_And, Bitwise_Xor, Bitwise_Or, Equation,
Logical_And, Logical_Or, Reference, Switch, Case, Default, Ternary_Cond, Noop, Class, Binary, Arg, Global_Decl Var_Decl,
}; Assign_Decl,
Array_Call,
Dot_Access,
Lambda,
Block,
Scopeless_Block,
Def,
While,
If,
For,
Ranged_For,
Inline_Array,
Inline_Map,
Return,
File,
Prefix,
Break,
Continue,
Map_Pair,
Value_Range,
Inline_Range,
Try,
Catch,
Finally,
Method,
Attr_Decl,
Logical_And,
Logical_Or,
Reference,
Switch,
Case,
Default,
Noop,
Class,
Binary,
Arg,
Global_Decl,
Constant,
Compiled
}; };
namespace enum class Operator_Precedence {
{ Ternary_Cond,
Logical_Or,
Logical_And,
Bitwise_Or,
Bitwise_Xor,
Bitwise_And,
Equality,
Comparison,
Shift,
Addition,
Multiplication,
Prefix
};
namespace {
/// Helper lookup to get the name of each node type /// Helper lookup to get the name of each node type
const char *ast_node_type_to_string(int ast_node_type) { constexpr const char *ast_node_type_to_string(AST_Node_Type ast_node_type) noexcept {
const char *ast_node_types[] = { "Internal Parser Error", "Int", "Float", "Id", "Char", "Str", "Eol", "Fun_Call", "Arg_List", "Variable", "Equation", "Var_Decl", constexpr const char *const ast_node_types[] = {"Id", "Fun_Call", "Unused_Return_Fun_Call", "Arg_List", "Equation", "Var_Decl", "Assign_Decl", "Array_Call", "Dot_Access", "Lambda", "Block", "Scopeless_Block", "Def", "While", "If", "For", "Ranged_For", "Inline_Array", "Inline_Map", "Return", "File", "Prefix", "Break", "Continue", "Map_Pair", "Value_Range", "Inline_Range", "Try", "Catch", "Finally", "Method", "Attr_Decl", "Logical_And", "Logical_Or", "Reference", "Switch", "Case", "Default", "Noop", "Class", "Binary", "Arg", "Global_Decl", "Constant", "Compiled"};
"Comparison", "Addition", "Subtraction", "Multiplication", "Division", "Modulus", "Array_Call", "Dot_Access", "Quoted_String", "Single_Quoted_String",
"Lambda", "Block", "Def", "While", "If", "For", "Inline_Array", "Inline_Map", "Return", "File", "Prefix", "Break", "Continue", "Map_Pair", "Value_Range",
"Inline_Range", "Annotation", "Try", "Catch", "Finally", "Method", "Attr_Decl", "Shift", "Equality", "Bitwise_And", "Bitwise_Xor", "Bitwise_Or",
"Logical_And", "Logical_Or", "Reference", "Switch", "Case", "Default", "Ternary Condition", "Noop", "Class", "Binary", "Arg"};
return ast_node_types[ast_node_type]; return ast_node_types[static_cast<int>(ast_node_type)];
}
} }
} // namespace
/// \brief Convenience type for file positions /// \brief Convenience type for file positions
struct File_Position { struct File_Position {
int line; int line = 0;
int column; int column = 0;
File_Position(int t_file_line, int t_file_column) constexpr File_Position(int t_file_line, int t_file_column) noexcept
: line(t_file_line), column(t_file_column) { } : line(t_file_line)
, column(t_file_column) {
}
File_Position() : line(0), column(0) { } constexpr File_Position() noexcept = default;
}; };
struct Parse_Location { struct Parse_Location {
Parse_Location(std::string t_fname="", const int t_start_line=0, const int t_start_col=0, Parse_Location(std::string t_fname = "", const int t_start_line = 0, const int t_start_col = 0, const int t_end_line = 0, const int t_end_col = 0)
const int t_end_line=0, const int t_end_col=0) : start(t_start_line, t_start_col)
: start(t_start_line, t_start_col), , end(t_end_line, t_end_col)
end(t_end_line, t_end_col), , filename(std::make_shared<std::string>(std::move(t_fname))) {
filename(std::make_shared<std::string>(std::move(t_fname)))
{
} }
Parse_Location(std::shared_ptr<std::string> t_fname, const int t_start_line=0, const int t_start_col=0, Parse_Location(std::shared_ptr<std::string> t_fname,
const int t_end_line=0, const int t_end_col=0) const int t_start_line = 0,
: start(t_start_line, t_start_col), const int t_start_col = 0,
end(t_end_line, t_end_col), const int t_end_line = 0,
filename(std::move(t_fname)) const int t_end_col = 0)
{ : start(t_start_line, t_start_col)
, end(t_end_line, t_end_col)
, filename(std::move(t_fname)) {
} }
File_Position start; File_Position start;
File_Position end; File_Position end;
std::shared_ptr<std::string> filename; std::shared_ptr<std::string> filename;
}; };
/// \brief Struct that doubles as both a parser ast_node and an AST node.
struct AST_Node {
public:
const AST_Node_Type identifier;
const std::string text;
Parse_Location location;
const std::string &filename() const noexcept { return *location.filename; }
const File_Position &start() const noexcept { return location.start; }
const File_Position &end() const noexcept { return location.end; }
std::string pretty_print() const {
std::ostringstream oss;
oss << text;
for (auto &elem : get_children()) {
oss << elem.get().pretty_print() << ' ';
}
return oss.str();
}
virtual std::vector<std::reference_wrapper<AST_Node>> get_children() const = 0;
virtual Boxed_Value eval(const chaiscript::detail::Dispatch_State &t_e) const = 0;
/// Prints the contents of an AST node, including its children, recursively
std::string to_string(const std::string &t_prepend = "") const {
std::ostringstream oss;
oss << t_prepend << "(" << ast_node_type_to_string(this->identifier) << ") " << this->text << " : " << this->location.start.line
<< ", " << this->location.start.column << '\n';
for (auto &elem : get_children()) {
oss << elem.get().to_string(t_prepend + " ");
}
return oss.str();
}
static inline bool get_bool_condition(const Boxed_Value &t_bv, const chaiscript::detail::Dispatch_State &t_ss);
virtual ~AST_Node() noexcept = default;
AST_Node(AST_Node &&) = default;
AST_Node &operator=(AST_Node &&) = delete;
AST_Node(const AST_Node &) = delete;
AST_Node &operator=(const AST_Node &) = delete;
protected:
AST_Node(std::string t_ast_node_text, AST_Node_Type t_id, Parse_Location t_loc)
: identifier(t_id)
, text(std::move(t_ast_node_text))
, location(std::move(t_loc)) {
}
};
/// \brief Typedef for pointers to AST_Node objects. Used in building of the AST_Node tree /// \brief Typedef for pointers to AST_Node objects. Used in building of the AST_Node tree
typedef std::shared_ptr<AST_Node> AST_NodePtr; using AST_NodePtr = std::unique_ptr<AST_Node>;
typedef std::shared_ptr<const AST_Node> AST_NodePtr_Const; using AST_NodePtr_Const = std::unique_ptr<const AST_Node>;
struct AST_Node_Trace {
const AST_Node_Type identifier;
const std::string text;
Parse_Location location;
const std::string &filename() const noexcept { return *location.filename; }
const File_Position &start() const noexcept { return location.start; }
const File_Position &end() const noexcept { return location.end; }
std::string pretty_print() const {
std::ostringstream oss;
oss << text;
for (const auto &elem : children) {
oss << elem.pretty_print() << ' ';
}
return oss.str();
}
std::vector<AST_Node_Trace> get_children(const AST_Node &node) {
const auto node_children = node.get_children();
return std::vector<AST_Node_Trace>(node_children.begin(), node_children.end());
}
AST_Node_Trace(const AST_Node &node)
: identifier(node.identifier)
, text(node.text)
, location(node.location)
, children(get_children(node)) {
}
std::vector<AST_Node_Trace> children;
};
/// \brief Classes which may be thrown during error cases when ChaiScript is executing. /// \brief Classes which may be thrown during error cases when ChaiScript is executing.
namespace exception namespace exception {
{ /// \brief Thrown if an error occurs while attempting to load a binary module
struct load_module_error : std::runtime_error {
explicit load_module_error(const std::string &t_reason)
: std::runtime_error(t_reason) {
}
load_module_error(const std::string &t_name, const std::vector<load_module_error> &t_errors)
: std::runtime_error(format_error(t_name, t_errors)) {
}
load_module_error(const load_module_error &) = default;
~load_module_error() noexcept override = default;
static std::string format_error(const std::string &t_name, const std::vector<load_module_error> &t_errors) {
std::stringstream ss;
ss << "Error loading module '" << t_name << "'\n"
<< " The following locations were searched:\n";
for (const auto &err : t_errors) {
ss << " " << err.what() << "\n";
}
return ss.str();
}
};
/// Errors generated during parsing or evaluation /// Errors generated during parsing or evaluation
struct eval_error : std::runtime_error { struct eval_error : std::runtime_error {
@ -108,50 +303,57 @@ namespace chaiscript
File_Position start_position; File_Position start_position;
std::string filename; std::string filename;
std::string detail; std::string detail;
std::vector<AST_NodePtr_Const> call_stack; std::vector<AST_Node_Trace> call_stack;
eval_error(const std::string &t_why, const File_Position &t_where, const std::string &t_fname,
const std::vector<Boxed_Value> &t_parameters, const std::vector<chaiscript::Const_Proxy_Function> &t_functions,
bool t_dot_notation,
const chaiscript::detail::Dispatch_Engine &t_ss) CHAISCRIPT_NOEXCEPT :
std::runtime_error(format(t_why, t_where, t_fname, t_parameters, t_dot_notation, t_ss)),
reason(t_why), start_position(t_where), filename(t_fname), detail(format_detail(t_functions, t_dot_notation, t_ss))
{}
eval_error(const std::string &t_why, eval_error(const std::string &t_why,
const std::vector<Boxed_Value> &t_parameters, const std::vector<chaiscript::Const_Proxy_Function> &t_functions, const File_Position &t_where,
const std::string &t_fname,
const std::vector<Boxed_Value> &t_parameters,
const std::vector<chaiscript::Const_Proxy_Function> &t_functions,
bool t_dot_notation, bool t_dot_notation,
const chaiscript::detail::Dispatch_Engine &t_ss) CHAISCRIPT_NOEXCEPT : const chaiscript::detail::Dispatch_Engine &t_ss) noexcept
std::runtime_error(format(t_why, t_parameters, t_dot_notation, t_ss)), : std::runtime_error(format(t_why, t_where, t_fname, t_parameters, t_dot_notation, t_ss))
reason(t_why), detail(format_detail(t_functions, t_dot_notation, t_ss)) , reason(t_why)
{} , start_position(t_where)
, filename(t_fname)
, detail(format_detail(t_functions, t_dot_notation, t_ss)) {
}
eval_error(const std::string &t_why,
const std::vector<Boxed_Value> &t_parameters,
const std::vector<chaiscript::Const_Proxy_Function> &t_functions,
bool t_dot_notation,
const chaiscript::detail::Dispatch_Engine &t_ss) noexcept
: std::runtime_error(format(t_why, t_parameters, t_dot_notation, t_ss))
, reason(t_why)
, detail(format_detail(t_functions, t_dot_notation, t_ss)) {
}
eval_error(const std::string &t_why, const File_Position &t_where, const std::string &t_fname) CHAISCRIPT_NOEXCEPT : eval_error(const std::string &t_why, const File_Position &t_where, const std::string &t_fname) noexcept
std::runtime_error(format(t_why, t_where, t_fname)), : std::runtime_error(format(t_why, t_where, t_fname))
reason(t_why), start_position(t_where), filename(t_fname) , reason(t_why)
{} , start_position(t_where)
, filename(t_fname) {
}
eval_error(const std::string &t_why) CHAISCRIPT_NOEXCEPT explicit eval_error(const std::string &t_why) noexcept
: std::runtime_error("Error: \"" + t_why + "\" "), : std::runtime_error("Error: \"" + t_why + "\" ")
reason(t_why) , reason(t_why) {
{} }
eval_error(const eval_error &) = default; eval_error(const eval_error &) = default;
std::string pretty_print() const std::string pretty_print() const {
{
std::ostringstream ss; std::ostringstream ss;
ss << what(); ss << what();
if (call_stack.size() > 0) { if (!call_stack.empty()) {
ss << "during evaluation at (" << fname(call_stack[0]) << " " << startpos(call_stack[0]) << ")\n"; ss << "during evaluation at (" << fname(call_stack[0]) << " " << startpos(call_stack[0]) << ")\n";
ss << '\n' << detail << '\n'; ss << '\n'
<< detail << '\n';
ss << " " << fname(call_stack[0]) << " (" << startpos(call_stack[0]) << ") '" << pretty(call_stack[0]) << "'"; ss << " " << fname(call_stack[0]) << " (" << startpos(call_stack[0]) << ") '" << pretty(call_stack[0]) << "'";
for (size_t j = 1; j < call_stack.size(); ++j) { for (size_t j = 1; j < call_stack.size(); ++j) {
if (id(call_stack[j]) != chaiscript::AST_Node_Type::Block if (id(call_stack[j]) != chaiscript::AST_Node_Type::Block && id(call_stack[j]) != chaiscript::AST_Node_Type::File) {
&& id(call_stack[j]) != chaiscript::AST_Node_Type::File)
{
ss << '\n'; ss << '\n';
ss << " from " << fname(call_stack[j]) << " (" << startpos(call_stack[j]) << ") '" << pretty(call_stack[j]) << "'"; ss << " from " << fname(call_stack[j]) << " (" << startpos(call_stack[j]) << ") '" << pretty(call_stack[j]) << "'";
} }
@ -161,54 +363,42 @@ namespace chaiscript
return ss.str(); return ss.str();
} }
virtual ~eval_error() CHAISCRIPT_NOEXCEPT {} ~eval_error() noexcept override = default;
private: private:
template<typename T> template<typename T>
static int id(const T& t) static AST_Node_Type id(const T &t) noexcept {
{ return t.identifier;
return t->identifier;
} }
template<typename T> template<typename T>
static std::string pretty(const T& t) static std::string pretty(const T &t) {
{ return t.pretty_print();
return t->pretty_print();
} }
template<typename T> template<typename T>
static const std::string &fname(const T& t) static const std::string &fname(const T &t) noexcept {
{ return t.filename();
return t->filename();
} }
template<typename T> template<typename T>
static std::string startpos(const T& t) static std::string startpos(const T &t) {
{
std::ostringstream oss; std::ostringstream oss;
oss << t->start().line << ", " << t->start().column; oss << t.start().line << ", " << t.start().column;
return oss.str(); return oss.str();
} }
static std::string format_why(const std::string &t_why) static std::string format_why(const std::string &t_why) { return "Error: \"" + t_why + "\""; }
{
return "Error: \"" + t_why + "\"";
}
static std::string format_types(const Const_Proxy_Function &t_func, static std::string format_types(const Const_Proxy_Function &t_func, bool t_dot_notation, const chaiscript::detail::Dispatch_Engine &t_ss) {
bool t_dot_notation, assert(t_func);
const chaiscript::detail::Dispatch_Engine &t_ss)
{
int arity = t_func->get_arity(); int arity = t_func->get_arity();
std::vector<Type_Info> types = t_func->get_param_types(); std::vector<Type_Info> types = t_func->get_param_types();
std::string retval; std::string retval;
if (arity == -1) if (arity == -1) {
{
retval = "(...)"; retval = "(...)";
if (t_dot_notation) if (t_dot_notation) {
{
retval = "(Object)." + retval; retval = "(Object)." + retval;
} }
} else if (types.size() <= 1) { } else if (types.size() <= 1) {
@ -219,18 +409,13 @@ namespace chaiscript
std::string paramstr; std::string paramstr;
for (size_t index = 1; for (size_t index = 1; index != types.size(); ++index) {
index != types.size(); paramstr += (types[index].is_const() ? "const " : "");
++index)
{
paramstr += (types[index].is_const()?"const ":"");
paramstr += t_ss.get_type_name(types[index]); paramstr += t_ss.get_type_name(types[index]);
if (index == 1 && t_dot_notation) if (index == 1 && t_dot_notation) {
{
paramstr += ").("; paramstr += ").(";
if (types.size() == 2) if (types.size() == 2) {
{
paramstr += ", "; paramstr += ", ";
} }
} else { } else {
@ -244,19 +429,15 @@ namespace chaiscript
retval = ss.str(); retval = ss.str();
} }
std::shared_ptr<const dispatch::Dynamic_Proxy_Function> dynfun std::shared_ptr<const dispatch::Dynamic_Proxy_Function> dynfun
= std::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(t_func); = std::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(t_func);
if (dynfun) if (dynfun && dynfun->has_parse_tree()) {
{
Proxy_Function f = dynfun->get_guard(); Proxy_Function f = dynfun->get_guard();
if (f) if (f) {
{
auto dynfunguard = std::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(f); auto dynfunguard = std::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(f);
if (dynfunguard) if (dynfunguard && dynfunguard->has_parse_tree()) {
{
retval += " : " + format_guard(dynfunguard->get_parse_tree()); retval += " : " + format_guard(dynfunguard->get_parse_tree());
} }
} }
@ -268,69 +449,50 @@ namespace chaiscript
} }
template<typename T> template<typename T>
static std::string format_guard(const T &t) static std::string format_guard(const T &t) {
{ return t.pretty_print();
return t->pretty_print();
} }
template<typename T> template<typename T>
static std::string format_location(const T &t) static std::string format_location(const T &t) {
{
if (t) {
std::ostringstream oss; std::ostringstream oss;
oss << "(" << t->filename() << " " << t->start().line << ", " << t->start().column << ")"; oss << "(" << t.filename() << " " << t.start().line << ", " << t.start().column << ")";
return oss.str(); return oss.str();
} else {
return "(internal)";
}
} }
static std::string format_detail(const std::vector<chaiscript::Const_Proxy_Function> &t_functions, static std::string format_detail(const std::vector<chaiscript::Const_Proxy_Function> &t_functions,
bool t_dot_notation, bool t_dot_notation,
const chaiscript::detail::Dispatch_Engine &t_ss) const chaiscript::detail::Dispatch_Engine &t_ss) {
{
std::stringstream ss; std::stringstream ss;
if (t_functions.size() == 1) if (t_functions.size() == 1) {
{ assert(t_functions[0]);
ss << " Expected: " << format_types(t_functions[0], t_dot_notation, t_ss) << '\n'; ss << " Expected: " << format_types(t_functions[0], t_dot_notation, t_ss) << '\n';
} else { } else {
ss << " " << t_functions.size() << " overloads available:\n"; ss << " " << t_functions.size() << " overloads available:\n";
for (const auto & t_function : t_functions) for (const auto &t_function : t_functions) {
{
ss << " " << format_types((t_function), t_dot_notation, t_ss) << '\n'; ss << " " << format_types((t_function), t_dot_notation, t_ss) << '\n';
} }
} }
return ss.str(); return ss.str();
} }
static std::string format_parameters(const std::vector<Boxed_Value> &t_parameters, static std::string
bool t_dot_notation, format_parameters(const std::vector<Boxed_Value> &t_parameters, bool t_dot_notation, const chaiscript::detail::Dispatch_Engine &t_ss) {
const chaiscript::detail::Dispatch_Engine &t_ss)
{
std::stringstream ss; std::stringstream ss;
ss << "("; ss << "(";
if (!t_parameters.empty()) if (!t_parameters.empty()) {
{
std::string paramstr; std::string paramstr;
for (auto itr = t_parameters.begin(); for (auto itr = t_parameters.begin(); itr != t_parameters.end(); ++itr) {
itr != t_parameters.end(); paramstr += (itr->is_const() ? "const " : "");
++itr)
{
paramstr += (itr->is_const()?"const ":"");
paramstr += t_ss.type_name(*itr); paramstr += t_ss.type_name(*itr);
if (itr == t_parameters.begin() && t_dot_notation) if (itr == t_parameters.begin() && t_dot_notation) {
{
paramstr += ").("; paramstr += ").(";
if (t_parameters.size() == 1) if (t_parameters.size() == 1) {
{
paramstr += ", "; paramstr += ", ";
} }
} else { } else {
@ -345,12 +507,10 @@ namespace chaiscript
return ss.str(); return ss.str();
} }
static std::string format_filename(const std::string &t_fname) static std::string format_filename(const std::string &t_fname) {
{
std::stringstream ss; std::stringstream ss;
if (t_fname != "__EVAL__") if (t_fname != "__EVAL__") {
{
ss << "in '" << t_fname << "' "; ss << "in '" << t_fname << "' ";
} else { } else {
ss << "during evaluation "; ss << "during evaluation ";
@ -359,16 +519,18 @@ namespace chaiscript
return ss.str(); return ss.str();
} }
static std::string format_location(const File_Position &t_where) static std::string format_location(const File_Position &t_where) {
{
std::stringstream ss; std::stringstream ss;
ss << "at (" << t_where.line << ", " << t_where.column << ")"; ss << "at (" << t_where.line << ", " << t_where.column << ")";
return ss.str(); return ss.str();
} }
static std::string format(const std::string &t_why, const File_Position &t_where, const std::string &t_fname, static std::string format(const std::string &t_why,
const std::vector<Boxed_Value> &t_parameters, bool t_dot_notation, const chaiscript::detail::Dispatch_Engine &t_ss) const File_Position &t_where,
{ const std::string &t_fname,
const std::vector<Boxed_Value> &t_parameters,
bool t_dot_notation,
const chaiscript::detail::Dispatch_Engine &t_ss) {
std::stringstream ss; std::stringstream ss;
ss << format_why(t_why); ss << format_why(t_why);
@ -388,8 +550,7 @@ namespace chaiscript
static std::string format(const std::string &t_why, static std::string format(const std::string &t_why,
const std::vector<Boxed_Value> &t_parameters, const std::vector<Boxed_Value> &t_parameters,
bool t_dot_notation, bool t_dot_notation,
const chaiscript::detail::Dispatch_Engine &t_ss) const chaiscript::detail::Dispatch_Engine &t_ss) {
{
std::stringstream ss; std::stringstream ss;
ss << format_why(t_why); ss << format_why(t_why);
@ -401,8 +562,7 @@ namespace chaiscript
return ss.str(); return ss.str();
} }
static std::string format(const std::string &t_why, const File_Position &t_where, const std::string &t_fname) static std::string format(const std::string &t_why, const File_Position &t_where, const std::string &t_fname) {
{
std::stringstream ss; std::stringstream ss;
ss << format_why(t_why); ss << format_why(t_why);
@ -417,218 +577,125 @@ namespace chaiscript
} }
}; };
/// Errors generated when loading a file /// Errors generated when loading a file
struct file_not_found_error : std::runtime_error { struct file_not_found_error : std::runtime_error {
file_not_found_error(const std::string &t_filename) CHAISCRIPT_NOEXCEPT explicit file_not_found_error(const std::string &t_filename)
: std::runtime_error("File Not Found: " + t_filename) : std::runtime_error("File Not Found: " + t_filename)
{ } , filename(t_filename) {
}
file_not_found_error(const file_not_found_error &) = default; file_not_found_error(const file_not_found_error &) = default;
virtual ~file_not_found_error() CHAISCRIPT_NOEXCEPT {} ~file_not_found_error() noexcept override = default;
std::string filename;
}; };
} } // namespace exception
//static
/// \brief Struct that doubles as both a parser ast_node and an AST node. bool AST_Node::get_bool_condition(const Boxed_Value &t_bv, const chaiscript::detail::Dispatch_State &t_ss) {
struct AST_Node : std::enable_shared_from_this<AST_Node> {
public:
const int identifier; //< \todo shouldn't this be a strongly typed enum value?
const std::string text;
Parse_Location location;
std::vector<AST_NodePtr> children;
AST_NodePtr annotation;
const std::string &filename() const {
return *location.filename;
}
const File_Position &start() const {
return location.start;
}
const File_Position &end() const {
return location.end;
}
virtual std::string pretty_print() const
{
std::ostringstream oss;
oss << text;
for (auto & elem : this->children) {
oss << elem->pretty_print();
}
return oss.str();
}
/// Prints the contents of an AST node, including its children, recursively
std::string to_string(const std::string &t_prepend = "") const {
std::ostringstream oss;
oss << t_prepend << "(" << ast_node_type_to_string(this->identifier) << ") "
<< this->text << " : " << this->location.start.line << ", " << this->location.start.column << '\n';
for (auto & elem : this->children) {
oss << elem->to_string(t_prepend + " ");
}
return oss.str();
}
Boxed_Value eval(const chaiscript::detail::Dispatch_State &t_e) const
{
try { try {
return eval_internal(t_e); return t_ss->boxed_cast<bool>(t_bv);
} catch (exception::eval_error &ee) { } catch (const exception::bad_boxed_cast &) {
ee.call_stack.push_back(shared_from_this());
throw;
}
}
static bool get_bool_condition(const Boxed_Value &t_bv) {
try {
return boxed_cast<bool>(t_bv);
}
catch (const exception::bad_boxed_cast &) {
throw exception::eval_error("Condition not boolean"); throw exception::eval_error("Condition not boolean");
} }
} }
namespace parser {
class ChaiScript_Parser_Base {
public:
virtual AST_NodePtr parse(const std::string &t_input, const std::string &t_fname) = 0;
virtual void debug_print(const AST_Node &t, std::string prepend = "") const = 0;
virtual void *get_tracer_ptr() = 0;
virtual ~ChaiScript_Parser_Base() = default;
ChaiScript_Parser_Base() = default;
ChaiScript_Parser_Base(ChaiScript_Parser_Base &&) = default;
ChaiScript_Parser_Base &operator=(ChaiScript_Parser_Base &&) = delete;
ChaiScript_Parser_Base &operator=(const ChaiScript_Parser_Base &&) = delete;
void replace_child(const AST_NodePtr &t_child, const AST_NodePtr &t_new_child) template<typename T>
{ T &get_tracer() noexcept {
std::replace(children.begin(), children.end(), t_child, t_new_child); // to do type check this somehow?
return *static_cast<T *>(get_tracer_ptr());
} }
virtual ~AST_Node() {}
protected: protected:
AST_Node(std::string t_ast_node_text, int t_id, Parse_Location t_loc, ChaiScript_Parser_Base(const ChaiScript_Parser_Base &) = default;
std::vector<AST_NodePtr> t_children = std::vector<AST_NodePtr>()) :
identifier(t_id), text(std::move(t_ast_node_text)),
location(std::move(t_loc)),
children(std::move(t_children))
{
}
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &) const
{
throw std::runtime_error("Undispatched ast_node (internal error)");
}
private:
// Copy and assignment explicitly unimplemented
AST_Node(const AST_Node &) = delete;
AST_Node& operator=(const AST_Node &) = delete;
}; };
} // namespace parser
namespace eval {
namespace eval namespace detail {
{
namespace detail
{
/// Special type for returned values /// Special type for returned values
struct Return_Value { struct Return_Value {
Boxed_Value retval; Boxed_Value retval;
Return_Value(Boxed_Value t_return_value) : retval(std::move(t_return_value)) { }
}; };
/// Special type indicating a call to 'break' /// Special type indicating a call to 'break'
struct Break_Loop { struct Break_Loop {
Break_Loop() { }
}; };
/// Special type indicating a call to 'continue' /// Special type indicating a call to 'continue'
struct Continue_Loop { struct Continue_Loop {
Continue_Loop() { }
}; };
/// Creates a new scope then pops it on destruction /// Creates a new scope then pops it on destruction
struct Scope_Push_Pop struct Scope_Push_Pop {
{ Scope_Push_Pop(Scope_Push_Pop &&) = default;
Scope_Push_Pop &operator=(Scope_Push_Pop &&) = delete;
Scope_Push_Pop(const Scope_Push_Pop &) = delete; Scope_Push_Pop(const Scope_Push_Pop &) = delete;
Scope_Push_Pop& operator=(const Scope_Push_Pop &) = delete; Scope_Push_Pop &operator=(const Scope_Push_Pop &) = delete;
Scope_Push_Pop(const chaiscript::detail::Dispatch_State &t_ds) explicit Scope_Push_Pop(const chaiscript::detail::Dispatch_State &t_ds)
: m_ds(t_ds) : m_ds(t_ds) {
{ m_ds->new_scope(m_ds.stack_holder());
m_ds.get()->new_scope(m_ds.get().stack_holder());
}
~Scope_Push_Pop()
{
m_ds.get()->pop_scope(m_ds.get().stack_holder());
} }
~Scope_Push_Pop() { m_ds->pop_scope(m_ds.stack_holder()); }
private: private:
std::reference_wrapper<const chaiscript::detail::Dispatch_State> m_ds; const chaiscript::detail::Dispatch_State &m_ds;
}; };
/// Creates a new function call and pops it on destruction /// Creates a new function call and pops it on destruction
struct Function_Push_Pop struct Function_Push_Pop {
{ Function_Push_Pop(Function_Push_Pop &&) = default;
Function_Push_Pop &operator=(Function_Push_Pop &&) = delete;
Function_Push_Pop(const Function_Push_Pop &) = delete; Function_Push_Pop(const Function_Push_Pop &) = delete;
Function_Push_Pop& operator=(const Function_Push_Pop &) = delete; Function_Push_Pop &operator=(const Function_Push_Pop &) = delete;
Function_Push_Pop(const chaiscript::detail::Dispatch_State &t_ds) explicit Function_Push_Pop(const chaiscript::detail::Dispatch_State &t_ds)
: m_ds(t_ds) : m_ds(t_ds) {
{ m_ds->new_function_call(m_ds.stack_holder(), m_ds.conversion_saves());
m_ds.get()->new_function_call(m_ds.get().stack_holder());
} }
~Function_Push_Pop() ~Function_Push_Pop() { m_ds->pop_function_call(m_ds.stack_holder(), m_ds.conversion_saves()); }
{
m_ds.get()->pop_function_call(m_ds.get().stack_holder());
}
void save_params(const std::vector<Boxed_Value> &t_params)
{
m_ds.get()->save_function_params(t_params);
}
void save_params(std::initializer_list<Boxed_Value> t_params)
{
m_ds.get()->save_function_params(std::move(t_params));
}
void save_params(const Function_Params &t_params) { m_ds->save_function_params(t_params); }
private: private:
std::reference_wrapper<const chaiscript::detail::Dispatch_State> m_ds; const chaiscript::detail::Dispatch_State &m_ds;
}; };
/// Creates a new scope then pops it on destruction /// Creates a new scope then pops it on destruction
struct Stack_Push_Pop struct Stack_Push_Pop {
{ Stack_Push_Pop(Stack_Push_Pop &&) = default;
Stack_Push_Pop &operator=(Stack_Push_Pop &&) = delete;
Stack_Push_Pop(const Stack_Push_Pop &) = delete; Stack_Push_Pop(const Stack_Push_Pop &) = delete;
Stack_Push_Pop& operator=(const Stack_Push_Pop &) = delete; Stack_Push_Pop &operator=(const Stack_Push_Pop &) = delete;
Stack_Push_Pop(const chaiscript::detail::Dispatch_State &t_ds) explicit Stack_Push_Pop(const chaiscript::detail::Dispatch_State &t_ds)
: m_ds(t_ds) : m_ds(t_ds) {
{ m_ds->new_stack(m_ds.stack_holder());
m_ds.get()->new_stack(m_ds.get().stack_holder());
}
~Stack_Push_Pop()
{
m_ds.get()->pop_stack(m_ds.get().stack_holder());
} }
~Stack_Push_Pop() { m_ds->pop_stack(m_ds.stack_holder()); }
private: private:
std::reference_wrapper<const chaiscript::detail::Dispatch_State> m_ds; const chaiscript::detail::Dispatch_State &m_ds;
}; };
} } // namespace detail
} } // namespace eval
} } // namespace chaiscript
#endif /* _CHAISCRIPT_COMMON_HPP */ #endif /* _CHAISCRIPT_COMMON_HPP */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,433 @@
// 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
#ifndef CHAISCRIPT_OPTIMIZER_HPP_
#define CHAISCRIPT_OPTIMIZER_HPP_
#include "chaiscript_eval.hpp"
namespace chaiscript {
namespace optimizer {
template<typename... T>
struct Optimizer : T... {
Optimizer() = default;
explicit Optimizer(T... t)
: T(std::move(t))... {
}
template<typename Tracer>
auto optimize(eval::AST_Node_Impl_Ptr<Tracer> p) {
((p = static_cast<T &>(*this).optimize(std::move(p))), ...);
return p;
}
};
template<typename T>
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>
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(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(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() = std::move(block_last_child->children[0]);
}
}
}
}
return p;
}
};
template<typename T>
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;
}
const auto num = child_count(node);
for (size_t i = 0; i < num; ++i) {
const auto &child = child_at(node, i);
if (child.identifier != AST_Node_Type::Block && child.identifier != AST_Node_Type::For
&& child.identifier != AST_Node_Type::Ranged_For && contains_var_decl_in_scope(child)) {
return true;
}
}
return false;
}
struct Block {
template<typename T>
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 std::move(node->children[0]);
} else {
return chaiscript::make_unique<eval::AST_Node_Impl<T>, eval::Scopeless_Block_AST_Node<T>>(node->text,
node->location,
std::move(node->children));
}
}
}
return node;
}
};
struct Dead_Code {
template<typename T>
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) {
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 {
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(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_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;
}
};
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(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 std::move(node->children[1]);
} else if (node->children.size() == 3) {
return std::move(node->children[2]);
}
}
}
return node;
}
};
struct Partial_Fold {
template<typename T>
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) {
try {
const auto &oper = node->text;
const auto parsed = Operators::to_operator(oper);
if (parsed != Operators::Opers::invalid) {
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_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
}
}
return node;
}
};
struct Constant_Fold {
template<typename T>
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 = 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_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_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
}
} else if ((node->identifier == AST_Node_Type::Logical_And || node->identifier == AST_Node_Type::Logical_Or)
&& node->children.size() == 2 && node->children[0]->identifier == AST_Node_Type::Constant
&& node->children[1]->identifier == AST_Node_Type::Constant) {
try {
const auto lhs = 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);
}
}();
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
}
} 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 = 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 match = node->children[0]->text + " " + oper + " " + node->children[1]->text;
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
}
} 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 match = fun_name + "(" + node->children[1]->children[0]->text + ")";
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") {
return make_constant(Boxed_Number(arg).get_as<double>());
} else if (fun_name == "int") {
return make_constant(Boxed_Number(arg).get_as<int>());
} else if (fun_name == "float") {
return make_constant(Boxed_Number(arg).get_as<float>());
} else if (fun_name == "long") {
return make_constant(Boxed_Number(arg).get_as<long>());
} else if (fun_name == "size_t") {
return make_constant(Boxed_Number(arg).get_as<size_t>());
}
}
}
return node;
}
};
struct For_Loop {
template<typename T>
auto optimize(eval::AST_Node_Impl_Ptr<T> for_node) {
if (for_node->identifier != AST_Node_Type::For) {
return for_node;
}
const auto &eq_node = child_at(*for_node, 0);
const auto &binary_node = child_at(*for_node, 1);
const auto &prefix_node = child_at(*for_node, 2);
if (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);
// 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(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));
try {
for (; i < end_int; ++i) {
try {
// Body of Loop
children[0]->eval(t_ss);
} catch (eval::detail::Continue_Loop &) {
// we got a continue exception, which means all of the remaining
// loop implementation is skipped and we just need to continue to
// the next iteration step
}
}
} catch (eval::detail::Break_Loop &) {
// loop broken
}
return void_var();
});
} else {
return for_node;
}
} else {
return for_node;
}
}
};
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

@ -0,0 +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-2018, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_POSIX_HPP_
#define CHAISCRIPT_POSIX_HPP_
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(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,539 +0,0 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// and Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_PRELUDE_HPP_
#define CHAISCRIPT_PRELUDE_HPP_
namespace chaiscript {
struct ChaiScript_Prelude {
static std::string chaiscript_prelude() { return 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 eq(l, r) {
if (call_exists(`==`, l, r)) {
l == r
} else {
false
}
}
def new(x) {
eval(type_name(x))();
}
def clone(double x) {
double(x).clone_var_attrs(x)
}
def clone(string x) {
string(x).clone_var_attrs(x)
}
def clone(vector x) {
vector(x).clone_var_attrs(x)
}
def clone(int x) {
int(x).clone_var_attrs(x)
}
def clone(x) : function_exists(type_name(x)) && call_exists(eval(type_name(x)), x)
{
eval(type_name(x))(x).clone_var_attrs(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() + ">";
}
# to_string for containers
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());
}
# Prints to console with carriage return
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
}
}
# Returns the minimum value of two numbers
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
}
}
# Returns true if the value is even
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));
}
# 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;
}
def range(r) : call_exists(range_internal, r)
{
var ri := range_internal(r);
ri.get_var_attr("internal_obj") := r;
ri;
}
# Return a range from a range
def range(r) : call_exists(empty, r) && call_exists(pop_front, r) && call_exists(pop_back, r) && call_exists(back, r) && call_exists(front, r)
{
clone(r);
}
# The retro attribute that contains the underlying range
attr retro::m_range;
# 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)
}
# 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;
}
# Returns the first value of a retro
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()
{
pop_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)
}
# 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 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;
}
t_range.pop_front();
}
false;
}
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();
}
}
# 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);
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;
}
# Returns the sum of the elements of the given value
def sum(container) {
foldl(container, `+`, 0.0)
}
# Returns the product of the elements of the given value
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 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));
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;
}
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;
}
# 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;
}
# 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 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);
filter(container, f, back_inserter(retval));
retval;
}
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;
}
# Returns a new Vector with the first value to the second value as its elements
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();
}
}
# 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));
retval;
}
# Returns a new Vector which joins matching elements of the first and second
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));
}
# 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));
}
# 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));
}
# 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));
}
# 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));
}
# 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 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)
}
)"";
}
};
}
#endif /* CHAISCRIPT_PRELUDE_HPP_ */

View File

@ -0,0 +1,562 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@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(
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 eq(l, r) {
if (call_exists(`==`, l, r)) {
l == r
} else {
false
}
}
def new(x) {
eval(type_name(x))();
}
def clone(double x) {
double(x).clone_var_attrs(x)
}
def clone(string x) {
string(x).clone_var_attrs(x)
}
def clone(vector x) {
vector(x).clone_var_attrs(x)
}
def clone(int x) {
int(x).clone_var_attrs(x)
}
def clone(x) : function_exists(type_name(x)) && call_exists(eval(type_name(x)), x)
{
eval(type_name(x))(x).clone_var_attrs(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() + ">";
}
# to_string for containers
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());
}
# Prints to console with carriage return
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
}
}
# Returns the minimum value of two numbers
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
}
}
# Returns true if the value is even
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));
}
# 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;
}
def range(r) : call_exists(range_internal, r)
{
var ri := range_internal(r);
ri.get_var_attr("internal_obj") := r;
ri;
}
# Return a range from a range
def range(r) : call_exists(empty, r) && call_exists(pop_front, r) && call_exists(pop_back, r) && call_exists(back, r) && call_exists(front, r)
{
clone(r);
}
# The retro attribute that contains the underlying range
attr retro::m_range;
# 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)
}
# 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;
}
# Returns the first value of a retro
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()
{
pop_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)
}
# 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 any_of(container, func) : call_exists(range, container) {
var t_range := range(container);
while (!t_range.empty()) {
if (func(t_range.front())) {
return true;
}
t_range.pop_front();
}
false;
}
def all_of(container, func) : call_exists(range, container) {
var t_range := range(container);
while (!t_range.empty()) {
if (!func(t_range.front())) {
return false;
}
t_range.pop_front();
}
true;
}
def back_inserter(container) {
bind(push_back, container, _);
}
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;
}
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();
}
}
# 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);
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;
}
# Returns the sum of the elements of the given value
def sum(container) {
foldl(container, `+`, 0.0)
}
# Returns the product of the elements of the given value
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 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));
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;
}
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;
}
# 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;
}
# 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 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);
filter(container, f, back_inserter(retval));
retval;
}
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;
}
# Returns a new Vector with the first value to the second value as its elements
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();
}
}
# 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));
retval;
}
# Returns a new Vector which joins matching elements of the first and second
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));
}
# 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));
}
# 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));
}
# 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));
}
# 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));
}
# 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 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_ */

View File

@ -2,26 +2,22 @@
/// regarding the ChaiScript standard runtime library. /// regarding the ChaiScript standard runtime library.
/// \brief Items in this namespace exist in the ChaiScript language runtime. They are not part of the C++ API /// \brief Items in this namespace exist in the ChaiScript language runtime. They are not part of the C++ API
namespace ChaiScript_Language namespace ChaiScript_Language {
{ /// \page LangStandardLibraryRef ChaiScript Language Standard Library Reference
///
/// ChaiScript, at its core, has some very functional programming-inspired habits. Few places show this off as clearly
/// as the prelude, itself a name taken as a nod to the popular functional language Haskell. This prelude is available
/// to all standard ChaiScript applications, and provides a simple foundation for using numbers, strings, and ranges
/// (the general category of Range cs and their iteration).
///
/// \page LangStandardLibraryRef ChaiScript Language Standard Library Reference /// \brief Generic concept of a value in ChaiScript.
/// ///
/// ChaiScript, at its core, has some very functional programming-inspired habits. Few places show this off as clearly /// The Object type exists merely as a concept. All objects in ChaiScript support this concept
/// as the prelude, itself a name taken as a nod to the popular functional language Haskell. This prelude is available /// and have the following methods available to them. All objects are stored internally as chaiscript::Boxed_Value types.
/// to all standard ChaiScript applications, and provides a simple foundation for using numbers, strings, and ranges ///
/// (the general category of Range cs and their iteration). /// \sa chaiscript::Boxed_Value
/// class Object {
/// \brief Generic concept of a value in ChaiScript.
///
/// The Object type exists merely as a concept. All objects in ChaiScript support this concept
/// and have the following methods available to them. All objects are stored internally as chaiscript::Boxed_Value types.
///
/// \sa chaiscript::Boxed_Value
class Object
{
public: public:
/// \brief Returns the Type_Info value for this Object /// \brief Returns the Type_Info value for this Object
Type_Info get_type_info() const; Type_Info get_type_info() const;
@ -51,42 +47,39 @@ class Object
/// ///
/// \sa Type_Info::name(); /// \sa Type_Info::name();
string type_name() const; string type_name() const;
}; };
/// \brief Item returned from a Range object from a Map /// \brief Item returned from a Range object from a Map
class Map_Pair class Map_Pair {
{
public: public:
/// \brief Returns the key of the Map entry /// \brief Returns the key of the Map entry
const string first(); const string first();
/// \brief Returns the value Object of the Map entry /// \brief Returns the value Object of the Map entry
Object second(); Object second();
}; };
/// \brief Maps strings to Objects
/// \brief Maps strings to Objects ///
/// /// ChaiScript has a built in shortcut for generating Map objects:
/// ChaiScript has a built in shortcut for generating Map objects: ///
/// /// Example:
/// Example: /// \code
/// \code /// eval> var m = ["a":1, "b":2];
/// eval> var m = ["a":1, "b":2]; /// [<a,1>, <b,2>]
/// [<a,1>, <b,2>] /// eval> m.count("a");
/// eval> m.count("a"); /// 1
/// 1 /// eval> m.count("c");
/// eval> m.count("c"); /// 0
/// 0 /// eval> m.size();
/// eval> m.size(); /// 2
/// 2 /// \endcode
/// \endcode ///
/// /// Implemented as std::map<Boxed_Value>
/// Implemented as std::map<Boxed_Value> ///
/// /// \sa Map_Pair
/// \sa Map_Pair /// \sa chaiscript::bootstrap::standard_library::map_type
/// \sa chaiscript::bootstrap::standard_library::map_type class Map {
class Map
{
public: public:
/// \brief Returns an object that implements the Range concept for the Map_Pair's in this Map /// \brief Returns an object that implements the Range concept for the Map_Pair's in this Map
Range range(); Range range();
@ -108,64 +101,57 @@ class Map
/// \brief Returns true if the map contains no items /// \brief Returns true if the map contains no items
bool empty() const; bool empty() const;
};
}; /// \brief A concept implemented by string, Vector and Map. It is convertible to Range, default constructable and back_insertable
class Container {
/// \brief A concept implemented by string, Vector and Map. It is convertible to Range, default constructable and back_insertable
class Container
{
public: public:
void push_back(Object); void push_back(Object);
Range range(); Range range();
Const_Range range() const; Const_Range range() const;
}; };
/// \brief Converts o into a string.
///
/// \code
/// eval> to_string(3).is_type("string") <br>
/// true<br>
/// \endcode
string to_string(Object o);
/// \brief Converts o into a string. /// \brief Prints o to the terminal, without a trailing carriage return. Applies conversions to string automatically.
/// /// \code
/// \code /// eval> puts("hi, "); puts("there")
/// eval> to_string(3).is_type("string") <br> /// hi, thereeval>
/// true<br> /// \endcode
/// \endcode /// \sa to_string
string to_string(Object o); /// \sa print
void puts(Object o);
/// \brief Prints o to the terminal, with a trailing carriage return. Applies conversions to string automatically
/// \code
/// eval> print("hello")
/// hello
/// eval>
/// \endcode
/// \sa to_string
/// \sa puts
void print(Object o);
/// \brief Prints o to the terminal, without a trailing carriage return. Applies conversions to string automatically. /// \brief ChaiScript representation of std::string. It is an std::string but only some member are exposed to ChaiScript.
/// \code ///
/// eval> puts("hi, "); puts("there") /// Because the ChaiScript string object is an std::string, it is directly convertible to and from std::string
/// hi, thereeval> /// using the chaiscript::boxed_cast and chaiscript::var functions.
/// \endcode ///
/// \sa to_string /// With the exception of string::trim, string::rtrim, string::ltrim, all members are direct pass-throughs to the
/// \sa print /// std::string of the same name.
void puts(Object o); ///
/// \note Object and function notations are equivalent in ChaiScript. This means that
/// \c "bob".find("b") and \c find("bob", "b") are exactly the same. Most examples below follow the
/// \brief Prints o to the terminal, with a trailing carriage return. Applies conversions to string automatically /// second formation of the function calls.
/// \code /// \sa \ref keyworddef for extending existing C++ classes in ChaiScript
/// eval> print("hello") /// \sa chaiscript::bootstrap::standard_library::string_type
/// hello class string {
/// eval>
/// \endcode
/// \sa to_string
/// \sa puts
void print(Object o);
/// \brief ChaiScript representation of std::string. It is an std::string but only some member are exposed to ChaiScript.
///
/// Because the ChaiScript string object is an std::string, it is directly convertible to and from std::string
/// using the chaiscript::boxed_cast and chaiscript::var functions.
///
/// With the exception of string::trim, string::rtrim, string::ltrim, all members are direct pass-throughs to the
/// std::string of the same name.
///
/// \note Object and function notations are equivalent in ChaiScript. This means that
/// \c "bob".find("b") and \c find("bob", "b") are exactly the same. Most examples below follow the
/// second formation of the function calls.
/// \sa \ref keyworddef for extending existing C++ classes in ChaiScript
/// \sa chaiscript::bootstrap::standard_library::string_type
class string
{
public: public:
/// \brief Finds the first instance of substr. /// \brief Finds the first instance of substr.
/// \code /// \code
@ -174,7 +160,6 @@ class string
/// \endcode /// \endcode
int find(string s) const; int find(string s) const;
/// \brief Finds the last instance of substr. /// \brief Finds the last instance of substr.
/// \code /// \code
/// eval> rfind("abab", "ab") /// eval> rfind("abab", "ab")
@ -281,16 +266,15 @@ class string
/// \brief Returns an object that implements the Const_Range concept for the characters of this string /// \brief Returns an object that implements the Const_Range concept for the characters of this string
Const_Range range() const; Const_Range range() const;
}; };
/// \brief A concept in ChaiScript that is implemented by \ref string, Vector and Map. It provides /// \brief A concept in ChaiScript that is implemented by \ref string, Vector and Map. It provides
/// easy iteration over the elements in a container. /// easy iteration over the elements in a container.
/// ///
/// Implemented by the template chaiscript::bootstrap::standard_library::Bidir_Range /// Implemented by the template chaiscript::bootstrap::standard_library::Bidir_Range
/// ///
/// \sa Const_Range /// \sa Const_Range
class Range class Range {
{
public: public:
/// \brief Returns the last item of the range /// \brief Returns the last item of the range
Object back(); Object back();
@ -311,17 +295,15 @@ class Range
/// ///
/// \post front() returns the element at front() + 1; /// \post front() returns the element at front() + 1;
void pop_front(); void pop_front();
};
}; /// \brief A concept in ChaiScript that is implemented by \ref string, Vector and Map. It provides
/// easy iteration over the elements in a container. Contained values are const.
/// \brief A concept in ChaiScript that is implemented by \ref string, Vector and Map. It provides ///
/// easy iteration over the elements in a container. Contained values are const. /// Implemented by the template chaiscript::bootstrap::standard_library::Const_Bidir_Range
/// ///
/// Implemented by the template chaiscript::bootstrap::standard_library::Const_Bidir_Range /// \sa Range
/// class Const_Range {
/// \sa Range
class Const_Range
{
public: public:
/// \brief Returns the last item of the range /// \brief Returns the last item of the range
const Object back(); const Object back();
@ -342,28 +324,26 @@ class Const_Range
/// ///
/// \post front() returns the element at front() + 1; /// \post front() returns the element at front() + 1;
void pop_front(); void pop_front();
};
}; /// \brief A vector of Objects
///
/// \brief A vector of Objects /// ChaiScript includes a shortcut for creating a Vector of Objects
/// ///
/// ChaiScript includes a shortcut for creating a Vector of Objects /// Example:
/// /// \code
/// Example: /// eval> var v = [1,2,3,4]
/// \code /// [1, 2, 3, 4]
/// eval> var v = [1,2,3,4] /// eval> v[0];
/// [1, 2, 3, 4] /// 1
/// eval> v[0]; /// eval> v.size();
/// 1 /// 4
/// eval> v.size(); /// \endcode
/// 4 ///
/// \endcode /// Implemented with std::vector<chaiscript::Boxed_Value>
/// ///
/// Implemented with std::vector<chaiscript::Boxed_Value> /// \sa chaiscript::bootstrap::standard_library::vector_type
/// class Vector {
/// \sa chaiscript::bootstrap::standard_library::vector_type
class Vector
{
public: public:
/// \brief returns the Object at the given index. Throws an exception if the index does not exist /// \brief returns the Object at the given index. Throws an exception if the index does not exist
Object operator[](int t_index); Object operator[](int t_index);
@ -417,11 +397,9 @@ class Vector
/// \brief Returns the number of elements in the Vector /// \brief Returns the number of elements in the Vector
int size() const; int size() const;
};
}; class Type_Info {
class Type_Info
{
public: public:
/// \brief Compares this Type_Info object with another one and returns true if the two types are the same /// \brief Compares this Type_Info object with another one and returns true if the two types are the same
/// after const, pointer, reference are removed. /// after const, pointer, reference are removed.
@ -450,32 +428,29 @@ class Type_Info
/// \brief Returns the ChaiScript registered name for the type if one exists. /// \brief Returns the ChaiScript registered name for the type if one exists.
string name() const; string name() const;
};
}; /// \brief Represents a function object in ChaiScript
///
/// A function object may be one function, such as:
/// \brief Represents a function object in ChaiScript /// \code
/// /// var f = fun(x) { return x; }
/// A function object may be one function, such as: /// \endcode
/// \code ///
/// var f = fun(x) { return x; } /// Or it may represent multiple functions
/// \endcode /// \code
/// /// var f2 = `-`; // represents the unary - as well as the set of binary - operators
/// Or it may represent multiple functions /// \endcode
/// \code ///
/// var f2 = `-`; // represents the unary - as well as the set of binary - operators /// Guarded function example
/// \endcode /// \code
/// /// def f3(x) : x > 2 {
/// Guarded function example /// return x;
/// \code /// }
/// def f3(x) : x > 2 { /// \endcode
/// return x; ///
/// } /// Examples in the function definitions below will reference these examples
/// \endcode class Function {
///
/// Examples in the function definitions below will reference these examples
class Function
{
public: public:
/// \brief Returns the annotation description of the function /// \brief Returns the annotation description of the function
string get_annotation() const; string get_annotation() const;
@ -505,7 +480,7 @@ class Function
/// \endcode /// \endcode
Vector get_contained_functions() const; Vector get_contained_functions() const;
/// \brief Returns a vector of the contained functions /// \brief Returns a function guard as function
/// ///
/// Example: /// Example:
/// \code /// \code
@ -545,286 +520,264 @@ class Function
/// 1 /// 1
/// \endcode /// \endcode
Object call(Vector t_params) const; Object call(Vector t_params) const;
} }
/// \brief Returns the max of a or b. Requires that operator>(a, b) exists
/// Equivalent to
/// \code
/// return a>b?a:b;
/// \endcode
///
/// Example:
/// \code
/// eval> max(4, 10)
/// 10
/// \endcode
Object
max(Object a, Object b);
/// \brief Returns the min of a or b. Requires that operator<(a, b) exists
///
/// Equivalent to
/// \code
/// return a<b?a:b;
/// \endcode
///
/// Example:
/// \code
/// eval> min(4, 10)
/// 4
/// \endcode
Object min(Object a, Object b);
/// \brief Returns the max of a or b. Requires that operator>(a, b) exists /// \brief Returns true if x is an even integer.
/// Equivalent to ///
/// \code /// Will also work on any non-integer type for which an operator%(x, int) exists
/// return a>b?a:b; ///
/// \endcode /// Example:
/// /// \code
/// Example: /// eval> even(4)
/// \code /// true
/// eval> max(4, 10) /// \endcode
/// 10 bool even(Object x);
/// \endcode
Object max(Object a, Object b);
/// \brief Returns the min of a or b. Requires that operator<(a, b) exists /// \brief Returns true if x is an odd integer.
/// ///
/// Equivalent to /// Will also work on any non-integer type for which an operator%(x, int) exists
/// \code ///
/// return a<b?a:b; /// Example:
/// \endcode /// \code
/// /// eval> odd(4)
/// Example: /// false
/// \code /// \endcode
/// eval> min(4, 10) bool even(Object x);
/// 4
/// \endcode
Object min(Object a, Object b);
/// \brief Returns true if x is an even integer. /// \brief Applies the function f over each element in the Range c.
/// ///
/// Will also work on any non-integer type for which an operator%(x, int) exists /// Example:
/// /// \code
/// Example: /// eval> for_each([1, 2, 3], print)
/// \code /// 1
/// eval> even(4) /// 2
/// true /// 3
/// \endcode /// \endcode
bool even(Object x); void for_each(Range c, Function f);
/// \brief Returns true if x is an odd integer. /// \brief Applies f over each element in the Range c, joining all the results.
/// ///
/// Will also work on any non-integer type for which an operator%(x, int) exists /// Example:
/// /// \code
/// Example: /// eval> map([1, 2, 3], odd)
/// \code /// [true, false, true]
/// eval> odd(4) /// \endcode
/// false Object map(Range c, Function f);
/// \endcode
bool even(Object x);
/// \brief Starts with the initial value and applies the function f to it and the first element of the Range c.
/// The result is then applied to the second element, and so on until the elements are exhausted.
///
/// Example:
/// \code
/// eval> foldl([1, 2, 3, 4], `+`, 0)
/// 10
/// \endcode
Object foldl(Range c, Function f, Object initial);
/// \brief Applies the function f over each element in the Range c. /// \brief Returns the sum total of the values in the Range c.
/// ///
/// Example: /// Example:
/// \code /// \code
/// eval> for_each([1, 2, 3], print) /// eval> sum([1, 2, 3, 4])
/// 1 /// 10
/// 2 /// \endcode
/// 3 ///
/// \endcode /// Equivalent to:
void for_each(Range c, Function f); /// \code
/// foldl(c, `+`, 0.0);
/// \endcode
Numeric sum(Range c);
/// \brief Returns the product of the value in the Range c.
///
/// Example:
/// \code
/// eval> product([1, 2, 3, 4])
/// 24
/// \endcode
///
/// Equivalent to:
/// \code
/// foldl(c, `*`, 1.0);
/// \endcode
Numeric product(Range c);
/// \brief Applies f over each element in the Range c, joining all the results. /// \brief Takes num elements from the Range c, returning them.
/// ///
/// Example: /// Example:
/// \code /// \code
/// eval> map([1, 2, 3], odd) /// eval> take([1, 2, 3, 4], 2)
/// [true, false, true] /// [1, 2]
/// \endcode /// \endcode
Object map(Range c, Function f); ///
/// \returns A container of the same type that was passed in
Object take(Range c, int num);
/// \brief Takes elements from the Range c that match function f, stopping at the first non-match, returning them as a new Vector.
///
/// Example:
/// \code
/// eval> take_while([1, 2, 3], odd)
/// [1]
/// \endcode
///
/// \returns A container of the same type that was passed in
Object take_while(Range c, Function f);
/// \brief Starts with the initial value and applies the function f to it and the first element of the Range c. /// \brief Drops num elements from the Range c, returning the remainder.
/// The result is then applied to the second element, and so on until the elements are exhausted. ///
/// /// Example:
/// Example: /// \code
/// \code /// eval> drop([1, 2, 3, 4], 2)
/// eval> foldl([1, 2, 3, 4], `+`, 0) /// [3, 4]
/// 10 /// \endcode
/// \endcode ///
Object foldl(Range c, Function f, Object initial); /// \returns A container of the same type that was passed in
Object drop(Range c, int num);
/// \brief Drops elements from the Range c that match f, stopping at the first non-match, returning the remainder.
///
/// Example:
/// \code
/// eval> drop_while([1, 2, 3], odd)
/// [2, 3]
/// \endcode
Object drop_while(Range c, Function f);
/// \brief Returns the sum total of the values in the Range c. /// \brief Similar to foldl, this takes the first two elements as its starting values for f. This assumes Range c has at least 2 elements.
/// ///
/// Example: /// Example:
/// \code /// \code
/// eval> sum([1, 2, 3, 4]) /// eval> reduce([1, 2, 3, 4], `+`)
/// 10 /// 10
/// \endcode /// \endcode
/// Object reduce(Range c, Function f);
/// Equivalent to:
/// \code
/// foldl(c, `+`, 0.0);
/// \endcode
Numeric sum(Range c);
/// \brief Takes elements from Container c that match function f, return them.
///
/// Example:
/// \code
/// eval> filter([1, 2, 3, 4], odd)
/// [1, 3]
/// \endcode
Object filter(Container c, Function f);
/// \brief Returns the product of the value in the Range c. /// \brief Joins the elements of the Range c into a string, delimiting each with the delim string.
/// ///
/// Example: /// Example:
/// \code /// \code
/// eval> product([1, 2, 3, 4]) /// eval> join([1, 2, 3], "*")
/// 24 /// 1*2*3
/// \endcode /// \endcode
/// string join(Range c, string delim);
/// Equivalent to:
/// \code
/// foldl(c, `*`, 1.0);
/// \endcode
Numeric product(Range c);
/// \brief Returns the contents of the Container c in reversed order.
///
/// Example:
/// \code
/// eval> reverse([1, 2, 3, 4, 5, 6, 7])
/// [7, 6, 5, 4, 3, 2, 1]
/// \endcode
Container reverse(Container c);
/// \brief Takes num elements from the Range c, returning them. /// \brief Generates a new Vector filled with values starting at x and ending with y.
/// ///
/// Example: /// Works on types supporting operator<=(x, y) and operator++(x)
/// \code ///
/// eval> take([1, 2, 3, 4], 2) /// Example:
/// [1, 2] /// \code
/// \endcode /// eval> generate_range(1, 10)
/// /// [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
/// \returns A container of the same type that was passed in /// \endcode
Object take(Range c, int num); Vector generate_range(Object x, Object y);
/// \brief Returns a new Range with x and y concatenated.
///
/// Example:
/// \code
/// eval> concat([1, 2, 3], [4, 5, 6])
/// [1, 2, 3, 4, 5, 6]
/// \endcode
Object concat(Range x, Range y);
/// \brief Takes elements from the Range c that match function f, stopping at the first non-match, returning them as a new Vector. /// \brief Returns a new Vector with x and y as its values.
/// ///
/// Example: /// Example:
/// \code /// \code
/// eval> take_while([1, 2, 3], odd) /// eval> collate(1, 2)
/// [1] /// [1, 2]
/// \endcode /// \endcode
/// Vector collate(Object x, Object y);
/// \returns A container of the same type that was passed in
Object take_while(Range c, Function f);
/// \brief Applies f to elements of x and y, returning a new Vector with the result of each application.
///
/// Example:
/// \code
/// eval> zip_with(`+`, [1, 2, 3], [4, 5, 6])
/// [5, 7, 9]
/// \endcode
Vector zip_with(Function f, Range x, Range y);
/// \brief Drops num elements from the Range c, returning the remainder. /// \brief Collates elements of x and y, returning a new Vector with the result.
/// ///
/// Example: /// Example:
/// \code /// \code
/// eval> drop([1, 2, 3, 4], 2) /// eval> zip([1, 2, 3], [4, 5, 6])
/// [3, 4] /// [[1, 4], [2, 5], [3, 6]]
/// \endcode /// \endcode
/// Vector zip(Range x, Range y);
/// \returns A container of the same type that was passed in
Object drop(Range c, int num);
/// \brief returns true if there exists a call to the Function f that takes the given parameters
///
/// Example:
/// \code
/// eval> call_exists(`+`, 1, 2)
/// true
/// \endcode
bool call_exists(Function f, ...);
/// \brief Drops elements from the Range c that match f, stopping at the first non-match, returning the remainder. /// \brief Reverses a Range object so that the elements are accessed in reverse
/// Range retro(Range);
/// Example:
/// \code
/// eval> drop_while([1, 2, 3], odd)
/// [2, 3]
/// \endcode
Object drop_while(Range c, Function f);
/// \brief Reverses a Const_Range object so that the elements are accessed in reverse
Const_Range retro(Const_Range);
/// \brief Similar to foldl, this takes the first two elements as its starting values for f. This assumes Range c has at least 2 elements. /// \brief Raises the given object as an exception. Any type of object can be thrown.
/// ///
/// Example: /// Example:
/// \code /// \code
/// eval> reduce([1, 2, 3, 4], `+`) /// eval> try { throw(1); } catch (e) { print("Exception caught: " + to_string(e)); }
/// 10 /// Exception caught: 1
/// \endcode /// \endcode
Object reduce(Range c, Function f); ///
/// \sa \ref keywordtry
void throw(Object);
/// \brief Takes elements from Container c that match function f, return them. } // namespace ChaiScript_Language
///
/// Example:
/// \code
/// eval> filter([1, 2, 3, 4], odd)
/// [1, 3]
/// \endcode
Object filter(Container c, Function f);
/// \brief Joins the elements of the Range c into a string, delimiting each with the delim string.
///
/// Example:
/// \code
/// eval> join([1, 2, 3], "*")
/// 1*2*3
/// \endcode
string join(Range c, string delim);
/// \brief Returns the contents of the Container c in reversed order.
///
/// Example:
/// \code
/// eval> reverse([1, 2, 3, 4, 5, 6, 7])
/// [7, 6, 5, 4, 3, 2, 1]
/// \endcode
Container reverse(Container c);
/// \brief Generates a new Vector filled with values starting at x and ending with y.
///
/// Works on types supporting operator<=(x, y) and operator++(x)
///
/// Example:
/// \code
/// eval> generate_range(1, 10)
/// [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
/// \endcode
Vector generate_range(Object x, Object y);
/// \brief Returns a new Range with x and y concatenated.
///
/// Example:
/// \code
/// eval> concat([1, 2, 3], [4, 5, 6])
/// [1, 2, 3, 4, 5, 6]
/// \endcode
Object concat(Range x, Range y);
/// \brief Returns a new Vector with x and y as its values.
///
/// Example:
/// \code
/// eval> collate(1, 2)
/// [1, 2]
/// \endcode
Vector collate(Object x, Object y);
/// \brief Applies f to elements of x and y, returning a new Vector with the result of each application.
///
/// Example:
/// \code
/// eval> zip_with(`+`, [1, 2, 3], [4, 5, 6])
/// [5, 7, 9]
/// \endcode
Vector zip_with(Function f, Range x, Range y);
/// \brief Collates elements of x and y, returning a new Vector with the result.
///
/// Example:
/// \code
/// eval> zip([1, 2, 3], [4, 5, 6])
/// [[1, 4], [2, 5], [3, 6]]
/// \endcode
Vector zip(Range x, Range y);
/// \brief returns true if there exists a call to the Function f that takes the given parameters
///
/// Example:
/// \code
/// eval> call_exists(`+`, 1, 2)
/// true
/// \endcode
bool call_exists(Function f, ...);
/// \brief Reverses a Range object so that the elements are accessed in reverse
Range retro(Range);
/// \brief Reverses a Const_Range object so that the elements are accessed in reverse
Const_Range retro(Const_Range);
/// \brief Raises the given object as an exception. Any type of object can be thrown.
///
/// Example:
/// \code
/// eval> try { throw(1); } catch (e) { print("Exception caught: " + to_string(e)); }
/// Exception caught: 1
/// \endcode
///
/// \sa \ref keywordtry
void throw(Object);
}

View File

@ -0,0 +1,37 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_TRACER_HPP_
#define CHAISCRIPT_TRACER_HPP_
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))... {
}
void do_trace(const chaiscript::detail::Dispatch_State &ds, const AST_Node_Impl<Tracer<T...>> *node) {
(static_cast<T &>(*this).trace(ds, node), ...);
}
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);
}
};
using Noop_Tracer = Tracer<Noop_Tracer_Detail>;
} // namespace chaiscript::eval
#endif

View File

@ -0,0 +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-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 &) {
#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

@ -0,0 +1,113 @@
// 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
#ifndef CHAISCRIPT_WINDOWS_HPP_
#define CHAISCRIPT_WINDOWS_HPP_
#include <string>
#ifdef CHAISCRIPT_WINDOWS
#define VC_EXTRA_LEAN
#if !defined(WIN32_LEAN_AND_MEAN)
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
#endif
namespace chaiscript {
namespace detail {
struct Loadable_Module {
template<typename T>
static std::wstring to_wstring(const T &t_str) {
return std::wstring(t_str.begin(), t_str.end());
}
template<typename T>
static std::string to_string(const T &t_str) {
return std::string(t_str.begin(), t_str.end());
}
#if defined(_UNICODE) || defined(UNICODE)
template<typename T>
static std::wstring to_proper_string(const T &t_str) {
return to_wstring(t_str);
}
#else
template<typename T>
static std::string to_proper_string(const T &t_str) {
return to_string(t_str);
}
#endif
static std::string get_error_message(DWORD t_err) {
using StringType = LPTSTR;
#if defined(_UNICODE) || defined(UNICODE)
std::wstring retval = L"Unknown Error";
#else
std::string retval = "Unknown Error";
#endif
StringType lpMsgBuf = nullptr;
if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
nullptr,
t_err,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
reinterpret_cast<StringType>(&lpMsgBuf),
0,
nullptr)
!= 0
&& lpMsgBuf) {
retval = lpMsgBuf;
LocalFree(lpMsgBuf);
}
return to_string(retval);
}
struct DLModule {
explicit DLModule(const std::string &t_filename)
: m_data(LoadLibrary(to_proper_string(t_filename).c_str())) {
if (!m_data) {
throw chaiscript::exception::load_module_error(get_error_message(GetLastError()));
}
}
DLModule(DLModule &&) = default;
DLModule &operator=(DLModule &&) = default;
DLModule(const DLModule &) = delete;
DLModule &operator=(const DLModule &) = delete;
~DLModule() { FreeLibrary(m_data); }
HMODULE m_data;
};
template<typename T>
struct DLSym {
DLSym(DLModule &t_mod, const std::string &t_symbol)
: m_symbol(reinterpret_cast<T>(GetProcAddress(t_mod.m_data, t_symbol.c_str()))) {
if (!m_symbol) {
throw chaiscript::exception::load_module_error(get_error_message(GetLastError()));
}
}
T m_symbol;
};
Loadable_Module(const std::string &t_module_name, const std::string &t_filename)
: m_dlmodule(t_filename)
, m_func(m_dlmodule, "create_chaiscript_module_" + t_module_name)
, m_moduleptr(m_func.m_symbol()) {
}
DLModule m_dlmodule;
DLSym<Create_Module_Func> m_func;
ModulePtr m_moduleptr;
};
} // namespace detail
} // namespace chaiscript
#endif

View File

@ -0,0 +1,38 @@
// 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
#ifndef CHAISCRIPT_UTILITY_FNV1A_HPP_
#define CHAISCRIPT_UTILITY_FNV1A_HPP_
#include "../chaiscript_defines.hpp"
#include <cstdint>
namespace chaiscript {
namespace utility {
static constexpr std::uint32_t fnv1a_32(const char *s, std::uint32_t h = 0x811c9dc5) {
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wsign-conversion"
#endif
#ifdef CHAISCRIPT_MSVC
#pragma warning(push)
#pragma warning(disable : 4307)
#endif
return (*s == 0) ? h : fnv1a_32(s + 1, ((h ^ (*s)) * 0x01000193));
#ifdef CHAISCRIPT_MSVC
#pragma warning(pop)
#endif
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
}
} // 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,82 +3,68 @@
#include "json.hpp" #include "json.hpp"
namespace chaiscript namespace chaiscript {
{ class json_wrap {
class json_wrap
{
public: public:
static Module &library(Module &m) {
static ModulePtr library(ModulePtr m = std::make_shared<Module>()) m.add(chaiscript::fun([](const std::string &t_str) { return from_json(t_str); }), "from_json");
{ m.add(chaiscript::fun(&json_wrap::to_json), "to_json");
m->add(chaiscript::fun([](const std::string &t_str) { return from_json(t_str); }), "from_json");
m->add(chaiscript::fun(&json_wrap::to_json), "to_json");
return m; return m;
} }
private: private:
static Boxed_Value from_json(const json::JSON &t_json) {
static Boxed_Value from_json(const json::JSON &t_json) switch (t_json.JSONType()) {
{
switch( t_json.JSONType() ) {
case json::JSON::Class::Null: case json::JSON::Class::Null:
return Boxed_Value(); return Boxed_Value();
case json::JSON::Class::Object: case json::JSON::Class::Object: {
{
std::map<std::string, Boxed_Value> m; std::map<std::string, Boxed_Value> m;
for (const auto &p : t_json.ObjectRange()) for (const auto &p : t_json.object_range()) {
{
m.insert(std::make_pair(p.first, from_json(p.second))); m.insert(std::make_pair(p.first, from_json(p.second)));
} }
return Boxed_Value(m); return Boxed_Value(m);
} }
case json::JSON::Class::Array: case json::JSON::Class::Array: {
{
std::vector<Boxed_Value> vec; std::vector<Boxed_Value> vec;
for (const auto &p : t_json.ArrayRange()) for (const auto &p : t_json.array_range()) {
{
vec.emplace_back(from_json(p)); vec.emplace_back(from_json(p));
} }
return Boxed_Value(vec); return Boxed_Value(vec);
} }
case json::JSON::Class::String: case json::JSON::Class::String:
return Boxed_Value(t_json.ToString()); return Boxed_Value(t_json.to_string());
case json::JSON::Class::Floating: case json::JSON::Class::Floating:
return Boxed_Value(t_json.ToFloat()); return Boxed_Value(t_json.to_float());
case json::JSON::Class::Integral: case json::JSON::Class::Integral:
return Boxed_Value(t_json.ToInt()); return Boxed_Value(t_json.to_int());
case json::JSON::Class::Boolean: case json::JSON::Class::Boolean:
return Boxed_Value(t_json.ToBool()); return Boxed_Value(t_json.to_bool());
} }
throw std::runtime_error("Unknown JSON type"); throw std::runtime_error("Unknown JSON type");
} }
static Boxed_Value from_json(const std::string &t_json) static Boxed_Value from_json(const std::string &t_json) {
{ try {
return from_json( json::JSON::Load(t_json) ); 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) static std::string to_json(const Boxed_Value &t_bv) { return to_json_object(t_bv).dump(); }
{
return to_json_object(t_bv).dump();
}
static json::JSON to_json_object(const Boxed_Value &t_bv) static json::JSON to_json_object(const Boxed_Value &t_bv) {
{
try { try {
const std::map<std::string, Boxed_Value> m = chaiscript::boxed_cast<const std::map<std::string, Boxed_Value> &>(t_bv); 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 obj(json::JSON::Class::Object);
for (const auto &o : m) for (const auto &o : m) {
{
obj[o.first] = to_json_object(o.second); obj[o.first] = to_json_object(o.second);
} }
return obj; return obj;
@ -89,9 +75,8 @@ namespace chaiscript
try { try {
const std::vector<Boxed_Value> v = chaiscript::boxed_cast<const std::vector<Boxed_Value> &>(t_bv); const std::vector<Boxed_Value> v = chaiscript::boxed_cast<const std::vector<Boxed_Value> &>(t_bv);
json::JSON obj; json::JSON obj(json::JSON::Class::Array);
for (size_t i = 0; i < v.size(); ++i) for (size_t i = 0; i < v.size(); ++i) {
{
obj[i] = to_json_object(v[i]); obj[i] = to_json_object(v[i]);
} }
return obj; return obj;
@ -99,46 +84,34 @@ namespace chaiscript
// not a vector // not a vector
} }
try { try {
Boxed_Number bn(t_bv); Boxed_Number bn(t_bv);
json::JSON obj; if (Boxed_Number::is_floating_point(t_bv)) {
if (Boxed_Number::is_floating_point(t_bv)) return json::JSON(bn.get_as<double>());
{
obj = bn.get_as<double>();
} else { } else {
obj = bn.get_as<long>(); return json::JSON(bn.get_as<std::int64_t>());
} }
return obj;
} catch (const chaiscript::detail::exception::bad_any_cast &) { } catch (const chaiscript::detail::exception::bad_any_cast &) {
// not a number // not a number
} }
try { try {
bool b = boxed_cast<bool>(t_bv); return json::JSON(boxed_cast<bool>(t_bv));
json::JSON obj;
obj = b;
return obj;
} catch (const chaiscript::exception::bad_boxed_cast &) { } catch (const chaiscript::exception::bad_boxed_cast &) {
// not a bool // not a bool
} }
try { try {
std::string s = boxed_cast<std::string>(t_bv); return json::JSON(boxed_cast<std::string>(t_bv));
json::JSON obj;
obj = s;
return obj;
} catch (const chaiscript::exception::bad_boxed_cast &) { } catch (const chaiscript::exception::bad_boxed_cast &) {
// not a string // not a string
} }
try { try {
const chaiscript::dispatch::Dynamic_Object &o = boxed_cast<const dispatch::Dynamic_Object &>(t_bv); const chaiscript::dispatch::Dynamic_Object &o = boxed_cast<const dispatch::Dynamic_Object &>(t_bv);
json::JSON obj; json::JSON obj(json::JSON::Class::Object);
for (const auto &attr : o.get_attrs()) for (const auto &attr : o.get_attrs()) {
{
obj[attr.first] = to_json_object(attr.second); obj[attr.first] = to_json_object(attr.second);
} }
return obj; return obj;
@ -146,13 +119,13 @@ namespace chaiscript
// not a dynamic object // 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"); throw std::runtime_error("Unknown object type to convert to JSON");
} }
}; };
} // namespace chaiscript
}
#endif #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

@ -0,0 +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-2018, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_UTILITY_STATIC_STRING_HPP_
#define CHAISCRIPT_UTILITY_STATIC_STRING_HPP_
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]) {
}
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;
}
++b1;
++b2;
}
return true;
}
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;
};
} // namespace chaiscript::utility
#endif

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