Merge pull request #144 from ChaiScript/develop

Merge release 5.5.0 to master
This commit is contained in:
Jason Turner 2014-11-10 12:48:25 -07:00
commit 4a3315cfd1
44 changed files with 3341 additions and 3353 deletions

13
.decent_ci-Linux.yaml Normal file
View File

@ -0,0 +1,13 @@
compilers:
- name: "clang"
version: "3.5"
cmake_extra_flags: -DUSE_LIBCXX:BOOL=OFF -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON
- name: "gcc"
version: "4.8"
cmake_extra_flags: -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DBUILD_TESTING:BOOL=ON
- name: "gcc"
version: "4.6"
cmake_extra_flags: -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON
- name: cppcheck
compiler_extra_flags: --enable=all -I include --inline-suppr

7
.decent_ci-MacOS.yaml Normal file
View File

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

20
.decent_ci-Windows.yaml Normal file
View File

@ -0,0 +1,20 @@
compilers:
- name: Visual Studio
version: 14
cmake_extra_flags: -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DCOMMIT_SHA=%COMMIT_SHA%
compiler_extra_flags: /ANALYZE
- name: Visual Studio
version: 14
architecture: Win64
cmake_extra_flags: -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DCOMMIT_SHA=%COMMIT_SHA%
compiler_extra_flags: /ANALYZE
- name: Visual Studio
version: 12
cmake_extra_flags: -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DCOMMIT_SHA=%COMMIT_SHA%
compiler_extra_flags: /ANALYZE
- name: Visual Studio
version: 12
architecture: Win64
cmake_extra_flags: -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DCOMMIT_SHA=%COMMIT_SHA%
compiler_extra_flags: /ANALYZE

4
.decent_ci.yaml Normal file
View File

@ -0,0 +1,4 @@
results_repository : ChaiScript/ChaiScript-BuildResults
results_path : _posts
results_base_url : https://chaiscript.github.io/ChaiScript-BuildResults
aging_pull_requests_notification: true

View File

@ -36,11 +36,38 @@ if(CMAKE_COMPILER_IS_GNUCC OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
set(LINKER_FLAGS "${LINKER_FLAGS} -fsanitize=address") set(LINKER_FLAGS "${LINKER_FLAGS} -fsanitize=address")
endif() endif()
option(ENABLE_MEMORY_SANITIZER "Enable memory sanitizer testing in gcc/clang" FALSE)
if(ENABLE_MEMORY_SANITIZER)
add_definitions(-fsanitize=memory -g)
set(LINKER_FLAGS "${LINKER_FLAGS} -fsanitize=memory")
endif()
option(ENABLE_UNDEFINED_SANITIZER "Enable undefined behavior sanitizer testing in gcc/clang" FALSE) option(ENABLE_UNDEFINED_SANITIZER "Enable undefined behavior sanitizer testing in gcc/clang" FALSE)
if(ENABLE_UNDEFINED_SANITIZER) if(ENABLE_UNDEFINED_SANITIZER)
add_definitions(-fsanitize=undefined -g) add_definitions(-fsanitize=undefined -g)
set(LINKER_FLAGS "${LINKER_FLAGS} -fsanitize=undefined") set(LINKER_FLAGS "${LINKER_FLAGS} -fsanitize=undefined")
endif() endif()
option(ENABLE_LTO "Enable Link Time Optimization" FALSE)
if (ENABLE_LTO)
add_definitions(-flto)
set(LINKER_FLAGS "${LINKER_FLAGS} -flto")
endif()
option(PROFILE_GENERATE "Generate profile data" FALSE)
if (PROFILE_GENERATE)
add_definitions(-fprofile-generate)
set(LINKER_FLAGS "${LINKER_FLAGS} -fprofile-generate")
endif()
option(PROFILE_USE "Use profile data" FALSE)
if (PROFILE_USE)
add_definitions(-fprofile-use)
set(LINKER_FLAGS "${LINKER_FLAGS} -fprofile-use")
endif()
endif() endif()
list(APPEND CPACK_SOURCE_IGNORE_FILES "${CMAKE_CURRENT_BINARY_DIR}") list(APPEND CPACK_SOURCE_IGNORE_FILES "${CMAKE_CURRENT_BINARY_DIR}")
@ -54,7 +81,7 @@ 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 5)
set(CPACK_PACKAGE_VERSION_MINOR 4) set(CPACK_PACKAGE_VERSION_MINOR 5)
set(CPACK_PACKAGE_VERSION_PATCH 0) set(CPACK_PACKAGE_VERSION_PATCH 0)
set(CPACK_PACKAGE_EXECUTABLES "chai;ChaiScript Eval") set(CPACK_PACKAGE_EXECUTABLES "chai;ChaiScript Eval")
@ -154,7 +181,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/dynamic_cast_conversion.hpp include/chaiscript/dispatchkit/dynamic_object.hpp include/chaiscript/dispatchkit/exception_specification.hpp include/chaiscript/dispatchkit/function_call.hpp include/chaiscript/dispatchkit/function_call_detail.hpp include/chaiscript/dispatchkit/handle_return.hpp include/chaiscript/dispatchkit/operators.hpp include/chaiscript/dispatchkit/proxy_constructors.hpp include/chaiscript/dispatchkit/proxy_functions.hpp include/chaiscript/dispatchkit/proxy_functions_detail.hpp include/chaiscript/dispatchkit/register_function.hpp include/chaiscript/dispatchkit/type_info.hpp include/chaiscript/language/chaiscript_algebraic.hpp include/chaiscript/language/chaiscript_common.hpp include/chaiscript/language/chaiscript_engine.hpp include/chaiscript/language/chaiscript_eval.hpp include/chaiscript/language/chaiscript_parser.hpp include/chaiscript/language/chaiscript_prelude.chai include/chaiscript/language/chaiscript_prelude_docs.hpp include/chaiscript/utility/utility.hpp) set(Chai_INCLUDES include/chaiscript/chaiscript.hpp include/chaiscript/chaiscript_threading.hpp include/chaiscript/dispatchkit/bad_boxed_cast.hpp include/chaiscript/dispatchkit/bind_first.hpp include/chaiscript/dispatchkit/bootstrap.hpp include/chaiscript/dispatchkit/bootstrap_stl.hpp include/chaiscript/dispatchkit/boxed_cast.hpp include/chaiscript/dispatchkit/boxed_cast_helper.hpp include/chaiscript/dispatchkit/boxed_number.hpp include/chaiscript/dispatchkit/boxed_value.hpp include/chaiscript/dispatchkit/dispatchkit.hpp include/chaiscript/dispatchkit/type_conversions.hpp include/chaiscript/dispatchkit/dynamic_object.hpp include/chaiscript/dispatchkit/exception_specification.hpp include/chaiscript/dispatchkit/function_call.hpp include/chaiscript/dispatchkit/function_call_detail.hpp include/chaiscript/dispatchkit/handle_return.hpp include/chaiscript/dispatchkit/operators.hpp include/chaiscript/dispatchkit/proxy_constructors.hpp include/chaiscript/dispatchkit/proxy_functions.hpp include/chaiscript/dispatchkit/proxy_functions_detail.hpp include/chaiscript/dispatchkit/register_function.hpp include/chaiscript/dispatchkit/type_info.hpp include/chaiscript/language/chaiscript_algebraic.hpp include/chaiscript/language/chaiscript_common.hpp include/chaiscript/language/chaiscript_engine.hpp include/chaiscript/language/chaiscript_eval.hpp include/chaiscript/language/chaiscript_parser.hpp include/chaiscript/language/chaiscript_prelude.chai include/chaiscript/language/chaiscript_prelude_docs.hpp include/chaiscript/utility/utility.hpp)
set_source_files_properties(${Chai_INCLUDES} PROPERTIES HEADER_FILE_ONLY TRUE) set_source_files_properties(${Chai_INCLUDES} PROPERTIES HEADER_FILE_ONLY TRUE)
@ -203,6 +230,8 @@ if(BUILD_SAMPLES)
target_link_libraries(example ${LIBS}) target_link_libraries(example ${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})
add_executable(inheritance samples/inheritance.cpp)
target_link_libraries(inheritance ${LIBS})
endif() endif()

View File

@ -4,9 +4,9 @@ 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
make -j2 CXX=g++-4.8 make -j2
popd popd
../cppcheck-1.65/cppcheck --enable=all -I include --inline-suppr --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
echo -n '{ "body": " ' > output.json echo -n '{ "body": " ' > output.json
echo -n `awk '{printf "%s\\\\n", $0;}' output` >> output.json echo -n `awk '{printf "%s\\\\n", $0;}' output` >> output.json

View File

@ -75,7 +75,7 @@
/// ///
/// @subsection compiling Compiling ChaiScript Applications /// @subsection compiling Compiling ChaiScript Applications
/// ///
/// ChaiScript is a header only library with only one dependecy: The /// ChaiScript is a header only library with only one dependency: The
/// operating system provided dynamic library loader, which has to be specified on some platforms. /// operating system provided dynamic library loader, which has to be specified on some platforms.
/// ///
/// @subsubsection compilinggcc Compiling with GCC /// @subsubsection compilinggcc Compiling with GCC
@ -311,7 +311,7 @@
/// 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 convered 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 counting).
/// Const may be added, but never removed. /// 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.

View File

@ -45,7 +45,7 @@
namespace chaiscript { namespace chaiscript {
static const int version_major = 5; static const int version_major = 5;
static const int version_minor = 4; static const int version_minor = 5;
static const int version_patch = 0; static const int version_patch = 0;
} }

View File

@ -28,7 +28,7 @@ namespace chaiscript {
virtual ~bad_any_cast() CHAISCRIPT_NOEXCEPT {} virtual ~bad_any_cast() CHAISCRIPT_NOEXCEPT {}
/// \brief Description of what error occured /// \brief Description of what error occurred
virtual const char * what() const CHAISCRIPT_NOEXCEPT CHAISCRIPT_OVERRIDE virtual const char * what() const CHAISCRIPT_NOEXCEPT CHAISCRIPT_OVERRIDE
{ {
return m_what.c_str(); return m_what.c_str();
@ -52,6 +52,7 @@ namespace chaiscript {
Data &operator=(const Data &) = delete; Data &operator=(const Data &) = delete;
virtual ~Data() {} virtual ~Data() {}
virtual void *data() = 0; virtual void *data() = 0;
const std::type_info &type() const const std::type_info &type() const
{ {
@ -65,7 +66,7 @@ namespace chaiscript {
template<typename T> template<typename T>
struct Data_Impl : Data struct Data_Impl : Data
{ {
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))
{ {
@ -104,12 +105,19 @@ namespace chaiscript {
} }
} }
template<typename ValueType> #if _MSC_VER != 1800
Any(const ValueType &t_value) Any(Any &&) = default;
: m_data(std::unique_ptr<Data>(new Data_Impl<ValueType>(t_value))) 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)
: m_data(std::unique_ptr<Data>(new Data_Impl<typename std::decay<ValueType>::type>(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);
@ -117,13 +125,6 @@ namespace chaiscript {
return *this; return *this;
} }
template<typename ValueType>
Any & operator=(const ValueType &t_value)
{
m_data = std::unique_ptr<Data>(new Data_Impl<ValueType>(t_value));
return *this;
}
template<typename ToType> template<typename ToType>
ToType &cast() const ToType &cast() const
{ {

View File

@ -10,6 +10,7 @@
#include <string> #include <string>
#include <typeinfo> #include <typeinfo>
#include "../chaiscript_defines.hpp"
#include "type_info.hpp" #include "type_info.hpp"
namespace chaiscript { namespace chaiscript {
@ -28,14 +29,14 @@ namespace chaiscript
class bad_boxed_cast : public std::bad_cast class bad_boxed_cast : public std::bad_cast
{ {
public: public:
bad_boxed_cast(const Type_Info &t_from, const std::type_info &t_to, bad_boxed_cast(Type_Info t_from, const std::type_info &t_to,
std::string t_what) CHAISCRIPT_NOEXCEPT std::string t_what) CHAISCRIPT_NOEXCEPT
: from(t_from), to(&t_to), m_what(std::move(t_what)) : from(std::move(t_from)), to(&t_to), m_what(std::move(t_what))
{ {
} }
bad_boxed_cast(const Type_Info &t_from, const std::type_info &t_to) CHAISCRIPT_NOEXCEPT bad_boxed_cast(Type_Info t_from, const std::type_info &t_to)
: from(t_from), to(&t_to), m_what("Cannot perform boxed_cast") : from(std::move(t_from)), to(&t_to), m_what("Cannot perform boxed_cast")
{ {
} }
@ -46,7 +47,7 @@ namespace chaiscript
virtual ~bad_boxed_cast() CHAISCRIPT_NOEXCEPT {} virtual ~bad_boxed_cast() CHAISCRIPT_NOEXCEPT {}
/// \brief Description of what error occured /// \brief Description of what error occurred
virtual const char * what() const CHAISCRIPT_NOEXCEPT CHAISCRIPT_OVERRIDE virtual const char * what() const CHAISCRIPT_NOEXCEPT CHAISCRIPT_OVERRIDE
{ {
return m_what.c_str(); return m_what.c_str();

View File

@ -14,79 +14,20 @@ namespace chaiscript
namespace detail namespace detail
{ {
template<int>
struct Placeholder struct Placeholder
{ {
static std::tuple<decltype(std::placeholders::_1),decltype(std::placeholders::_2),decltype(std::placeholders::_3),decltype(std::placeholders::_4),decltype(std::placeholders::_5),decltype(std::placeholders::_6),decltype(std::placeholders::_7),decltype(std::placeholders::_8),decltype(std::placeholders::_9),decltype(std::placeholders::_10)> placeholder() {
return std::tuple<decltype(std::placeholders::_1),decltype(std::placeholders::_2),decltype(std::placeholders::_3),decltype(std::placeholders::_4),decltype(std::placeholders::_5),decltype(std::placeholders::_6),decltype(std::placeholders::_7),decltype(std::placeholders::_8),decltype(std::placeholders::_9),decltype(std::placeholders::_10)>(std::placeholders::_1,std::placeholders::_2,std::placeholders::_3,std::placeholders::_4,std::placeholders::_5,std::placeholders::_6,std::placeholders::_7,std::placeholders::_8,std::placeholders::_9,std::placeholders::_10);
}
}; };
template<>
struct Placeholder<1>
{
static decltype(std::placeholders::_1) value() { return std::placeholders::_1; }
};
template<>
struct Placeholder<2>
{
static decltype(std::placeholders::_2) value() { return std::placeholders::_2; }
};
template<>
struct Placeholder<3>
{
static decltype(std::placeholders::_3) value() { return std::placeholders::_3; }
};
template<>
struct Placeholder<4>
{
static decltype(std::placeholders::_4) value() { return std::placeholders::_4; }
};
template<>
struct Placeholder<5>
{
static decltype(std::placeholders::_5) value() { return std::placeholders::_5; }
};
template<>
struct Placeholder<6>
{
static decltype(std::placeholders::_6) value() { return std::placeholders::_6; }
};
template<>
struct Placeholder<7>
{
static decltype(std::placeholders::_7) value() { return std::placeholders::_7; }
};
template<>
struct Placeholder<8>
{
static decltype(std::placeholders::_8) value() { return std::placeholders::_8; }
};
template<>
struct Placeholder<9>
{
static decltype(std::placeholders::_9) value() { return std::placeholders::_9; }
};
template<>
struct Placeholder<10>
{
static decltype(std::placeholders::_10) value() { return std::placeholders::_10; }
};
template<int count, int maxcount, typename Sig> template<int count, int maxcount, typename Sig>
struct Bind_First struct Bind_First
{ {
template<typename F, typename ... InnerParams> template<typename F, typename ... InnerParams>
static std::function<Sig> bind(F f, InnerParams ... innerparams) static std::function<Sig> bind(F&& f, InnerParams ... innerparams)
{ {
return Bind_First<count - 1, maxcount, Sig>::bind(f, innerparams..., Placeholder<maxcount - count + 1>::value()); return Bind_First<count - 1, maxcount, Sig>::bind(std::forward<F>(f), innerparams..., std::get<maxcount - count>(Placeholder::placeholder()));
} }
}; };
@ -94,37 +35,42 @@ namespace chaiscript
struct Bind_First<0, maxcount, Sig> struct Bind_First<0, maxcount, Sig>
{ {
template<typename F, typename ... InnerParams> template<typename F, typename ... InnerParams>
static std::function<Sig> bind(F f, InnerParams ... innerparams) static std::function<Sig> bind(F&& f, InnerParams ... innerparams)
{ {
return std::bind(f, innerparams...); return std::bind(std::forward<F>(f), innerparams...);
} }
}; };
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) std::function<Ret (Param...)> bind_first(Ret (*f)(P1, Param...), O&& o)
{ {
return Bind_First<sizeof...(Param), sizeof...(Param), Ret (Param...)>::bind(f, o); return Bind_First<sizeof...(Param), sizeof...(Param), Ret (Param...)>::bind(f, std::forward<O>(o));
} }
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) std::function<Ret (Param...)> bind_first(Ret (Class::*f)(Param...), O&& o)
{ {
return Bind_First<sizeof...(Param), sizeof...(Param), Ret (Param...)>::bind(f, o); return Bind_First<sizeof...(Param), sizeof...(Param), Ret (Param...)>::bind(f, std::forward<O>(o));
} }
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) std::function<Ret (Param...)> bind_first(Ret (Class::*f)(Param...) const, O&& o)
{ {
return Bind_First<sizeof...(Param), sizeof...(Param), Ret (Param...)>::bind(f, o); return Bind_First<sizeof...(Param), sizeof...(Param), Ret (Param...)>::bind(f, std::forward<O>(o));
} }
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) std::function<Ret (Param...)> bind_first(const std::function<Ret (P1, Param...)> &f, O&& o)
{ {
return Bind_First<sizeof...(Param), sizeof...(Param), Ret (Param...)>::bind(f, o); return Bind_First<sizeof...(Param), sizeof...(Param), Ret (Param...)>::bind(f, std::forward<O>(o));
} }
template<typename O, typename Ret, typename P1, typename ... Param>
std::function<Ret (Param...)> bind_first(std::function<Ret (P1, Param...)> &&f, O&& o)
{
return Bind_First<sizeof...(Param), sizeof...(Param), Ret (Param...)>::bind(std::move(f), std::forward<O>(o));
}
} }
} }

View File

@ -24,7 +24,7 @@
#include "boxed_number.hpp" #include "boxed_number.hpp"
#include "boxed_value.hpp" #include "boxed_value.hpp"
#include "dispatchkit.hpp" #include "dispatchkit.hpp"
#include "dynamic_cast_conversion.hpp" #include "type_conversions.hpp"
#include "dynamic_object.hpp" #include "dynamic_object.hpp"
#include "operators.hpp" #include "operators.hpp"
#include "proxy_constructors.hpp" #include "proxy_constructors.hpp"
@ -46,13 +46,9 @@ namespace chaiscript
/// \param[in] v Boxed_Number to copy into the new object /// \param[in] v Boxed_Number to copy into the new object
/// \returns The newly created object. /// \returns The newly created object.
template<typename P1> template<typename P1>
std::shared_ptr<P1> construct_pod(Boxed_Number v) std::shared_ptr<P1> construct_pod(const Boxed_Number &v)
{ {
std::shared_ptr<P1> p(new P1()); return std::make_shared<P1>(v.get_as<P1>());
Boxed_Value bv(p);
Boxed_Number nb(bv);
nb = v;
return p;
} }
} }
@ -113,9 +109,7 @@ namespace chaiscript
} }
/** /// to_string function for internal use. Uses ostream operator<<
* to_string function for internal use. Uses ostream operator<<
*/
template<typename Input> template<typename Input>
std::string to_string(Input i) std::string to_string(Input i)
{ {
@ -124,10 +118,8 @@ namespace chaiscript
return ss.str(); 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>
Input parse_string(const std::string &i) Input parse_string(const std::string &i)
{ {
@ -138,10 +130,8 @@ namespace chaiscript
} }
/** /// 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 = ModulePtr(new Module())) ModulePtr bootstrap_pod_type(const std::string &name, ModulePtr m = ModulePtr(new Module()))
{ {
@ -155,22 +145,18 @@ namespace chaiscript
} }
/** /// "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) std::shared_ptr<Type> 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<typename std::remove_const<Type>::type>
shared_ptr_unconst_clone(const std::shared_ptr<typename std::add_const<Type>::type> &p) shared_ptr_unconst_clone(const std::shared_ptr<typename std::add_const<Type>::type> &p)
@ -180,11 +166,9 @@ namespace chaiscript
/** /// 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)
{ {
@ -198,10 +182,8 @@ 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:
@ -229,9 +211,7 @@ namespace chaiscript
} }
/** /// Add all arithmetic operators for PODs
* Add all arithmetic operators for PODs
*/
static void opers_arithmetic_pod(ModulePtr m = ModulePtr(new Module())) static void opers_arithmetic_pod(ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun(&Boxed_Number::equals), "=="); m->add(fun(&Boxed_Number::equals), "==");
@ -271,11 +251,8 @@ namespace chaiscript
} }
/** /// 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 std::vector<Boxed_Value> &params)
{ {
if (params.size() < 2) if (params.size() < 2)
@ -285,7 +262,7 @@ namespace chaiscript
Const_Proxy_Function f = boxed_cast<Const_Proxy_Function>(params[0]); Const_Proxy_Function f = boxed_cast<Const_Proxy_Function>(params[0]);
return Boxed_Value(Const_Proxy_Function(new dispatch::Bound_Function(f, return Boxed_Value(Const_Proxy_Function(std::make_shared<dispatch::Bound_Function>(f,
std::vector<Boxed_Value>(params.begin() + 1, params.end())))); std::vector<Boxed_Value>(params.begin() + 1, params.end()))));
} }
@ -330,9 +307,7 @@ namespace chaiscript
return e.what(); return e.what();
} }
/** /// Boolean specialization of internal to_string function
* Boolean specialization of internal to_string function
*/
static std::string bool_to_string(bool b) static std::string bool_to_string(bool b)
{ {
if (b) if (b)
@ -362,9 +337,7 @@ namespace chaiscript
static bool has_parse_tree(const chaiscript::Const_Proxy_Function &t_pf) static bool has_parse_tree(const chaiscript::Const_Proxy_Function &t_pf)
{ {
std::shared_ptr<const chaiscript::dispatch::Dynamic_Proxy_Function> pf if (auto pf = std::dynamic_pointer_cast<const chaiscript::dispatch::Dynamic_Proxy_Function>(t_pf))
= std::dynamic_pointer_cast<const chaiscript::dispatch::Dynamic_Proxy_Function>(t_pf);
if (pf)
{ {
if (pf->get_parse_tree()) if (pf->get_parse_tree())
{ {
@ -379,9 +352,7 @@ namespace chaiscript
static chaiscript::AST_NodePtr get_parse_tree(const chaiscript::Const_Proxy_Function &t_pf) static chaiscript::AST_NodePtr get_parse_tree(const chaiscript::Const_Proxy_Function &t_pf)
{ {
std::shared_ptr<const chaiscript::dispatch::Dynamic_Proxy_Function> pf if (auto pf = std::dynamic_pointer_cast<const chaiscript::dispatch::Dynamic_Proxy_Function>(t_pf))
= std::dynamic_pointer_cast<const chaiscript::dispatch::Dynamic_Proxy_Function>(t_pf);
if (pf)
{ {
if (pf->get_parse_tree()) if (pf->get_parse_tree())
{ {
@ -504,8 +475,7 @@ namespace chaiscript
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(Proxy_Function(new dispatch::Dynamic_Proxy_Function(std::bind(&bind_function, std::placeholders::_1))), m->add(Proxy_Function(new dispatch::Dynamic_Proxy_Function(&bind_function)), "bind");
"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>), "=");
@ -526,11 +496,11 @@ namespace chaiscript
"eval_error", "eval_error",
{ }, { },
{ {fun(&chaiscript::exception::eval_error::reason), "reason"}, { {fun(&chaiscript::exception::eval_error::reason), "reason"},
{fun(std::function<std::vector<Boxed_Value> (const chaiscript::exception::eval_error &t_eval_error)>([](const chaiscript::exception::eval_error &t_eval_error) { {fun(std::function<std::vector<Boxed_Value> (const chaiscript::exception::eval_error &t_eval_error)>([](const chaiscript::exception::eval_error &t_eval_error) -> std::vector<Boxed_Value> {
std::vector<Boxed_Value> retval; std::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<std::shared_ptr<chaiscript::AST_Node>>); &chaiscript::var<std::shared_ptr<const chaiscript::AST_Node>>);
return retval; return retval;
})), "call_stack"} } })), "call_stack"} }
); );
@ -554,7 +524,7 @@ namespace chaiscript
{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) { {fun(std::function<std::vector<Boxed_Value> (const chaiscript::AST_Node &t_node)>([](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(), std::transform(t_node.children.begin(), t_node.children.end(),
std::back_inserter(retval), std::back_inserter(retval),

View File

@ -278,9 +278,9 @@ namespace chaiscript
template<typename ContainerType> template<typename ContainerType>
ModulePtr container_type(const std::string &/*type*/, ModulePtr m = ModulePtr(new Module())) ModulePtr container_type(const std::string &/*type*/, ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun( std::function<size_t (const ContainerType *)>( [](const ContainerType *a) { return a->size(); } ) ), "size"); m->add(fun<size_t (const ContainerType *)>([](const ContainerType *a) { return a->size(); } ), "size");
m->add(fun( std::function<bool (const ContainerType *)>( [](const ContainerType *a) { return a->empty(); } ) ), "empty"); m->add(fun<bool (const ContainerType *)>([](const ContainerType *a) { return a->empty(); } ), "empty");
m->add(fun( std::function<void (ContainerType *)>( [](ContainerType *a) { a->clear(); } ) ), "clear"); m->add(fun<void (ContainerType *)>([](ContainerType *a) { a->clear(); } ), "clear");
return m; return m;
} }
@ -493,24 +493,26 @@ namespace chaiscript
if (typeid(VectorType) == typeid(std::vector<Boxed_Value>)) if (typeid(VectorType) == typeid(std::vector<Boxed_Value>))
{ {
m->eval("def Vector::`==`(rhs) : type_match(rhs, this) { \ m->eval(R"(
if ( rhs.size() != this.size() ) { \ def Vector::`==`(rhs) : type_match(rhs, this) {
return false; \ if ( rhs.size() != this.size() ) {
} else { \ return false;
auto r1 = range(this); \ } else {
auto r2 = range(rhs); \ auto r1 = range(this);
while (!r1.empty()) \ auto r2 = range(rhs);
{ \ while (!r1.empty())
if (!eq(r1.front(), r2.front())) \ {
{ \ if (!eq(r1.front(), r2.front()))
return false; \ {
} \ return false;
r1.pop_front(); \ }
r2.pop_front(); \ r1.pop_front();
} \ r2.pop_front();
return true; \ }
} \ true;
}"); }
} )"
);
} }
return m; return m;

View File

@ -14,11 +14,11 @@
#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 "dynamic_cast_conversion.hpp" #include "type_conversions.hpp"
#include "type_info.hpp" #include "type_info.hpp"
namespace chaiscript { namespace chaiscript {
class Dynamic_Cast_Conversions; class Type_Conversions;
namespace detail { namespace detail {
namespace exception { namespace exception {
class bad_any_cast; class bad_any_cast;
@ -72,7 +72,7 @@ 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 Dynamic_Cast_Conversions *t_conversions = nullptr) typename detail::Cast_Helper<Type>::Result_Type boxed_cast(const Boxed_Value &bv, const Type_Conversions *t_conversions = nullptr)
{ {
try { try {
return detail::Cast_Helper<Type>::cast(bv, t_conversions); return detail::Cast_Helper<Type>::cast(bv, t_conversions);
@ -86,18 +86,18 @@ namespace chaiscript
#pragma warning(disable : 4127) #pragma warning(disable : 4127)
#endif #endif
if (std::is_polymorphic<typename detail::Stripped_Type<Type>::type>::value && t_conversions) if (t_conversions && t_conversions->convertable_type<Type>())
{ {
try { try {
// std::cout << "trying an up conversion " << typeid(Type).name() << std::endl; // std::cout << "trying an up conversion " << typeid(Type).name() << std::endl;
// We will not catch any bad_boxed_dynamic_cast that is thrown, let the user get it // 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_dynamic_cast<Type>(bv), t_conversions); return detail::Cast_Helper<Type>::cast(t_conversions->boxed_type_conversion<Type>(bv), t_conversions);
} catch (...) { } catch (...) {
try { try {
// std::cout << "trying a down conversion " << typeid(Type).name() << std::endl; // std::cout << "trying a down conversion " << typeid(Type).name() << std::endl;
// try going the other way - down the inheritance graph // try going the other way - down the inheritance graph
return detail::Cast_Helper<Type>::cast(t_conversions->boxed_dynamic_down_cast<Type>(bv), t_conversions); return detail::Cast_Helper<Type>::cast(t_conversions->boxed_type_down_conversion<Type>(bv), 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));
} }

View File

@ -17,37 +17,32 @@
namespace chaiscript namespace chaiscript
{ {
class Dynamic_Cast_Conversions; class Type_Conversions;
namespace detail namespace detail
{ {
// Cast_Helper_Inner helper classes // Cast_Helper_Inner helper classes
/** template<typename T>
* Generic Cast_Helper_Inner, for casting to any type T* throw_if_null(T *t)
*/ {
if (t) return t;
throw std::runtime_error("Attempted to dereference null Boxed_Value");
}
/// Generic Cast_Helper_Inner, for casting to any type
template<typename Result> template<typename Result>
struct Cast_Helper_Inner struct Cast_Helper_Inner
{ {
typedef typename std::reference_wrapper<typename std::add_const<Result>::type > Result_Type; typedef typename std::reference_wrapper<typename std::add_const<Result>::type > Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *) static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *)
{ {
if (ob.is_ref()) if (ob.get_type_info().bare_equal_type_info(typeid(Result)))
{ {
if (!ob.get_type_info().is_const()) return *(static_cast<const Result *>(throw_if_null(ob.get_const_ptr())));
{
return std::cref((ob.get().cast<std::reference_wrapper<Result> >()).get());
} else { } else {
return ob.get().cast<std::reference_wrapper<const Result> >(); throw chaiscript::detail::exception::bad_any_cast();
}
} else {
if (!ob.get_type_info().is_const())
{
return std::cref(*(ob.get().cast<std::shared_ptr<Result> >()));
} else {
return std::cref(*(ob.get().cast<std::shared_ptr<const Result> >()));
}
} }
} }
}; };
@ -57,23 +52,18 @@ namespace chaiscript
{ {
}; };
/** /// 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 &> : Cast_Helper_Inner<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 *>
{ {
typedef const Result * Result_Type; typedef const Result * Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *)
static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *)
{ {
if (ob.is_ref()) if (ob.is_ref())
{ {
@ -94,15 +84,12 @@ namespace chaiscript
} }
}; };
/** /// 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 *>
{ {
typedef Result * Result_Type; typedef Result * Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *)
static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *)
{ {
if (ob.is_ref()) if (ob.is_ref())
{ {
@ -113,49 +100,43 @@ namespace chaiscript
} }
}; };
/**
* 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 &>
{ {
typedef Result& Result_Type; typedef Result& Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *) static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *)
{ {
if (ob.is_ref()) if (!ob.get_type_info().is_const() && ob.get_type_info().bare_equal_type_info(typeid(Result)))
{ {
return ob.get().cast<std::reference_wrapper<Result> >(); return *(static_cast<Result *>(throw_if_null(ob.get_ptr())));
} else { } else {
Result &r = *(ob.get().cast<std::shared_ptr<Result> >()); throw chaiscript::detail::exception::bad_any_cast();
return r;
} }
} }
}; };
/** /// 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<typename std::shared_ptr<Result> > struct Cast_Helper_Inner<typename std::shared_ptr<Result> >
{ {
typedef typename std::shared_ptr<Result> Result_Type; typedef typename std::shared_ptr<Result> Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *) static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *)
{ {
return ob.get().cast<std::shared_ptr<Result> >(); 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<typename std::shared_ptr<const Result> > struct Cast_Helper_Inner<typename std::shared_ptr<const Result> >
{ {
typedef typename std::shared_ptr<const Result> Result_Type; typedef typename std::shared_ptr<const Result> Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *) static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *)
{ {
if (!ob.get_type_info().is_const()) if (!ob.get_type_info().is_const())
{ {
@ -166,9 +147,7 @@ namespace chaiscript
} }
}; };
/** /// 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> >
{ {
@ -180,9 +159,7 @@ namespace chaiscript
}; };
/** /// 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> >
{ {
@ -195,38 +172,32 @@ namespace chaiscript
/** /// 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>
{ {
typedef const Boxed_Value & Result_Type; typedef const Boxed_Value & Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *) static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *)
{ {
return ob; 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 &>
{ {
typedef Boxed_Value& Result_Type; typedef Boxed_Value& Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *) static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *)
{ {
return const_cast<Boxed_Value &>(ob); return 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>
{ {
@ -238,9 +209,7 @@ namespace chaiscript
}; };
/** /// 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 &>
{ {
@ -271,15 +240,13 @@ namespace chaiscript
{ {
}; };
/** /// 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
{ {
typedef typename Cast_Helper_Inner<T>::Result_Type Result_Type; typedef typename Cast_Helper_Inner<T>::Result_Type Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *t_conversions) static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *t_conversions)
{ {
return Cast_Helper_Inner<T>::cast(ob, t_conversions); return Cast_Helper_Inner<T>::cast(ob, t_conversions);
} }

View File

@ -19,7 +19,7 @@
#include "type_info.hpp" #include "type_info.hpp"
namespace chaiscript { namespace chaiscript {
class Dynamic_Cast_Conversions; class Type_Conversions;
} // namespace chaiscript } // namespace chaiscript
namespace chaiscript namespace chaiscript
@ -233,7 +233,7 @@ namespace chaiscript
template<typename LHS, bool Float> template<typename LHS, bool Float>
static Boxed_Value oper_rhs(Operators::Opers t_oper, const Boxed_Value &t_lhs, const Boxed_Value &t_rhs) static Boxed_Value oper_rhs(Operators::Opers t_oper, const Boxed_Value &t_lhs, const Boxed_Value &t_rhs)
{ {
const Type_Info &inp_ = t_rhs.get_type_info(); const auto &inp_ = t_rhs.get_type_info();
if (inp_ == typeid(int)) { if (inp_ == typeid(int)) {
return Go<LHS, int, Float>::go(t_oper, t_lhs, t_rhs); return Go<LHS, int, Float>::go(t_oper, t_lhs, t_rhs);
@ -334,10 +334,10 @@ namespace chaiscript
{ {
} }
Boxed_Number(const Boxed_Value &v) Boxed_Number(Boxed_Value v)
: bv(v) : bv(std::move(v))
{ {
validate_boxed_number(v); validate_boxed_number(bv);
} }
template<typename T> explicit Boxed_Number(T t) template<typename T> explicit Boxed_Number(T t)
@ -826,31 +826,25 @@ namespace chaiscript
namespace detail namespace detail
{ {
/** /// Cast_Helper for converting from Boxed_Value to Boxed_Number
* Cast_Helper for converting from Boxed_Value to Boxed_Number
*/
template<> template<>
struct Cast_Helper<Boxed_Number> struct Cast_Helper<Boxed_Number>
{ {
typedef Boxed_Number Result_Type; typedef Boxed_Number Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *) static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *)
{ {
return Boxed_Number(ob); return Boxed_Number(ob);
} }
}; };
/** /// Cast_Helper for converting from Boxed_Value to Boxed_Number
* Cast_Helper for converting from Boxed_Value to Boxed_Number
*/
template<> template<>
struct Cast_Helper<const Boxed_Number &> : Cast_Helper<Boxed_Number> struct Cast_Helper<const Boxed_Number &> : Cast_Helper<Boxed_Number>
{ {
}; };
/** /// Cast_Helper for converting from Boxed_Value to Boxed_Number
* Cast_Helper for converting from Boxed_Value to Boxed_Number
*/
template<> template<>
struct Cast_Helper<const Boxed_Number> : Cast_Helper<Boxed_Number> struct Cast_Helper<const Boxed_Number> : Cast_Helper<Boxed_Number>
{ {

View File

@ -13,6 +13,7 @@
#include <type_traits> #include <type_traits>
#include "../chaiscript_threading.hpp" #include "../chaiscript_threading.hpp"
#include "../chaiscript_defines.hpp"
#include "any.hpp" #include "any.hpp"
#include "type_info.hpp" #include "type_info.hpp"
@ -35,10 +36,10 @@ namespace chaiscript
struct Data struct Data
{ {
Data(const Type_Info &ti, Data(const Type_Info &ti,
const chaiscript::detail::Any &to, chaiscript::detail::Any to,
bool tr, bool tr,
const void *t_void_ptr) const void *t_void_ptr)
: m_type_info(ti), m_obj(to), m_data_ptr(ti.is_const()?nullptr:const_cast<void *>(t_void_ptr)), m_const_data_ptr(t_void_ptr), : m_type_info(ti), m_obj(std::move(to)), m_data_ptr(ti.is_const()?nullptr:const_cast<void *>(t_void_ptr)), m_const_data_ptr(t_void_ptr),
m_is_ref(tr) m_is_ref(tr)
{ {
} }
@ -61,9 +62,11 @@ namespace chaiscript
Data(const Data &) = delete; Data(const Data &) = delete;
~Data() #if !defined(__APPLE__) && (!defined(_MSC_VER) || _MSC_VER != 1800)
{ Data(Data &&) = 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;
@ -102,32 +105,53 @@ namespace chaiscript
); );
} }
template<typename T>
static std::shared_ptr<Data> get(std::shared_ptr<T> &&obj)
{
auto ptr = obj.get();
return std::make_shared<Data>(
detail::Get_Type_Info<T>::get(),
chaiscript::detail::Any(std::move(obj)),
false,
ptr
);
}
template<typename T> template<typename T>
static std::shared_ptr<Data> get(T *t) static std::shared_ptr<Data> get(T *t)
{ {
return get(std::ref(*t)); return get(std::ref(*t));
} }
template<typename T>
static std::shared_ptr<Data> get(const T *t)
{
return get(std::cref(*t));
}
template<typename T> template<typename T>
static std::shared_ptr<Data> get(std::reference_wrapper<T> obj) static std::shared_ptr<Data> get(std::reference_wrapper<T> obj)
{ {
auto p = &obj.get();
return std::make_shared<Data>( return std::make_shared<Data>(
detail::Get_Type_Info<T>::get(), detail::Get_Type_Info<T>::get(),
chaiscript::detail::Any(obj), chaiscript::detail::Any(std::move(obj)),
true, true,
&obj.get() p
); );
} }
template<typename T> template<typename T>
static std::shared_ptr<Data> get(const T& t) static std::shared_ptr<Data> get(T t)
{ {
auto p = std::make_shared<T>(t); auto p = std::make_shared<T>(std::move(t));
auto ptr = p.get();
return std::make_shared<Data>( return std::make_shared<Data>(
detail::Get_Type_Info<T>::get(), detail::Get_Type_Info<T>::get(),
chaiscript::detail::Any(p), chaiscript::detail::Any(std::move(p)),
false, false,
p.get() ptr
); );
} }
@ -145,15 +169,10 @@ namespace chaiscript
public: public:
/// Basic Boxed_Value constructor /// Basic Boxed_Value constructor
template<typename T> template<typename T,
explicit Boxed_Value(T t) typename = typename std::enable_if<!std::is_same<Boxed_Value, typename std::decay<T>::type>::value>::type>
: m_data(Object_Data::get(t)) explicit Boxed_Value(T &&t)
{ : m_data(Object_Data::get(std::forward<T>(t)))
}
/// Copy constructor - each copy shares the same data pointer
Boxed_Value(const Boxed_Value &t_so)
: m_data(t_so.m_data)
{ {
} }
@ -163,9 +182,13 @@ namespace chaiscript
{ {
} }
~Boxed_Value() #if !defined(_MSC_VER) || _MSC_VER != 1800
{ Boxed_Value(Boxed_Value&&) = default;
} Boxed_Value& operator=(Boxed_Value&&) = default;
#endif
Boxed_Value(const Boxed_Value&) = default;
Boxed_Value& operator=(const Boxed_Value&) = default;
void swap(Boxed_Value &rhs) void swap(Boxed_Value &rhs)
{ {
@ -180,61 +203,53 @@ namespace chaiscript
return *this; return *this;
} }
/// shared data assignment, same as copy construction const Type_Info &get_type_info() const CHAISCRIPT_NOEXCEPT
Boxed_Value &operator=(const Boxed_Value &rhs)
{
Boxed_Value temp(rhs);
swap(temp);
return *this;
}
const Type_Info &get_type_info() const
{ {
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 bool is_undef() const CHAISCRIPT_NOEXCEPT
{ {
return m_data->m_type_info.is_undef(); return m_data->m_type_info.is_undef();
} }
bool is_const() const bool is_const() const CHAISCRIPT_NOEXCEPT
{ {
return m_data->m_type_info.is_const(); return m_data->m_type_info.is_const();
} }
bool is_type(const Type_Info &ti) const bool is_type(const Type_Info &ti) const CHAISCRIPT_NOEXCEPT
{ {
return m_data->m_type_info.bare_equal(ti); return m_data->m_type_info.bare_equal(ti);
} }
bool is_null() const bool is_null() const CHAISCRIPT_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 const chaiscript::detail::Any & get() const CHAISCRIPT_NOEXCEPT
{ {
return m_data->m_obj; return m_data->m_obj;
} }
bool is_ref() const bool is_ref() const CHAISCRIPT_NOEXCEPT
{ {
return m_data->m_is_ref; return m_data->m_is_ref;
} }
bool is_pointer() const bool is_pointer() const CHAISCRIPT_NOEXCEPT
{ {
return !is_ref(); return !is_ref();
} }
void *get_ptr() const void *get_ptr() const CHAISCRIPT_NOEXCEPT
{ {
return m_data->m_data_ptr; return m_data->m_data_ptr;
} }
const void *get_const_ptr() const const void *get_const_ptr() const CHAISCRIPT_NOEXCEPT
{ {
return m_data->m_const_data_ptr; return m_data->m_const_data_ptr;
} }
@ -260,7 +275,7 @@ namespace chaiscript
/// \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(Boxed_Value l, Boxed_Value r) static bool type_match(const Boxed_Value &l, const Boxed_Value &r) CHAISCRIPT_NOEXCEPT
{ {
return l.get_type_info() == r.get_type_info(); return l.get_type_info() == r.get_type_info();
} }
@ -297,7 +312,7 @@ namespace chaiscript
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::shared_ptr<typename std::add_const<T>::type >(new T(t))); return Boxed_Value(std::make_shared<typename std::add_const<T>::type >(t));
} }
/// \brief Takes a pointer to a value, adds const to the pointed to type and returns an immutable Boxed_Value. /// \brief Takes a pointer to a value, adds const to the pointed to type and returns an immutable Boxed_Value.

View File

@ -27,7 +27,7 @@
#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_cast_conversion.hpp" #include "type_conversions.hpp"
#include "dynamic_object.hpp" #include "dynamic_object.hpp"
#include "proxy_constructors.hpp" #include "proxy_constructors.hpp"
#include "proxy_functions.hpp" #include "proxy_functions.hpp"
@ -53,9 +53,7 @@ namespace chaiscript
{ {
namespace exception namespace exception
{ {
/** /// Exception thrown in the case that an object name is invalid because it is a reserved word
* Exception thrown in the case that an object name is invalid because it is a reserved word
*/
class reserved_word_error : public std::runtime_error class reserved_word_error : public std::runtime_error
{ {
public: public:
@ -75,18 +73,16 @@ namespace chaiscript
std::string m_word; std::string m_word;
}; };
/** /// Exception thrown in the case that an object name is invalid because it contains illegal characters
* Exception thrown in the case that an object name is invalid because it contains illegal characters
*/
class illegal_name_error : public std::runtime_error class illegal_name_error : public std::runtime_error
{ {
public: public:
illegal_name_error(const std::string &t_name) throw() illegal_name_error(const std::string &t_name) CHAISCRIPT_NOEXCEPT
: std::runtime_error("Reserved name not allowed in object name: " + t_name), m_name(t_name) : std::runtime_error("Reserved name not allowed in object name: " + t_name), m_name(t_name)
{ {
} }
virtual ~illegal_name_error() throw() {} virtual ~illegal_name_error() CHAISCRIPT_NOEXCEPT {}
std::string name() const std::string name() const
{ {
@ -98,18 +94,16 @@ namespace chaiscript
}; };
/** /// Exception thrown in the case that an object name is invalid because it already exists in current context
* Exception thrown in the case that an object name is invalid because it already exists in current context
*/
class name_conflict_error : public std::runtime_error class name_conflict_error : public std::runtime_error
{ {
public: public:
name_conflict_error(const std::string &t_name) throw() name_conflict_error(const std::string &t_name) CHAISCRIPT_NOEXCEPT
: std::runtime_error("Name already exists in current context " + t_name), m_name(t_name) : std::runtime_error("Name already exists in current context " + t_name), m_name(t_name)
{ {
} }
virtual ~name_conflict_error() throw() {} virtual ~name_conflict_error() CHAISCRIPT_NOEXCEPT {}
std::string name() const std::string name() const
{ {
@ -122,9 +116,7 @@ namespace chaiscript
}; };
/** /// Exception thrown in the case that a non-const object was added as a shared object
* Exception thrown in the case that a non-const object was added as a shared object
*/
class global_non_const : public std::runtime_error class global_non_const : public std::runtime_error
{ {
public: public:
@ -143,37 +135,37 @@ namespace chaiscript
class Module class Module
{ {
public: public:
Module &add(const Type_Info &ti, const std::string &name) Module &add(Type_Info ti, std::string name)
{ {
m_typeinfos.push_back(std::make_pair(ti, name)); m_typeinfos.emplace_back(std::move(ti), std::move(name));
return *this; return *this;
} }
Module &add(const Dynamic_Cast_Conversion &d) Module &add(Type_Conversion d)
{ {
m_conversions.push_back(d); m_conversions.push_back(std::move(d));
return *this; return *this;
} }
Module &add(const Proxy_Function &f, const std::string &name) Module &add(Proxy_Function f, std::string name)
{ {
m_funcs.push_back(std::make_pair(f, name)); m_funcs.emplace_back(std::move(f), std::move(name));
return *this; return *this;
} }
Module &add_global_const(const Boxed_Value &t_bv, const std::string &t_name) Module &add_global_const(Boxed_Value t_bv, std::string t_name)
{ {
if (!t_bv.is_const()) if (!t_bv.is_const())
{ {
throw chaiscript::exception::global_non_const(); throw chaiscript::exception::global_non_const();
} }
m_globals.push_back(std::make_pair(t_bv, t_name)); m_globals.emplace_back(std::move(t_bv), std::move(t_name));
return *this; return *this;
} }
//Add a bit of chaiscript to eval during module implementation //Add a bit of ChaiScript to eval during module implementation
Module &eval(const std::string &str) Module &eval(const std::string &str)
{ {
m_evals.push_back(str); m_evals.push_back(str);
@ -205,21 +197,21 @@ namespace chaiscript
std::vector<std::pair<Proxy_Function, std::string> > m_funcs; std::vector<std::pair<Proxy_Function, std::string> > m_funcs;
std::vector<std::pair<Boxed_Value, std::string> > m_globals; std::vector<std::pair<Boxed_Value, std::string> > m_globals;
std::vector<std::string> m_evals; std::vector<std::string> m_evals;
std::vector<Dynamic_Cast_Conversion> m_conversions; std::vector<Type_Conversion> m_conversions;
template<typename T, typename InItr> template<typename T, typename InItr>
static void apply(InItr begin, InItr end, T &t) static void apply(InItr begin, const InItr end, T &t)
{ {
while (begin != end) for_each(begin, end, [&t](typename std::iterator_traits<InItr>::reference obj)
{ {
try { try {
t.add(begin->first, begin->second); t.add(obj.first, obj.second);
} catch (const chaiscript::exception::name_conflict_error &) { } catch (const chaiscript::exception::name_conflict_error &) {
/// \todo Should we throw an error if there's a name conflict /// \todo Should we throw an error if there's a name conflict
/// while applying a module? /// while applying a module?
} }
++begin;
} }
);
} }
template<typename T, typename InItr> template<typename T, typename InItr>
@ -258,24 +250,22 @@ namespace chaiscript
namespace detail namespace detail
{ {
/** /// A Proxy_Function implementation that is able to take
* A Proxy_Function implementation that is able to take /// a vector of Proxy_Functions and perform a dispatch on them. It is
* a vector of Proxy_Functions and perform a dispatch on them. It is /// used specifically in the case of dealing with Function object variables
* used specifically in the case of dealing with Function object variables
*/
class Dispatch_Function : public dispatch::Proxy_Function_Base class Dispatch_Function : public dispatch::Proxy_Function_Base
{ {
public: public:
Dispatch_Function(const std::vector<Proxy_Function> &t_funcs) Dispatch_Function(std::vector<Proxy_Function> t_funcs)
: Proxy_Function_Base(build_type_infos(t_funcs)), : Proxy_Function_Base(build_type_infos(t_funcs), calculate_arity(t_funcs)),
m_funcs(t_funcs) m_funcs(std::move(t_funcs))
{ {
} }
virtual bool operator==(const dispatch::Proxy_Function_Base &rhs) const CHAISCRIPT_OVERRIDE virtual bool operator==(const dispatch::Proxy_Function_Base &rhs) const CHAISCRIPT_OVERRIDE
{ {
try { try {
const Dispatch_Function &dispatchfun = dynamic_cast<const Dispatch_Function &>(rhs); const auto &dispatchfun = dynamic_cast<const Dispatch_Function &>(rhs);
return m_funcs == dispatchfun.m_funcs; return m_funcs == dispatchfun.m_funcs;
} catch (const std::bad_cast &) { } catch (const std::bad_cast &) {
return false; return false;
@ -290,52 +280,30 @@ namespace chaiscript
} }
virtual int get_arity() const CHAISCRIPT_OVERRIDE static int calculate_arity(const std::vector<Proxy_Function> &t_funcs)
{ {
typedef std::vector<Proxy_Function> function_vec; if (t_funcs.empty()) {
return -1;
}
auto begin = m_funcs.begin(); const auto arity = t_funcs.front()->get_arity();
const function_vec::const_iterator end = m_funcs.end();
if (begin != end) for (const auto &func : t_funcs)
{ {
int arity = (*begin)->get_arity(); if (arity != func->get_arity())
++begin;
while (begin != end)
{
if (arity != (*begin)->get_arity())
{ {
// The arities in the list do not match, so it's unspecified // The arities in the list do not match, so it's unspecified
return -1; return -1;
} }
++begin;
} }
return arity; return arity;
} }
return -1; // unknown arity virtual bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
}
virtual bool call_match(const std::vector<Boxed_Value> &vals, const Dynamic_Cast_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
{ {
auto begin = m_funcs.begin(); return std::any_of(m_funcs.cbegin(), m_funcs.cend(),
auto end = m_funcs.end(); [&vals, &t_conversions](const Proxy_Function &f){ return f->call_match(vals, t_conversions); });
while (begin != end)
{
if ((*begin)->call_match(vals, t_conversions))
{
return true;
} else {
++begin;
}
}
return false;
} }
virtual std::string annotation() const CHAISCRIPT_OVERRIDE virtual std::string annotation() const CHAISCRIPT_OVERRIDE
@ -344,9 +312,9 @@ namespace chaiscript
} }
protected: protected:
virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
{ {
return dispatch::dispatch(m_funcs.begin(), m_funcs.end(), params, t_conversions); return dispatch::dispatch(m_funcs, params, t_conversions);
} }
private: private:
@ -354,10 +322,8 @@ namespace chaiscript
static std::vector<Type_Info> build_type_infos(const std::vector<Proxy_Function> &t_funcs) static std::vector<Type_Info> build_type_infos(const std::vector<Proxy_Function> &t_funcs)
{ {
typedef std::vector<Proxy_Function> function_vec; auto begin = t_funcs.cbegin();
const auto &end = t_funcs.cend();
auto begin = t_funcs.begin();
const function_vec::const_iterator end = t_funcs.end();
if (begin != end) if (begin != end)
{ {
@ -405,17 +371,14 @@ namespace chaiscript
namespace detail namespace detail
{ {
/** /// Main class for the dispatchkit. Handles management
* Main class for the dispatchkit. Handles management /// of the object stack, functions and registered types.
* of the object stack, functions and registered types.
*/
class Dispatch_Engine class Dispatch_Engine
{ {
public: public:
typedef std::map<std::string, chaiscript::Type_Info> Type_Name_Map; typedef std::map<std::string, chaiscript::Type_Info> Type_Name_Map;
typedef std::map<std::string, Boxed_Value> Scope; typedef std::map<std::string, Boxed_Value> Scope;
typedef std::deque<Scope> StackData; typedef std::vector<Scope> StackData;
typedef std::shared_ptr<StackData> Stack;
struct State struct State
{ {
@ -430,8 +393,7 @@ namespace chaiscript
Dispatch_Engine() Dispatch_Engine()
: m_stack_holder(this), : m_stack_holder(this),
m_place_holder(std::shared_ptr<dispatch::Placeholder_Object>(new dispatch::Placeholder_Object())) m_place_holder(std::make_shared<dispatch::Placeholder_Object>())
{ {
} }
@ -446,67 +408,56 @@ namespace chaiscript
return chaiscript::boxed_cast<Type>(bv, &m_conversions); return chaiscript::boxed_cast<Type>(bv, &m_conversions);
} }
/** /// Add a new conversion for upcasting to a base class
* Add a new conversion for upcasting to a base class void add(const Type_Conversion &d)
*/
void add(const Dynamic_Cast_Conversion &d)
{ {
m_conversions.add_conversion(d); m_conversions.add_conversion(d);
} }
/** /// Add a new named Proxy_Function to the system
* Add a new named Proxy_Function to the system
*/
void add(const Proxy_Function &f, const std::string &name) void add(const Proxy_Function &f, const std::string &name)
{ {
validate_object_name(name); validate_object_name(name);
add_function(f, name); add_function(f, name);
} }
/** /// Set the value of an object, by name. If the object
* Set the value of an object, by name. If the object /// is not available in the current scope it is created
* is not available in the current scope it is created
*/
void add(const Boxed_Value &obj, const std::string &name) void add(const Boxed_Value &obj, const std::string &name)
{ {
validate_object_name(name); validate_object_name(name);
StackData &stack = get_stack_data(); auto &stack = get_stack_data();
for (int i = static_cast<int>(stack.size())-1; i >= 0; --i) for (auto stack_elem = stack.rbegin(); stack_elem != stack.rend(); ++stack_elem)
{ {
std::map<std::string, Boxed_Value>::const_iterator itr = stack[i].find(name); auto itr = stack_elem->find(name);
if (itr != stack[i].end()) if (itr != stack_elem->end())
{ {
stack[i][name] = obj; itr->second = std::move(obj);
return; return;
} }
} }
add_object(name, obj); add_object(name, std::move(obj));
} }
/** /// Adds a named object to the current scope
* Adds a named object to the current scope
*/
void add_object(const std::string &name, const Boxed_Value &obj) const void add_object(const std::string &name, const Boxed_Value &obj) const
{ {
StackData &stack = get_stack_data(); auto &stack = get_stack_data();
validate_object_name(name); validate_object_name(name);
Scope &scope = stack.back(); auto &scope = stack.back();
auto itr = scope.find(name); if (scope.find(name) != scope.end())
if (itr != stack.back().end())
{ {
throw chaiscript::exception::name_conflict_error(name); throw chaiscript::exception::name_conflict_error(name);
} else { } else {
stack.back().insert(std::make_pair(name, obj)); scope.insert(std::make_pair(name, obj));
} }
} }
/** /// Adds a new global shared object, between all the threads
* Adds a new global shared object, between all the threads
*/
void add_global_const(const Boxed_Value &obj, const std::string &name) void add_global_const(const Boxed_Value &obj, const std::string &name)
{ {
validate_object_name(name); validate_object_name(name);
@ -526,9 +477,7 @@ namespace chaiscript
} }
/** /// Adds a new global (non-const) shared object, between all the threads
* Adds a new global (non-const) shared object, between all the threads
*/
void add_global(const Boxed_Value &obj, const std::string &name) void add_global(const Boxed_Value &obj, const std::string &name)
{ {
validate_object_name(name); validate_object_name(name);
@ -544,18 +493,13 @@ namespace chaiscript
} }
/** /// Adds a new scope to the stack
* Adds a new scope to the stack
*/
void new_scope() void new_scope()
{ {
StackData &stack = get_stack_data(); get_stack_data().emplace_back();
stack.push_back(Scope());
} }
/** /// Pops the current scope from the stack
* Pops the current scope from the stack
*/
void pop_scope() void pop_scope()
{ {
StackData &stack = get_stack_data(); StackData &stack = get_stack_data();
@ -571,9 +515,8 @@ namespace chaiscript
/// Pushes a new stack on to the list of stacks /// Pushes a new stack on to the list of stacks
void new_stack() void new_stack()
{ {
Stack s(new Stack::element_type()); // add a new Stack with 1 element
s->push_back(Scope()); m_stack_holder->stacks.emplace_back(1);
m_stack_holder->stacks.push_back(s);
} }
void pop_stack() void pop_stack()
@ -581,17 +524,9 @@ namespace chaiscript
m_stack_holder->stacks.pop_back(); m_stack_holder->stacks.pop_back();
} }
/// \returns the current stack /// Searches the current stack for an object of the given name
Stack get_stack() const /// includes a special overload for the _ place holder object to
{ /// ensure that it is always in scope.
return m_stack_holder->stacks.back();
}
/**
* Searches the current stack for an object of the given name
* includes a special overload for the _ place holder object to
* ensure that it is always in scope.
*/
Boxed_Value get_object(const std::string &name) const Boxed_Value get_object(const std::string &name) const
{ {
// Is it a placeholder object? // Is it a placeholder object?
@ -600,13 +535,13 @@ namespace chaiscript
return m_place_holder; return m_place_holder;
} }
StackData &stack = get_stack_data(); auto &stack = get_stack_data();
// Is it in the stack? // Is it in the stack?
for (int i = static_cast<int>(stack.size())-1; i >= 0; --i) for (auto stack_elem = stack.rbegin(); stack_elem != stack.rend(); ++stack_elem)
{ {
std::map<std::string, Boxed_Value>::const_iterator stackitr = stack[i].find(name); const auto stackitr = stack_elem->find(name);
if (stackitr != stack[i].end()) if (stackitr != stack_elem->end())
{ {
return stackitr->second; return stackitr->second;
} }
@ -616,7 +551,7 @@ namespace chaiscript
{ {
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_global_object_mutex); chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_global_object_mutex);
auto itr = m_state.m_global_objects.find(name); const auto itr = m_state.m_global_objects.find(name);
if (itr != m_state.m_global_objects.end()) if (itr != m_state.m_global_objects.end())
{ {
return itr->second; return itr->second;
@ -627,9 +562,7 @@ namespace chaiscript
return get_function_object(name); return get_function_object(name);
} }
/** /// Registers a new named type
* Registers a new named type
*/
void add(const Type_Info &ti, const std::string &name) void add(const Type_Info &ti, const std::string &name)
{ {
add_global_const(const_var(ti), name + "_type"); add_global_const(const_var(ti), name + "_type");
@ -639,14 +572,12 @@ namespace chaiscript
m_state.m_types.insert(std::make_pair(name, ti)); m_state.m_types.insert(std::make_pair(name, ti));
} }
/** /// Returns the type info for a named type
* Returns the type info for a named type
*/
Type_Info get_type(const std::string &name) const Type_Info get_type(const std::string &name) 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 = m_state.m_types.find(name); const auto itr = m_state.m_types.find(name);
if (itr != m_state.m_types.end()) if (itr != m_state.m_types.end())
{ {
@ -656,11 +587,9 @@ namespace chaiscript
throw std::range_error("Type Not Known"); throw std::range_error("Type Not Known");
} }
/** /// Returns the registered name of a known type_info object
* Returns the registered name of a known type_info object /// compares the "bare_type_info" for the broadest possible
* compares the "bare_type_info" for the broadest possible /// match
* match
*/
std::string get_type_name(const Type_Info &ti) const std::string get_type_name(const Type_Info &ti) 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);
@ -676,9 +605,7 @@ namespace chaiscript
return ti.bare_name(); return ti.bare_name();
} }
/** /// Return all registered types
* Return all registered types
*/
std::vector<std::pair<std::string, Type_Info> > get_types() const std::vector<std::pair<std::string, Type_Info> > get_types() 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);
@ -686,18 +613,14 @@ namespace chaiscript
return std::vector<std::pair<std::string, Type_Info> >(m_state.m_types.begin(), m_state.m_types.end()); return std::vector<std::pair<std::string, Type_Info> >(m_state.m_types.begin(), m_state.m_types.end());
} }
/** /// Return a function by name
* Return a function by name std::vector< Proxy_Function > get_function(const std::string &t_name) const
*/
std::vector< Proxy_Function >
get_function(const std::string &t_name) 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);
const std::map<std::string, std::vector<Proxy_Function> > &funs = get_functions_int(); const auto &funs = get_functions_int();
auto itr auto itr = funs.find(t_name);
= funs.find(t_name);
if (itr != funs.end()) if (itr != funs.end())
{ {
@ -713,7 +636,7 @@ namespace chaiscript
{ {
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);
const std::map<std::string, Proxy_Function> &funs = get_function_objects_int(); const auto &funs = get_function_objects_int();
auto itr = funs.find(t_name); auto itr = funs.find(t_name);
@ -725,14 +648,12 @@ namespace chaiscript
} }
} }
/** /// Return true if a function exists
* Return true if a function exists
*/
bool function_exists(const std::string &name) const bool function_exists(const std::string &name) 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);
const std::map<std::string, std::vector<Proxy_Function> > &functions = get_functions_int(); const auto &functions = get_functions_int();
return functions.find(name) != functions.end(); return functions.find(name) != functions.end();
} }
@ -740,7 +661,7 @@ namespace chaiscript
/// the current scope. /// the current scope.
std::map<std::string, Boxed_Value> get_parent_locals() const std::map<std::string, Boxed_Value> get_parent_locals() const
{ {
StackData &stack = get_stack_data(); auto &stack = get_stack_data();
if (stack.size() > 1) if (stack.size() > 1)
{ {
return stack[1]; return stack[1];
@ -752,8 +673,8 @@ namespace chaiscript
/// \returns All values in the local thread state, added through the add() function /// \returns All values in the local thread state, added through the add() function
std::map<std::string, Boxed_Value> get_locals() const std::map<std::string, Boxed_Value> get_locals() const
{ {
StackData &stack = get_stack_data(); auto &stack = get_stack_data();
Scope &scope = stack.front(); auto &scope = stack.front();
return scope; return scope;
} }
@ -764,8 +685,8 @@ namespace chaiscript
/// Any existing locals are removed and the given set of variables is added /// Any existing locals are removed and the given set of variables is added
void set_locals(const std::map<std::string, Boxed_Value> &t_locals) void set_locals(const std::map<std::string, Boxed_Value> &t_locals)
{ {
StackData &stack = get_stack_data(); auto &stack = get_stack_data();
Scope &scope = stack.front(); auto &scope = stack.front();
scope = t_locals; scope = t_locals;
} }
@ -779,12 +700,11 @@ namespace chaiscript
Stack_Holder &s = *m_stack_holder; Stack_Holder &s = *m_stack_holder;
// We don't want the current context, but one up if it exists // We don't want the current context, but one up if it exists
StackData &stack = (s.stacks.size()==1)?(*(s.stacks.back())):(*s.stacks[s.stacks.size()-2]); StackData &stack = (s.stacks.size()==1)?(s.stacks.back()):(s.stacks[s.stacks.size()-2]);
std::map<std::string, Boxed_Value> retval; std::map<std::string, Boxed_Value> retval;
// note: map insert doesn't overwrite existing values, which is why this works // note: map insert doesn't overwrite existing values, which is why this works
for (auto itr = stack.rbegin(); itr != stack.rend(); ++itr) for (auto itr = stack.rbegin(); itr != stack.rend(); ++itr)
{ {
retval.insert(itr->begin(), itr->end()); retval.insert(itr->begin(), itr->end());
@ -808,7 +728,7 @@ namespace chaiscript
{ {
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);
const std::map<std::string, Proxy_Function> &funs = get_function_objects_int(); const auto &funs = get_function_objects_int();
std::map<std::string, Boxed_Value> objs; std::map<std::string, Boxed_Value> objs;
@ -821,22 +741,20 @@ namespace chaiscript
} }
/** /// Get a vector of all registered functions
* Get a vector of all registered functions
*/
std::vector<std::pair<std::string, Proxy_Function > > get_functions() const std::vector<std::pair<std::string, Proxy_Function > > get_functions() 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);
std::vector<std::pair<std::string, Proxy_Function> > rets; std::vector<std::pair<std::string, Proxy_Function> > rets;
const std::map<std::string, std::vector<Proxy_Function> > &functions = get_functions_int(); const auto &functions = get_functions_int();
for (const auto & function : functions) for (const auto & function : functions)
{ {
for (const auto & internal_func : function.second) for (const auto & internal_func : function.second)
{ {
rets.push_back(std::make_pair(function.first, internal_func)); rets.emplace_back(function.first, internal_func);
} }
} }
@ -850,16 +768,14 @@ namespace chaiscript
m_state.m_reserved_words.insert(name); m_state.m_reserved_words.insert(name);
} }
const Dynamic_Cast_Conversions &conversions() const const Type_Conversions &conversions() const
{ {
return m_conversions; return m_conversions;
} }
Boxed_Value call_function(const std::string &t_name, const std::vector<Boxed_Value> &params) const Boxed_Value call_function(const std::string &t_name, const std::vector<Boxed_Value> &params) const
{ {
std::vector<Proxy_Function> functions = get_function(t_name); return dispatch::dispatch(get_function(t_name), params, m_conversions);
return dispatch::dispatch(functions.begin(), functions.end(), params, m_conversions);
} }
Boxed_Value call_function(const std::string &t_name) const Boxed_Value call_function(const std::string &t_name) const
@ -867,40 +783,29 @@ namespace chaiscript
return call_function(t_name, std::vector<Boxed_Value>()); return call_function(t_name, std::vector<Boxed_Value>());
} }
Boxed_Value call_function(const std::string &t_name, const Boxed_Value &p1) const Boxed_Value call_function(const std::string &t_name, Boxed_Value p1) const
{ {
std::vector<Boxed_Value> params; return call_function(t_name, std::vector<Boxed_Value>({std::move(p1)}));
params.push_back(p1);
return call_function(t_name, params);
} }
Boxed_Value call_function(const std::string &t_name, const Boxed_Value &p1, const Boxed_Value &p2) const Boxed_Value call_function(const std::string &t_name, Boxed_Value p1, Boxed_Value p2) const
{ {
std::vector<Boxed_Value> params; return call_function(t_name, std::vector<Boxed_Value>({std::move(p1), std::move(p2)}));
params.push_back(p1);
params.push_back(p2);
return call_function(t_name, params);
} }
/** /// Dump object info to stdout
* Dump object info to stdout
*/
void dump_object(const Boxed_Value &o) const void dump_object(const Boxed_Value &o) const
{ {
std::cout << (o.is_const()?"const ":"") << type_name(o) << std::endl; std::cout << (o.is_const()?"const ":"") << type_name(o) << std::endl;
} }
/** /// Dump type info to stdout
* Dump type info to stdout
*/
void dump_type(const Type_Info &type) const void dump_type(const Type_Info &type) const
{ {
std::cout << (type.is_const()?"const ":"") << get_type_name(type); std::cout << (type.is_const()?"const ":"") << get_type_name(type);
} }
/** /// Dump function to stdout
* Dump function to stdout
*/
void dump_function(const std::pair<const std::string, Proxy_Function > &f) const void dump_function(const std::pair<const std::string, Proxy_Function > &f) const
{ {
std::vector<Type_Info> params = f.second->get_param_types(); std::vector<Type_Info> params = f.second->get_param_types();
@ -928,25 +833,21 @@ namespace chaiscript
std::cout << ") " << std::endl; std::cout << ") " << std::endl;
} }
/** /// Returns true if a call can be made that consists of the first parameter
* Returns true if a call can be made that consists of the first parameter /// (the function) with the remaining parameters as its arguments.
* (the function) with the remaining parameters as its arguments.
*/
Boxed_Value call_exists(const std::vector<Boxed_Value> &params) Boxed_Value call_exists(const std::vector<Boxed_Value> &params)
{ {
if (params.size() < 1) if (params.empty())
{ {
throw chaiscript::exception::arity_error(static_cast<int>(params.size()), 1); throw chaiscript::exception::arity_error(static_cast<int>(params.size()), 1);
} }
Const_Proxy_Function f = this->boxed_cast<Const_Proxy_Function>(params[0]); const Const_Proxy_Function &f = this->boxed_cast<Const_Proxy_Function>(params[0]);
return Boxed_Value(f->call_match(std::vector<Boxed_Value>(params.begin() + 1, params.end()), m_conversions)); return Boxed_Value(f->call_match(std::vector<Boxed_Value>(params.begin() + 1, params.end()), m_conversions));
} }
/** /// Dump all system info to stdout
* Dump all system info to stdout
*/
void dump_system() const void dump_system() const
{ {
std::cout << "Registered Types: " << std::endl; std::cout << "Registered Types: " << std::endl;
@ -973,9 +874,7 @@ namespace chaiscript
std::cout << std::endl; std::cout << std::endl;
} }
/** /// return true if the Boxed_Value matches the registered type by name
* return true if the Boxed_Value matches the registered type by name
*/
bool is_type(const Boxed_Value &r, const std::string &user_typename) const bool is_type(const Boxed_Value &r, const std::string &user_typename) const
{ {
try { try {
@ -1016,6 +915,22 @@ namespace chaiscript
m_state = t_state; m_state = t_state;
} }
void save_function_params(std::initializer_list<Boxed_Value> t_params)
{
Stack_Holder &s = *m_stack_holder;
s.call_params.insert(s.call_params.begin(), std::move(t_params));
}
void save_function_params(std::vector<Boxed_Value> &&t_params)
{
Stack_Holder &s = *m_stack_holder;
for (auto &&param : t_params)
{
s.call_params.insert(s.call_params.begin(), std::move(param));
}
}
void save_function_params(const std::vector<Boxed_Value> &t_params) void save_function_params(const std::vector<Boxed_Value> &t_params)
{ {
Stack_Holder &s = *m_stack_holder; Stack_Holder &s = *m_stack_holder;
@ -1024,7 +939,15 @@ namespace chaiscript
void new_function_call() void new_function_call()
{ {
Stack_Holder &s = *m_stack_holder;
if (s.call_depth == 0)
{
m_conversions.enable_conversion_saves(true);
}
++m_stack_holder->call_depth; ++m_stack_holder->call_depth;
save_function_params(m_conversions.take_saves());
} }
void pop_function_call() void pop_function_call()
@ -1039,17 +962,16 @@ namespace chaiscript
/// \todo Critical: this needs to be smarter, memory can expand quickly /// \todo Critical: this needs to be smarter, memory can expand quickly
/// in tight loops involving function calls /// in tight loops involving function calls
s.call_params.clear(); s.call_params.clear();
m_conversions.enable_conversion_saves(false);
} }
} }
private: private:
/** /// Returns the current stack
* Returns the current stack /// make const/non const versions
* make const/non const versions
*/
StackData &get_stack_data() const StackData &get_stack_data() const
{ {
return *(m_stack_holder->stacks.back()); return m_stack_holder->stacks.back();
} }
const std::map<std::string, Proxy_Function> &get_function_objects_int() const const std::map<std::string, Proxy_Function> &get_function_objects_int() const
@ -1074,17 +996,17 @@ namespace chaiscript
static bool function_less_than(const Proxy_Function &lhs, const Proxy_Function &rhs) static bool function_less_than(const Proxy_Function &lhs, const Proxy_Function &rhs)
{ {
const std::vector<Type_Info> lhsparamtypes = lhs->get_param_types(); const auto &lhsparamtypes = lhs->get_param_types();
const std::vector<Type_Info> rhsparamtypes = rhs->get_param_types(); const auto &rhsparamtypes = rhs->get_param_types();
const size_t lhssize = lhsparamtypes.size(); const auto lhssize = lhsparamtypes.size();
const size_t rhssize = rhsparamtypes.size(); const auto rhssize = rhsparamtypes.size();
const Type_Info boxed_type = user_type<Boxed_Value>(); CHAISCRIPT_CONSTEXPR auto boxed_type = user_type<Boxed_Value>();
const Type_Info boxed_pod_type = user_type<Boxed_Number>(); CHAISCRIPT_CONSTEXPR auto boxed_pod_type = user_type<Boxed_Number>();
std::shared_ptr<const dispatch::Dynamic_Proxy_Function> dynamic_lhs(std::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(lhs)); auto dynamic_lhs(std::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(lhs));
std::shared_ptr<const dispatch::Dynamic_Proxy_Function> dynamic_rhs(std::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(rhs)); auto dynamic_rhs(std::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(rhs));
if (dynamic_lhs && dynamic_rhs) if (dynamic_lhs && dynamic_rhs)
{ {
@ -1112,11 +1034,10 @@ namespace chaiscript
} }
for (size_t i = 1; i < lhssize && i < rhssize; ++i) for (size_t i = 1; i < lhssize && i < rhssize; ++i)
{ {
const Type_Info lt = lhsparamtypes[i]; const Type_Info &lt = lhsparamtypes[i];
const Type_Info rt = rhsparamtypes[i]; const Type_Info &rt = rhsparamtypes[i];
if (lt.bare_equal(rt) && lt.is_const() == rt.is_const()) if (lt.bare_equal(rt) && lt.is_const() == rt.is_const())
{ {
@ -1167,9 +1088,7 @@ namespace chaiscript
} }
/** /// Throw a reserved_word exception if the name is not allowed
* Throw a reserved_word exception if the name is not allowed
*/
void validate_object_name(const std::string &name) const void validate_object_name(const std::string &name) const
{ {
if (name.find("::") != std::string::npos) { if (name.find("::") != std::string::npos) {
@ -1184,29 +1103,24 @@ namespace chaiscript
} }
} }
/** /// Implementation detail for adding a function.
* Implementation detail for adding a function. /// \throws exception::name_conflict_error if there's a function matching the given one being added
* \throws exception::name_conflict_error if there's a function matching the given one being added
*/
void add_function(const Proxy_Function &t_f, const std::string &t_name) void add_function(const Proxy_Function &t_f, const std::string &t_name)
{ {
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);
std::map<std::string, std::vector<Proxy_Function> > &funcs = get_functions_int(); auto &funcs = get_functions_int();
auto itr auto itr = funcs.find(t_name);
= funcs.find(t_name);
std::map<std::string, Proxy_Function> &func_objs = get_function_objects_int(); auto &func_objs = get_function_objects_int();
if (itr != funcs.end()) if (itr != funcs.end())
{ {
std::vector<Proxy_Function> &vec = itr->second; auto &vec = itr->second;
for (std::vector<Proxy_Function>::const_iterator itr2 = vec.begin(); for (const auto &func : vec)
itr2 != vec.end();
++itr2)
{ {
if ((*t_f) == *(*itr2)) if ((*t_f) == *(func))
{ {
throw chaiscript::exception::name_conflict_error(t_name); throw chaiscript::exception::name_conflict_error(t_name);
} }
@ -1214,19 +1128,16 @@ namespace chaiscript
vec.push_back(t_f); vec.push_back(t_f);
std::stable_sort(vec.begin(), vec.end(), &function_less_than); std::stable_sort(vec.begin(), vec.end(), &function_less_than);
func_objs[t_name] = Proxy_Function(new Dispatch_Function(vec)); func_objs[t_name] = std::make_shared<Dispatch_Function>(vec);
} else if (t_f->has_arithmetic_param()) { } else if (t_f->has_arithmetic_param()) {
// if the function is the only function but it also contains // if the function is the only function but it also contains
// arithmetic operators, we must wrap it in a dispatch function // arithmetic operators, we must wrap it in a dispatch function
// to allow for automatic arithmetic type conversions // to allow for automatic arithmetic type conversions
std::vector<Proxy_Function> vec; std::vector<Proxy_Function> vec({t_f});
vec.push_back(t_f);
funcs.insert(std::make_pair(t_name, vec)); funcs.insert(std::make_pair(t_name, vec));
func_objs[t_name] = Proxy_Function(new Dispatch_Function(vec)); func_objs[t_name] = std::make_shared<Dispatch_Function>(std::move(vec));
} else { } else {
std::vector<Proxy_Function> vec; funcs.insert(std::make_pair(t_name, std::vector<Proxy_Function>{t_f}));
vec.push_back(t_f);
funcs.insert(std::make_pair(t_name, vec));
func_objs[t_name] = t_f; func_objs[t_name] = t_f;
} }
@ -1241,18 +1152,16 @@ namespace chaiscript
Stack_Holder() Stack_Holder()
: call_depth(0) : call_depth(0)
{ {
Stack s(new StackData()); stacks.emplace_back(1);
s->push_back(Scope());
stacks.push_back(s);
} }
std::deque<Stack> stacks; std::deque<StackData> stacks;
std::list<Boxed_Value> call_params; std::list<Boxed_Value> call_params;
int call_depth; int call_depth;
}; };
Dynamic_Cast_Conversions m_conversions; Type_Conversions m_conversions;
chaiscript::detail::threading::Thread_Storage<Stack_Holder> m_stack_holder; chaiscript::detail::threading::Thread_Storage<Stack_Holder> m_stack_holder;

View File

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

View File

@ -23,7 +23,7 @@
#include "type_info.hpp" #include "type_info.hpp"
namespace chaiscript { namespace chaiscript {
class Dynamic_Cast_Conversions; class Type_Conversions;
namespace dispatch { namespace dispatch {
class Proxy_Function_Base; class Proxy_Function_Base;
} // namespace dispatch } // namespace dispatch
@ -64,18 +64,16 @@ namespace chaiscript
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 : public Proxy_Function_Base
{ {
public: public:
Dynamic_Object_Function( Dynamic_Object_Function(
std::string t_type_name, std::string t_type_name,
const Proxy_Function &t_func) const Proxy_Function &t_func)
: Proxy_Function_Base(t_func->get_param_types()), : Proxy_Function_Base(t_func->get_param_types(), t_func->get_arity()),
m_type_name(std::move(t_type_name)), m_func(t_func), m_doti(user_type<Dynamic_Object>()) m_type_name(std::move(t_type_name)), m_func(t_func), m_doti(user_type<Dynamic_Object>())
{ {
assert( (t_func->get_arity() > 0 || t_func->get_arity() < 0) assert( (t_func->get_arity() > 0 || t_func->get_arity() < 0)
@ -86,7 +84,7 @@ namespace chaiscript
std::string t_type_name, std::string t_type_name,
const Proxy_Function &t_func, const Proxy_Function &t_func,
const Type_Info &t_ti) const Type_Info &t_ti)
: Proxy_Function_Base(build_param_types(t_func->get_param_types(), t_ti)), : Proxy_Function_Base(build_param_types(t_func->get_param_types(), t_ti), t_func->get_arity()),
m_type_name(std::move(t_type_name)), m_func(t_func), m_ti(new Type_Info(t_ti)), m_doti(user_type<Dynamic_Object>()) m_type_name(std::move(t_type_name)), m_func(t_func), m_ti(new Type_Info(t_ti)), m_doti(user_type<Dynamic_Object>())
{ {
assert( (t_func->get_arity() > 0 || t_func->get_arity() < 0) assert( (t_func->get_arity() > 0 || t_func->get_arity() < 0)
@ -96,11 +94,11 @@ namespace chaiscript
virtual ~Dynamic_Object_Function() {} 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;
virtual bool operator==(const Proxy_Function_Base &f) const CHAISCRIPT_OVERRIDE virtual bool operator==(const Proxy_Function_Base &f) const CHAISCRIPT_OVERRIDE
{ {
const Dynamic_Object_Function *df = dynamic_cast<const Dynamic_Object_Function *>(&f); if (const auto *df = dynamic_cast<const Dynamic_Object_Function *>(&f))
if (df)
{ {
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 {
@ -108,7 +106,7 @@ namespace chaiscript
} }
} }
virtual bool call_match(const std::vector<Boxed_Value> &vals, const Dynamic_Cast_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE virtual bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions &t_conversions) const CHAISCRIPT_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))
{ {
@ -123,12 +121,6 @@ namespace chaiscript
return {m_func}; return {m_func};
} }
virtual int get_arity() const CHAISCRIPT_OVERRIDE
{
return m_func->get_arity();
}
virtual std::string annotation() const CHAISCRIPT_OVERRIDE virtual std::string annotation() const CHAISCRIPT_OVERRIDE
{ {
return m_func->annotation(); return m_func->annotation();
@ -136,7 +128,7 @@ namespace chaiscript
protected: protected:
virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions) const CHAISCRIPT_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))
{ {
@ -146,7 +138,7 @@ namespace chaiscript
} }
} }
virtual bool compare_first_type(const Boxed_Value &bv, const Dynamic_Cast_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE virtual bool compare_first_type(const Boxed_Value &bv, const Type_Conversions &t_conversions) const CHAISCRIPT_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);
} }
@ -164,7 +156,7 @@ namespace chaiscript
} }
bool dynamic_object_typename_match(const Boxed_Value &bv, const std::string &name, bool dynamic_object_typename_match(const Boxed_Value &bv, const std::string &name,
const std::shared_ptr<Type_Info> &ti, const Dynamic_Cast_Conversions &t_conversions) const const std::unique_ptr<Type_Info> &ti, const Type_Conversions &t_conversions) const
{ {
if (bv.get_type_info().bare_equal(m_doti)) if (bv.get_type_info().bare_equal(m_doti))
{ {
@ -186,7 +178,7 @@ namespace chaiscript
} }
bool dynamic_object_typename_match(const std::vector<Boxed_Value> &bvs, const std::string &name, bool dynamic_object_typename_match(const std::vector<Boxed_Value> &bvs, const std::string &name,
const std::shared_ptr<Type_Info> &ti, const Dynamic_Cast_Conversions &t_conversions) const const std::unique_ptr<Type_Info> &ti, const Type_Conversions &t_conversions) const
{ {
if (bvs.size() > 0) if (bvs.size() > 0)
{ {
@ -198,7 +190,7 @@ namespace chaiscript
std::string m_type_name; std::string m_type_name;
Proxy_Function m_func; Proxy_Function m_func;
std::shared_ptr<Type_Info> m_ti; std::unique_ptr<Type_Info> m_ti;
const Type_Info m_doti; const Type_Info m_doti;
@ -217,7 +209,7 @@ namespace chaiscript
Dynamic_Object_Constructor( Dynamic_Object_Constructor(
std::string t_type_name, std::string t_type_name,
const Proxy_Function &t_func) const Proxy_Function &t_func)
: Proxy_Function_Base(build_type_list(t_func->get_param_types())), : Proxy_Function_Base(build_type_list(t_func->get_param_types()), t_func->get_arity() - 1),
m_type_name(std::move(t_type_name)), m_func(t_func) 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)
@ -250,33 +242,24 @@ namespace chaiscript
} }
} }
virtual bool call_match(const std::vector<Boxed_Value> &vals, const Dynamic_Cast_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE virtual bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
{ {
std::vector<Boxed_Value> new_vals; std::vector<Boxed_Value> new_vals{Boxed_Value(Dynamic_Object(m_type_name))};
new_vals.push_back(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(new_vals, t_conversions);
} }
virtual int get_arity() const CHAISCRIPT_OVERRIDE
{
// "this" is not considered part of the arity
return m_func->get_arity() - 1;
}
virtual std::string annotation() const CHAISCRIPT_OVERRIDE virtual std::string annotation() const CHAISCRIPT_OVERRIDE
{ {
return m_func->annotation(); return m_func->annotation();
} }
protected: protected:
virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
{ {
std::vector<Boxed_Value> new_params; auto bv = var(Dynamic_Object(m_type_name));
chaiscript::Boxed_Value bv = var(Dynamic_Object(m_type_name)); std::vector<Boxed_Value> new_params{bv};
new_params.push_back(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)(new_params, t_conversions);

View File

@ -23,6 +23,7 @@ namespace chaiscript
{ {
namespace detail namespace detail
{ {
/// \todo make this a variadic template
struct Exception_Handler_Base 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;

View File

@ -18,7 +18,7 @@
namespace chaiscript { namespace chaiscript {
class Boxed_Value; class Boxed_Value;
class Dynamic_Cast_Conversions; class Type_Conversions;
namespace detail { namespace detail {
template <typename T> struct Cast_Helper; template <typename T> struct Cast_Helper;
} // namespace detail } // namespace detail
@ -28,66 +28,56 @@ namespace chaiscript
{ {
namespace dispatch namespace dispatch
{ {
/** /// 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 = /// build_function_caller(dispatchkit.get_function("print"));
* build_function_caller(dispatchkit.get_function("print")); /// \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 Dynamic_Cast_Conversions *t_conversions) functor(const std::vector<Const_Proxy_Function> &funcs, const Type_Conversions *t_conversions)
{ {
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);
} }
/** /// Build a function caller for a particular Proxy_Function object
* Build a function caller for a particular Proxy_Function object /// useful in the case that a function is being pass out from scripting back
* useful in the case that a function is being pass out from scripting back /// into code
* into code /// example:
* example: /// void my_function(Proxy_Function f)
* void my_function(Proxy_Function f) /// {
* { /// std::function<void (int)> local_f =
* std::function<void (int)> local_f = /// build_function_caller(f);
* build_function_caller(f); /// }
* } /// \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 Dynamic_Cast_Conversions *t_conversions) functor(Const_Proxy_Function func, const Type_Conversions *t_conversions)
{ {
std::vector<Const_Proxy_Function> funcs; return functor<FunctionType>(std::vector<Const_Proxy_Function>({func}), t_conversions);
funcs.push_back(func);
return functor<FunctionType>(funcs, 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 Dynamic_Cast_Conversions *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 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> &>
{ {
typedef std::function<Signature> Result_Type; typedef std::function<Signature> Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *t_conversions) 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>())) if (ob.get_type_info().bare_equal(user_type<Const_Proxy_Function>()))
{ {
@ -98,15 +88,13 @@ 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> >
{ {
typedef std::function<Signature> Result_Type; typedef std::function<Signature> Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *t_conversions) 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>())) if (ob.get_type_info().bare_equal(user_type<Const_Proxy_Function>()))
{ {
@ -117,15 +105,13 @@ namespace chaiscript
} }
}; };
/** /// Cast helper to handle automatic casting to const std::function
* Cast helper to handle automatic casting to const std::function
*/
template<typename Signature> template<typename Signature>
struct Cast_Helper<const std::function<Signature> > struct Cast_Helper<const std::function<Signature> >
{ {
typedef std::function<Signature> Result_Type; typedef std::function<Signature> Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *t_conversions) 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>())) if (ob.get_type_info().bare_equal(user_type<Const_Proxy_Function>()))
{ {

View File

@ -17,7 +17,7 @@
#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 "dynamic_cast_conversion.hpp" #include "type_conversions.hpp"
#include "proxy_functions.hpp" #include "proxy_functions.hpp"
namespace chaiscript namespace chaiscript
@ -26,15 +26,13 @@ namespace chaiscript
{ {
namespace detail namespace detail
{ {
/** /// Internal helper class for handling the return
* Internal helper class for handling the return /// value of a build_function_caller
* value of a build_function_caller
*/
template<typename Ret, bool is_arithmetic> template<typename Ret, bool is_arithmetic>
struct Function_Caller_Ret struct Function_Caller_Ret
{ {
static Ret call(const std::vector<Const_Proxy_Function> &t_funcs, static Ret call(const std::vector<Const_Proxy_Function> &t_funcs,
const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions) const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions)
{ {
return boxed_cast<Ret>(dispatch::dispatch(t_funcs, params, t_conversions)); return boxed_cast<Ret>(dispatch::dispatch(t_funcs, params, t_conversions));
} }
@ -47,7 +45,7 @@ namespace chaiscript
struct Function_Caller_Ret<Ret, true> struct Function_Caller_Ret<Ret, true>
{ {
static Ret call(const std::vector<Const_Proxy_Function> &t_funcs, static Ret call(const std::vector<Const_Proxy_Function> &t_funcs,
const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions) const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions)
{ {
return Boxed_Number(dispatch::dispatch(t_funcs, params, t_conversions)).get_as<Ret>(); return Boxed_Number(dispatch::dispatch(t_funcs, params, t_conversions)).get_as<Ret>();
} }
@ -61,7 +59,7 @@ namespace chaiscript
struct Function_Caller_Ret<void, false> struct Function_Caller_Ret<void, false>
{ {
static void call(const std::vector<Const_Proxy_Function> &t_funcs, static void call(const std::vector<Const_Proxy_Function> &t_funcs,
const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions) const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions)
{ {
dispatch::dispatch(t_funcs, params, t_conversions); dispatch::dispatch(t_funcs, params, t_conversions);
} }
@ -73,7 +71,7 @@ namespace chaiscript
template<typename Ret, typename ... Param> template<typename Ret, typename ... Param>
struct Build_Function_Caller_Helper struct Build_Function_Caller_Helper
{ {
Build_Function_Caller_Helper(std::vector<Const_Proxy_Function> t_funcs, const Dynamic_Cast_Conversions &t_conversions) Build_Function_Caller_Helper(std::vector<Const_Proxy_Function> t_funcs, const Type_Conversions &t_conversions)
: m_funcs(std::move(t_funcs)), : m_funcs(std::move(t_funcs)),
m_conversions(t_conversions) m_conversions(t_conversions)
{ {
@ -81,7 +79,7 @@ namespace chaiscript
Ret operator()(Param...param) Ret operator()(Param...param)
{ {
return Function_Caller_Ret<Ret, std::is_arithmetic<Ret>::value>::call(m_funcs, { return Function_Caller_Ret<Ret, std::is_arithmetic<Ret>::value && !std::is_same<Ret, bool>::value>::call(m_funcs, {
(std::is_reference<Param>::value&&!(std::is_same<chaiscript::Boxed_Value, typename std::remove_const<typename std::remove_reference<Param>::type>::type>::value))?Boxed_Value(std::ref(param)):Boxed_Value(param)... (std::is_reference<Param>::value&&!(std::is_same<chaiscript::Boxed_Value, typename std::remove_const<typename std::remove_reference<Param>::type>::type>::value))?Boxed_Value(std::ref(param)):Boxed_Value(param)...
}, m_conversions }, m_conversions
@ -90,13 +88,13 @@ namespace chaiscript
} }
std::vector<Const_Proxy_Function> m_funcs; std::vector<Const_Proxy_Function> m_funcs;
Dynamic_Cast_Conversions m_conversions; Type_Conversions m_conversions;
}; };
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 Dynamic_Cast_Conversions *t_conversions) std::function<Ret (Params...)> build_function_caller_helper(Ret (Params...), const std::vector<Const_Proxy_Function> &funcs, const Type_Conversions *t_conversions)
{ {
if (funcs.size() == 1) if (funcs.size() == 1)
{ {
@ -112,7 +110,7 @@ namespace chaiscript
// 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?*t_conversions:Dynamic_Cast_Conversions())); return std::function<Ret (Params...)>(Build_Function_Caller_Helper<Ret, Params...>(funcs, t_conversions?*t_conversions:Type_Conversions()));
} }
} }
} }

View File

@ -48,6 +48,15 @@ namespace chaiscript
} }
}; };
template<typename Ret>
struct Handle_Return<const Ret *>
{
static Boxed_Value handle(const Ret *p)
{
return Boxed_Value(p);
}
};
template<typename Ret> template<typename Ret>
struct Handle_Return<std::shared_ptr<Ret> &> struct Handle_Return<std::shared_ptr<Ret> &>
{ {

View File

@ -8,6 +8,7 @@
#define CHAISCRIPT_OPERATORS_HPP_ #define CHAISCRIPT_OPERATORS_HPP_
#include "../chaiscript_defines.hpp" #include "../chaiscript_defines.hpp"
#include "register_function.hpp"
namespace chaiscript namespace chaiscript
{ {
@ -15,146 +16,150 @@ namespace chaiscript
{ {
namespace operators namespace operators
{ {
template<typename Ret, typename L, typename R> namespace detail
Ret assign(L l, R r) {
/// \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); return (l = r);
} }
template<typename Ret, typename L, typename R> template<typename L, typename R>
Ret assign_bitwise_and(L l, R r) auto assign_bitwise_and(L l, R r) -> decltype((l &= r))
{ {
return (l &= r); return (l &= r);
} }
template<typename Ret, typename L, typename R> template<typename L, typename R>
Ret assign_xor(L l, R r) auto assign_xor(L l, R r) -> decltype((l^=r))
{ {
return (l ^= r); return (l ^= r);
} }
template<typename Ret, typename L, typename R> template<typename L, typename R>
Ret assign_bitwise_or(L l, R r) auto assign_bitwise_or(L l, R r) -> decltype((l |= r))
{ {
return (l |= r); return (l |= r);
} }
template<typename Ret, typename L, typename R> template<typename L, typename R>
Ret assign_difference(L l, R r) auto assign_difference(L l, R r) -> decltype(( l -= r))
{ {
return (l -= r); return (l -= r);
} }
template<typename Ret, typename L, typename R> template<typename L, typename R>
Ret assign_left_shift(L l, R r) auto assign_left_shift(L l, R r) -> decltype(( l <<= r))
{ {
return (l <<= r); return (l <<= r);
} }
template<typename Ret, typename L, typename R> template<typename L, typename R>
Ret assign_product(L l, R r) auto assign_product(L l, R r) -> decltype(( l *= r ))
{ {
return (l *= r); return (l *= r);
} }
template<typename Ret, typename L, typename R> template<typename L, typename R>
Ret assign_quotient(L l, R r) auto assign_quotient(L l, R r) -> decltype(( l /= r ))
{ {
return (l /= r); return (l /= r);
} }
template<typename Ret, typename L, typename R> template<typename L, typename R>
Ret assign_remainder(L l, R r) auto assign_remainder(L l, R r) -> decltype(( l %= r ))
{ {
return (l %= r); return (l %= r);
} }
template<typename Ret, typename L, typename R> template<typename L, typename R>
Ret assign_right_shift(L l, R r) auto assign_right_shift(L l, R r) -> decltype(( l >>= r))
{ {
return (l >>= r); return (l >>= r);
} }
template<typename Ret, typename L, typename R> /// \todo make this return a decltype once we drop gcc 4.6
Ret assign_sum(L l, R r) template<typename L, typename R>
auto assign_sum(L l, R r) -> L&
{ {
return (l += r); return (l += r);
} }
template<typename Ret, typename L> template<typename L>
Ret prefix_decrement(L l) auto prefix_decrement(L l) -> decltype(( --l ))
{ {
return (--l); return (--l);
} }
template<typename Ret, typename L> template<typename L>
Ret prefix_increment(L l) auto prefix_increment(L l) -> decltype(( ++l ))
{ {
return (++l); return (++l);
} }
template<typename Ret, typename L, typename R> template<typename L, typename R>
Ret equal(L l, R r) auto equal(L l, R r) -> decltype(( l == r ))
{ {
return (l == r); return (l == r);
} }
template<typename Ret, typename L, typename R> template<typename L, typename R>
Ret greater_than(L l, R r) auto greater_than(L l, R r) -> decltype(( l > r ))
{ {
return (l > r); return (l > r);
} }
template<typename Ret, typename L, typename R> template<typename L, typename R>
Ret greater_than_equal(L l, R r) auto greater_than_equal(L l, R r) -> decltype(( l >= r ))
{ {
return (l >= r); return (l >= r);
} }
template<typename Ret, typename L, typename R> template<typename L, typename R>
Ret less_than(L l, R r) auto less_than(L l, R r) -> decltype(( l < r ))
{ {
return (l < r); return (l < r);
} }
template<typename Ret, typename L, typename R> template<typename L, typename R>
Ret less_than_equal(L l, R r) auto less_than_equal(L l, R r) -> decltype(( l <= r ))
{ {
return (l <= r); return (l <= r);
} }
template<typename Ret, typename L> template<typename L>
Ret logical_compliment(L l) auto logical_compliment(L l) -> decltype(( !l ))
{ {
return (!l); return (!l);
} }
template<typename Ret, typename L, typename R> template<typename L, typename R>
Ret not_equal(L l, R r) auto not_equal(L l, R r) -> decltype(( l != r ))
{ {
return (l != r); return (l != r);
} }
template<typename Ret, typename L, typename R> template<typename L, typename R>
Ret addition(L l, R r) auto addition(L l, R r) -> decltype(( l + r ))
{ {
return (l + r); return (l + r);
} }
template<typename Ret, typename L> template<typename L>
Ret unary_plus(L l) auto unary_plus(L l) -> decltype(( +l ))
{ {
return (+l); return (+l);
} }
template<typename Ret, typename L, typename R> template<typename L, typename R>
Ret subtraction(L l, R r) auto subtraction(L l, R r) -> decltype(( l - r ))
{ {
return (l - r); return (l - r);
} }
template<typename Ret, typename L> template<typename L>
Ret unary_minus(L l) auto unary_minus(L l) -> decltype(( -l ))
{ {
#ifdef CHAISCRIPT_MSVC #ifdef CHAISCRIPT_MSVC
#pragma warning(push) #pragma warning(push)
@ -166,291 +171,291 @@ namespace chaiscript
#endif #endif
} }
template<typename Ret, typename L, typename R> template<typename L, typename R>
Ret bitwise_and(L l, R r) auto bitwise_and(L l, R r) -> decltype(( l & r ))
{ {
return (l & r); return (l & r);
} }
template<typename Ret, typename L> template<typename L>
Ret bitwise_compliment(L l) auto bitwise_compliment(L l) -> decltype(( ~l ))
{ {
return (~l); return (~l);
} }
template<typename Ret, typename L, typename R> template<typename L, typename R>
Ret bitwise_xor(L l, R r) auto bitwise_xor(L l, R r) -> decltype(( l ^ r ))
{ {
return (l ^ r); return (l ^ r);
} }
template<typename Ret, typename L, typename R> template<typename L, typename R>
Ret bitwise_or(L l, R r) auto bitwise_or(L l, R r) -> decltype(( l | r ))
{ {
return (l | r); return (l | r);
} }
template<typename Ret, typename L, typename R> template<typename L, typename R>
Ret division(L l, R r) auto division(L l, R r) -> decltype(( l / r ))
{ {
return (l / r); return (l / r);
} }
template<typename Ret, typename L, typename R> template<typename L, typename R>
Ret left_shift(L l, R r) auto left_shift(L l, R r) -> decltype(( l << r ))
{ {
return l << r; return l << r;
} }
template<typename Ret, typename L, typename R> template<typename L, typename R>
Ret multiplication(L l, R r) auto multiplication(L l, R r) -> decltype(( l * r ))
{ {
return l * r; return l * r;
} }
template<typename Ret, typename L, typename R> template<typename L, typename R>
Ret remainder(L l, R r) auto remainder(L l, R r) -> decltype(( l % r ))
{ {
return (l % r); return (l % r);
} }
template<typename Ret, typename L, typename R> template<typename L, typename R>
Ret right_shift(L l, R r) auto right_shift(L l, R r) -> decltype(( l >> r ))
{ {
return (l >> r); return (l >> r);
} }
}
template<typename T> template<typename T>
ModulePtr assign(ModulePtr m = ModulePtr(new Module())) ModulePtr assign(ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun(&assign<T &, T &, const T&>), "="); m->add(chaiscript::fun(&detail::assign<T &, const T&>), "=");
return m; return m;
} }
template<typename T> template<typename T>
ModulePtr assign_bitwise_and(ModulePtr m = ModulePtr(new Module())) ModulePtr assign_bitwise_and(ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun(&assign_bitwise_and<T &, T &, const T&>), "&="); m->add(chaiscript::fun(&detail::assign_bitwise_and<T &, const T&>), "&=");
return m; return m;
} }
template<typename T> template<typename T>
ModulePtr assign_xor(ModulePtr m = ModulePtr(new Module())) ModulePtr assign_xor(ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun(&assign_xor<T &, T &, const T&>), "^="); m->add(chaiscript::fun(&detail::assign_xor<T &, const T&>), "^=");
return m; return m;
} }
template<typename T> template<typename T>
ModulePtr assign_bitwise_or(ModulePtr m = ModulePtr(new Module())) ModulePtr assign_bitwise_or(ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun(&assign_bitwise_or<T &, T &, const T&>), "|="); m->add(chaiscript::fun(&detail::assign_bitwise_or<T &, const T&>), "|=");
return m; return m;
} }
template<typename T> template<typename T>
ModulePtr assign_difference(ModulePtr m = ModulePtr(new Module())) ModulePtr assign_difference(ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun(&assign_difference<T &, T &, const T&>), "-="); m->add(chaiscript::fun(&detail::assign_difference<T &, const T&>), "-=");
return m; return m;
} }
template<typename T> template<typename T>
ModulePtr assign_left_shift(ModulePtr m = ModulePtr(new Module())) ModulePtr assign_left_shift(ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun(&assign_left_shift<T &, T &, const T&>), "<<="); m->add(chaiscript::fun(&detail::assign_left_shift<T &, const T&>), "<<=");
return m; return m;
} }
template<typename T> template<typename T>
ModulePtr assign_product(ModulePtr m = ModulePtr(new Module())) ModulePtr assign_product(ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun(&assign_product<T &, T &, const T&>), "*="); m->add(chaiscript::fun(&detail::assign_product<T &, const T&>), "*=");
return m; return m;
} }
template<typename T> template<typename T>
ModulePtr assign_quotient(ModulePtr m = ModulePtr(new Module())) ModulePtr assign_quotient(ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun(&assign_quotient<T &, T &, const T&>), "/="); m->add(chaiscript::fun(&detail::assign_quotient<T &, const T&>), "/=");
return m; return m;
} }
template<typename T> template<typename T>
ModulePtr assign_remainder(ModulePtr m = ModulePtr(new Module())) ModulePtr assign_remainder(ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun(&assign_remainder<T &, T &, const T&>), "%="); m->add(chaiscript::fun(&detail::assign_remainder<T &, const T&>), "%=");
return m; return m;
} }
template<typename T> template<typename T>
ModulePtr assign_right_shift(ModulePtr m = ModulePtr(new Module())) ModulePtr assign_right_shift(ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun(&assign_right_shift<T &, T &, const T&>), ">>="); m->add(chaiscript::fun(&detail::assign_right_shift<T &, const T&>), ">>=");
return m; return m;
} }
template<typename T> template<typename T>
ModulePtr assign_sum(ModulePtr m = ModulePtr(new Module())) ModulePtr assign_sum(ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun(&assign_sum<T &, T &, const T&>), "+="); m->add(chaiscript::fun(&detail::assign_sum<T &, const T&>), "+=");
return m; return m;
} }
template<typename T> template<typename T>
ModulePtr prefix_decrement(ModulePtr m = ModulePtr(new Module())) ModulePtr prefix_decrement(ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun(&prefix_decrement<T &, T &>), "--"); m->add(chaiscript::fun(&detail::prefix_decrement<T &>), "--");
return m; return m;
} }
template<typename T> template<typename T>
ModulePtr prefix_increment(ModulePtr m = ModulePtr(new Module())) ModulePtr prefix_increment(ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun(&prefix_increment<T &, T &>), "++"); m->add(chaiscript::fun(&detail::prefix_increment<T &>), "++");
return m; return m;
} }
template<typename T> template<typename T>
ModulePtr equal(ModulePtr m = ModulePtr(new Module())) ModulePtr equal(ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun(&equal<bool, const T&, const T&>), "=="); m->add(chaiscript::fun(&detail::equal<const T&, const T&>), "==");
return m; return m;
} }
template<typename T> template<typename T>
ModulePtr greater_than(ModulePtr m = ModulePtr(new Module())) ModulePtr greater_than(ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun(&greater_than<bool, const T&, const T&>), ">"); m->add(chaiscript::fun(&detail::greater_than<const T&, const T&>), ">");
return m; return m;
} }
template<typename T> template<typename T>
ModulePtr greater_than_equal(ModulePtr m = ModulePtr(new Module())) ModulePtr greater_than_equal(ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun(&greater_than_equal<bool, const T&, const T&>), ">="); m->add(chaiscript::fun(&detail::greater_than_equal<const T&, const T&>), ">=");
return m; return m;
} }
template<typename T> template<typename T>
ModulePtr less_than(ModulePtr m = ModulePtr(new Module())) ModulePtr less_than(ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun(&less_than<bool, const T&, const T&>), "<"); m->add(chaiscript::fun(&detail::less_than<const T&, const T&>), "<");
return m; return m;
} }
template<typename T> template<typename T>
ModulePtr less_than_equal(ModulePtr m = ModulePtr(new Module())) ModulePtr less_than_equal(ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun(&less_than_equal<bool, const T&, const T&>), "<="); m->add(chaiscript::fun(&detail::less_than_equal<const T&, const T&>), "<=");
return m; return m;
} }
template<typename T> template<typename T>
ModulePtr logical_compliment(ModulePtr m = ModulePtr(new Module())) ModulePtr logical_compliment(ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun(&logical_compliment<bool, const T &>), "!"); m->add(chaiscript::fun(&detail::logical_compliment<const T &>), "!");
return m; return m;
} }
template<typename T> template<typename T>
ModulePtr not_equal(ModulePtr m = ModulePtr(new Module())) ModulePtr not_equal(ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun(&not_equal<bool, const T &, const T &>), "!="); m->add(chaiscript::fun(&detail::not_equal<const T &, const T &>), "!=");
return m; return m;
} }
template<typename T> template<typename T>
ModulePtr addition(ModulePtr m = ModulePtr(new Module())) ModulePtr addition(ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun(&addition<T, const T &, const T &>), "+"); m->add(chaiscript::fun(&detail::addition<const T &, const T &>), "+");
return m; return m;
} }
template<typename T> template<typename T>
ModulePtr unary_plus(ModulePtr m = ModulePtr(new Module())) ModulePtr unary_plus(ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun(&unary_plus<T, const T &>), "+"); m->add(chaiscript::fun(&detail::unary_plus<const T &>), "+");
return m; return m;
} }
template<typename T> template<typename T>
ModulePtr subtraction(ModulePtr m = ModulePtr(new Module())) ModulePtr subtraction(ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun(&subtraction<T, const T &, const T &>), "-"); m->add(chaiscript::fun(&detail::subtraction<const T &, const T &>), "-");
return m; return m;
} }
template<typename T> template<typename T>
ModulePtr unary_minus(ModulePtr m = ModulePtr(new Module())) ModulePtr unary_minus(ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun(&unary_minus<T, const T &>), "-"); m->add(chaiscript::fun(&detail::unary_minus<const T &>), "-");
return m; return m;
} }
template<typename T> template<typename T>
ModulePtr bitwise_and(ModulePtr m = ModulePtr(new Module())) ModulePtr bitwise_and(ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun(&bitwise_and<T, const T &, const T &>), "&"); m->add(chaiscript::fun(&detail::bitwise_and<const T &, const T &>), "&");
return m; return m;
} }
template<typename T> template<typename T>
ModulePtr bitwise_compliment(ModulePtr m = ModulePtr(new Module())) ModulePtr bitwise_compliment(ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun(&bitwise_compliment<T, const T &>), "~"); m->add(chaiscript::fun(&detail::bitwise_compliment<const T &>), "~");
return m; return m;
} }
template<typename T> template<typename T>
ModulePtr bitwise_xor(ModulePtr m = ModulePtr(new Module())) ModulePtr bitwise_xor(ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun(&bitwise_xor<T, const T &, const T &>), "^"); m->add(chaiscript::fun(&detail::bitwise_xor<const T &, const T &>), "^");
return m; return m;
} }
template<typename T> template<typename T>
ModulePtr bitwise_or(ModulePtr m = ModulePtr(new Module())) ModulePtr bitwise_or(ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun(&bitwise_or<T, const T &, const T &>), "|"); m->add(chaiscript::fun(&detail::bitwise_or<const T &, const T &>), "|");
return m; return m;
} }
template<typename T> template<typename T>
ModulePtr division(ModulePtr m = ModulePtr(new Module())) ModulePtr division(ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun(&division<T, const T &, const T &>), "/"); m->add(chaiscript::fun(&detail::division<const T &, const T &>), "/");
return m; return m;
} }
template<typename T> template<typename T>
ModulePtr left_shift(ModulePtr m = ModulePtr(new Module())) ModulePtr left_shift(ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun(&left_shift<T, const T &, const T &>), "<<"); m->add(chaiscript::fun(&detail::left_shift<const T &, const T &>), "<<");
return m; return m;
} }
template<typename T> template<typename T>
ModulePtr multiplication(ModulePtr m = ModulePtr(new Module())) ModulePtr multiplication(ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun(&multiplication<T, const T &, const T &>), "*"); m->add(chaiscript::fun(&detail::multiplication<const T &, const T &>), "*");
return m; return m;
} }
template<typename T> template<typename T>
ModulePtr remainder(ModulePtr m = ModulePtr(new Module())) ModulePtr remainder(ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun(&remainder<T, const T &, const T &>), "%"); m->add(chaiscript::fun(&detail::remainder<const T &, const T &>), "%");
return m; return m;
} }
template<typename T> template<typename T>
ModulePtr right_shift(ModulePtr m = ModulePtr(new Module())) ModulePtr right_shift(ModulePtr m = ModulePtr(new Module()))
{ {
m->add(fun(&right_shift<T, const T &, const T &>), ">>"); m->add(chaiscript::fun(&detail::right_shift<const T &, const T &>), ">>");
return m; return m;
} }
} }

View File

@ -21,7 +21,7 @@ namespace chaiscript
template<typename Class, typename ... Params> template<typename Class, typename ... Params>
std::shared_ptr<Class> constructor_(Params ... params) std::shared_ptr<Class> constructor_(Params ... params)
{ {
return std::shared_ptr<Class>(new Class(params...)); return std::make_shared<Class>(params...);
} }
template<typename Class, typename ... Params > template<typename Class, typename ... Params >

View File

@ -26,7 +26,7 @@
#include "type_info.hpp" #include "type_info.hpp"
namespace chaiscript { namespace chaiscript {
class Dynamic_Cast_Conversions; class Type_Conversions;
namespace exception { namespace exception {
class bad_boxed_cast; class bad_boxed_cast;
struct arity_error; struct arity_error;
@ -55,7 +55,7 @@ namespace chaiscript
public: public:
virtual ~Proxy_Function_Base() {} virtual ~Proxy_Function_Base() {}
Boxed_Value operator()(const std::vector<Boxed_Value> &params, const chaiscript::Dynamic_Cast_Conversions &t_conversions) const Boxed_Value operator()(const std::vector<Boxed_Value> &params, const chaiscript::Type_Conversions &t_conversions) const
{ {
Boxed_Value bv = do_call(params, t_conversions); Boxed_Value bv = do_call(params, t_conversions);
return bv; return bv;
@ -63,12 +63,12 @@ namespace chaiscript
/// Returns a vector containing all of the types of the parameters the function returns/takes /// Returns a vector containing all of the types of the parameters the function returns/takes
/// if the function is variadic or takes no arguments (arity of 0 or -1), the returned /// if the function is variadic or takes no arguments (arity of 0 or -1), the returned
/// value containes exactly 1 Type_Info object: the return type /// value contains exactly 1 Type_Info object: the return type
/// \returns the types of all parameters. /// \returns the types of all parameters.
const std::vector<Type_Info> &get_param_types() const { return m_types; } const std::vector<Type_Info> &get_param_types() const { return m_types; }
virtual bool operator==(const Proxy_Function_Base &) const = 0; virtual bool operator==(const Proxy_Function_Base &) const = 0;
virtual bool call_match(const std::vector<Boxed_Value> &vals, const Dynamic_Cast_Conversions &t_conversions) const = 0; virtual bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions &t_conversions) const = 0;
bool has_arithmetic_param() const bool has_arithmetic_param() const
{ {
@ -82,15 +82,13 @@ namespace chaiscript
//! Return true if the function is a possible match //! Return true if the function is a possible match
//! to the passed in values //! to the passed in values
bool filter(const std::vector<Boxed_Value> &vals, const Dynamic_Cast_Conversions &t_conversions) const bool filter(const std::vector<Boxed_Value> &vals, const Type_Conversions &t_conversions) const
{ {
int arity = get_arity(); if (m_arity < 0)
if (arity < 0)
{ {
return true; return true;
} else if (size_t(arity) == vals.size()) { } else if (size_t(m_arity) == vals.size()) {
if (arity == 0) if (m_arity == 0)
{ {
return true; return true;
} else { } else {
@ -102,11 +100,14 @@ namespace chaiscript
} }
/// \returns the number of arguments the function takes or -1 if it is variadic /// \returns the number of arguments the function takes or -1 if it is variadic
virtual int get_arity() const = 0; int get_arity() const
{
return m_arity;
}
virtual std::string annotation() const = 0; virtual std::string annotation() const = 0;
static bool compare_type_to_param(const Type_Info &ti, const Boxed_Value &bv, const Dynamic_Cast_Conversions &t_conversions) static bool compare_type_to_param(const Type_Info &ti, const Boxed_Value &bv, const Type_Conversions &t_conversions)
{ {
if (ti.is_undef() if (ti.is_undef()
|| ti.bare_equal(user_type<Boxed_Value>()) || ti.bare_equal(user_type<Boxed_Value>())
@ -114,7 +115,7 @@ namespace chaiscript
&& (ti.bare_equal(user_type<Boxed_Number>()) && (ti.bare_equal(user_type<Boxed_Number>())
|| ti.bare_equal(bv.get_type_info()) || ti.bare_equal(bv.get_type_info())
|| bv.get_type_info().bare_equal(user_type<std::shared_ptr<const Proxy_Function_Base> >()) || bv.get_type_info().bare_equal(user_type<std::shared_ptr<const Proxy_Function_Base> >())
|| t_conversions.dynamic_cast_converts(ti, bv.get_type_info()) || t_conversions.converts(ti, bv.get_type_info())
) )
) )
) )
@ -125,10 +126,10 @@ namespace chaiscript
} }
} }
protected: protected:
virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions) const = 0; virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions) const = 0;
Proxy_Function_Base(std::vector<Type_Info> t_types) Proxy_Function_Base(std::vector<Type_Info> t_types, int t_arity)
: m_types(std::move(t_types)), m_has_arithmetic_param(false) : m_types(std::move(t_types)), m_has_arithmetic_param(false), m_arity(t_arity)
{ {
for (size_t i = 1; i < m_types.size(); ++i) for (size_t i = 1; i < m_types.size(); ++i)
{ {
@ -141,7 +142,7 @@ namespace chaiscript
} }
virtual bool compare_first_type(const Boxed_Value &bv, const Dynamic_Cast_Conversions &t_conversions) const virtual bool compare_first_type(const Boxed_Value &bv, const Type_Conversions &t_conversions) const
{ {
const std::vector<Type_Info> &types = get_param_types(); const std::vector<Type_Info> &types = get_param_types();
@ -175,14 +176,14 @@ namespace chaiscript
std::vector<Type_Info> m_types; std::vector<Type_Info> m_types;
bool m_has_arithmetic_param; bool m_has_arithmetic_param;
int m_arity;
}; };
} }
/// \brief Common typedef used for passing of any registered function in ChaiScript /// \brief Common typedef used for passing of any registered function in ChaiScript
typedef std::shared_ptr<dispatch::Proxy_Function_Base> Proxy_Function; typedef std::shared_ptr<dispatch::Proxy_Function_Base> Proxy_Function;
/// \brief Const version of Proxy_Function chaiscript. Points to a const Proxy_Function. This is how most registered functions /// \brief Const version of Proxy_Function. Points to a const Proxy_Function. This is how most registered functions
/// are handled internally. /// are handled internally.
typedef std::shared_ptr<const dispatch::Proxy_Function_Base> Const_Proxy_Function; typedef std::shared_ptr<const dispatch::Proxy_Function_Base> Const_Proxy_Function;
@ -216,7 +217,7 @@ namespace chaiscript
AST_NodePtr t_parsenode = AST_NodePtr(), AST_NodePtr t_parsenode = AST_NodePtr(),
std::string t_description = "", std::string t_description = "",
Proxy_Function t_guard = Proxy_Function()) Proxy_Function t_guard = Proxy_Function())
: Proxy_Function_Base(build_param_type_list(t_arity)), : Proxy_Function_Base(build_param_type_list(t_arity), t_arity),
m_f(std::move(t_f)), m_arity(t_arity), m_description(std::move(t_description)), m_guard(std::move(t_guard)), m_parsenode(std::move(t_parsenode)) m_f(std::move(t_f)), m_arity(t_arity), m_description(std::move(t_description)), m_guard(std::move(t_guard)), m_parsenode(std::move(t_parsenode))
{ {
} }
@ -233,16 +234,12 @@ namespace chaiscript
&& !this->m_guard && !prhs->m_guard); && !this->m_guard && !prhs->m_guard);
} }
virtual bool call_match(const std::vector<Boxed_Value> &vals, const Dynamic_Cast_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE virtual bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
{ {
return (m_arity < 0 || vals.size() == size_t(m_arity)) return (m_arity < 0 || vals.size() == size_t(m_arity))
&& test_guard(vals, t_conversions); && test_guard(vals, t_conversions);
} }
virtual int get_arity() const CHAISCRIPT_OVERRIDE
{
return m_arity;
}
Proxy_Function get_guard() const Proxy_Function get_guard() const
{ {
@ -260,7 +257,7 @@ namespace chaiscript
} }
protected: protected:
virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
{ {
if (m_arity < 0 || params.size() == size_t(m_arity)) if (m_arity < 0 || params.size() == size_t(m_arity))
{ {
@ -278,7 +275,7 @@ namespace chaiscript
} }
private: private:
bool test_guard(const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions) const bool test_guard(const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions) const
{ {
if (m_guard) if (m_guard)
{ {
@ -338,8 +335,8 @@ namespace chaiscript
public: public:
Bound_Function(const Const_Proxy_Function &t_f, Bound_Function(const Const_Proxy_Function &t_f,
const std::vector<Boxed_Value> &t_args) const std::vector<Boxed_Value> &t_args)
: Proxy_Function_Base(build_param_type_info(t_f, t_args)), : Proxy_Function_Base(build_param_type_info(t_f, t_args), (t_f->get_arity()<0?-1:static_cast<int>(build_param_type_info(t_f, t_args).size())-1)),
m_f(t_f), m_args(t_args), m_arity(t_f->get_arity()<0?-1:static_cast<int>(get_param_types().size())-1) m_f(t_f), m_args(t_args)
{ {
assert(m_f->get_arity() < 0 || m_f->get_arity() == static_cast<int>(m_args.size())); assert(m_f->get_arity() < 0 || m_f->get_arity() == static_cast<int>(m_args.size()));
} }
@ -351,7 +348,7 @@ namespace chaiscript
virtual ~Bound_Function() {} virtual ~Bound_Function() {}
virtual bool call_match(const std::vector<Boxed_Value> &vals, const Dynamic_Cast_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE virtual bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
{ {
return m_f->call_match(build_param_list(vals), t_conversions); return m_f->call_match(build_param_list(vals), t_conversions);
} }
@ -395,11 +392,6 @@ namespace chaiscript
return args; return args;
} }
virtual int get_arity() const CHAISCRIPT_OVERRIDE
{
return m_arity;
}
virtual std::string annotation() const CHAISCRIPT_OVERRIDE virtual std::string annotation() const CHAISCRIPT_OVERRIDE
{ {
return "Bound: " + m_f->annotation(); return "Bound: " + m_f->annotation();
@ -429,7 +421,7 @@ namespace chaiscript
return retval; return retval;
} }
virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
{ {
return (*m_f)(build_param_list(params), t_conversions); return (*m_f)(build_param_list(params), t_conversions);
} }
@ -437,30 +429,24 @@ namespace chaiscript
private: private:
Const_Proxy_Function m_f; Const_Proxy_Function m_f;
std::vector<Boxed_Value> m_args; std::vector<Boxed_Value> m_args;
int m_arity;
}; };
class Proxy_Function_Impl_Base : public Proxy_Function_Base class Proxy_Function_Impl_Base : public Proxy_Function_Base
{ {
public: public:
Proxy_Function_Impl_Base(std::vector<Type_Info> t_types) Proxy_Function_Impl_Base(const std::vector<Type_Info> &t_types)
: Proxy_Function_Base(std::move(t_types)) : Proxy_Function_Base(t_types, static_cast<int>(t_types.size()) - 1)
{ {
} }
virtual ~Proxy_Function_Impl_Base() {} virtual ~Proxy_Function_Impl_Base() {}
virtual int get_arity() const CHAISCRIPT_OVERRIDE
{
return static_cast<int>(m_types.size()) - 1;
}
virtual std::string annotation() const CHAISCRIPT_OVERRIDE virtual std::string annotation() const CHAISCRIPT_OVERRIDE
{ {
return ""; return "";
} }
virtual bool call_match(const std::vector<Boxed_Value> &vals, const Dynamic_Cast_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE virtual bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
{ {
if (int(vals.size()) != get_arity()) if (int(vals.size()) != get_arity())
{ {
@ -470,7 +456,7 @@ namespace chaiscript
return compare_types(m_types, vals) || compare_types_with_cast(vals, t_conversions); return compare_types(m_types, vals) || compare_types_with_cast(vals, t_conversions);
} }
virtual bool compare_types_with_cast(const std::vector<Boxed_Value> &vals, const Dynamic_Cast_Conversions &t_conversions) const = 0; virtual bool compare_types_with_cast(const std::vector<Boxed_Value> &vals, const Type_Conversions &t_conversions) const = 0;
}; };
/** /**
@ -490,7 +476,7 @@ namespace chaiscript
virtual ~Proxy_Function_Impl() {} virtual ~Proxy_Function_Impl() {}
virtual bool compare_types_with_cast(const std::vector<Boxed_Value> &vals, const Dynamic_Cast_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE virtual bool compare_types_with_cast(const std::vector<Boxed_Value> &vals, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
{ {
return detail::compare_types_cast(m_dummy_func, vals, t_conversions); return detail::compare_types_cast(m_dummy_func, vals, t_conversions);
} }
@ -506,7 +492,7 @@ namespace chaiscript
} }
protected: protected:
virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions) const virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions) const
{ {
return detail::Do_Call<typename std::function<Func>::result_type>::go(m_f, params, t_conversions); return detail::Do_Call<typename std::function<Func>::result_type>::go(m_f, params, t_conversions);
} }
@ -524,7 +510,7 @@ namespace chaiscript
{ {
public: public:
Attribute_Access(T Class::* t_attr) Attribute_Access(T Class::* t_attr)
: Proxy_Function_Base(param_types()), : Proxy_Function_Base(param_types(), 1),
m_attr(t_attr) m_attr(t_attr)
{ {
} }
@ -543,13 +529,7 @@ namespace chaiscript
} }
} }
virtual bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions &) const CHAISCRIPT_OVERRIDE
virtual int get_arity() const CHAISCRIPT_OVERRIDE
{
return 1;
}
virtual bool call_match(const std::vector<Boxed_Value> &vals, const Dynamic_Cast_Conversions &) const CHAISCRIPT_OVERRIDE
{ {
if (vals.size() != 1) if (vals.size() != 1)
{ {
@ -565,7 +545,7 @@ namespace chaiscript
} }
protected: protected:
virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
{ {
if (params.size() == 1) if (params.size() == 1)
{ {
@ -622,7 +602,7 @@ namespace chaiscript
{ {
template<typename FuncType> template<typename FuncType>
bool types_match_except_for_arithmetic(const FuncType &t_func, const std::vector<Boxed_Value> &plist, bool types_match_except_for_arithmetic(const FuncType &t_func, const std::vector<Boxed_Value> &plist,
const Dynamic_Cast_Conversions &t_conversions) const Type_Conversions &t_conversions)
{ {
if (t_func->get_arity() != static_cast<int>(plist.size())) if (t_func->get_arity() != static_cast<int>(plist.size()))
{ {
@ -650,7 +630,7 @@ namespace chaiscript
template<typename InItr> template<typename InItr>
Boxed_Value dispatch_with_conversions(InItr begin, const InItr &end, const std::vector<Boxed_Value> &plist, Boxed_Value dispatch_with_conversions(InItr begin, const InItr &end, const std::vector<Boxed_Value> &plist,
const Dynamic_Cast_Conversions &t_conversions) const Type_Conversions &t_conversions)
{ {
InItr orig(begin); InItr orig(begin);
@ -712,17 +692,42 @@ namespace chaiscript
* each function against the set of parameters, in order, until a matching * each function against the set of parameters, in order, until a matching
* function is found or throw dispatch_error if no matching function is found * function is found or throw dispatch_error if no matching function is found
*/ */
template<typename InItr> template<typename Funcs>
Boxed_Value dispatch(InItr begin, const InItr &end, Boxed_Value dispatch(const Funcs &funcs,
const std::vector<Boxed_Value> &plist, const Dynamic_Cast_Conversions &t_conversions) const std::vector<Boxed_Value> &plist, const Type_Conversions &t_conversions)
{ {
InItr orig(begin);
while (begin != end) std::multimap<size_t, const Proxy_Function_Base *> ordered_funcs;
for (const auto &func : funcs)
{
size_t numdiffs = 0;
const auto arity = func->get_arity();
if (arity == -1)
{
numdiffs = plist.size();
} else if (arity == static_cast<int>(plist.size())) {
for (size_t i = 0; i < plist.size(); ++i)
{
if (!func->get_param_types()[i+1].bare_equal(plist[i].get_type_info()))
{
++numdiffs;
}
}
} else {
continue;
}
ordered_funcs.insert(std::make_pair(numdiffs, func.get()));
}
for (const auto &func : ordered_funcs )
{ {
try { try {
if ((*begin)->filter(plist, t_conversions)) if (func.second->filter(plist, t_conversions))
{ {
return (*(*begin))(plist, t_conversions); return (*(func.second))(plist, t_conversions);
} }
} catch (const exception::bad_boxed_cast &) { } catch (const exception::bad_boxed_cast &) {
//parameter failed to cast, try again //parameter failed to cast, try again
@ -732,22 +737,9 @@ namespace chaiscript
//guard failed to allow the function to execute, //guard failed to allow the function to execute,
//try again //try again
} }
++begin;
} }
return detail::dispatch_with_conversions(orig, end, plist, t_conversions); return detail::dispatch_with_conversions(funcs.cbegin(), funcs.cend(), plist, t_conversions);
}
/**
* Take a vector of functions and a vector of parameters. Attempt to execute
* each function against the set of parameters, in order, until a matching
* function is found or throw dispatch_error if no matching function is found
*/
template<typename Funcs>
Boxed_Value dispatch(const Funcs &funcs,
const std::vector<Boxed_Value> &plist, const Dynamic_Cast_Conversions &t_conversions)
{
return dispatch::dispatch(funcs.begin(), funcs.end(), plist, t_conversions);
} }
} }
} }

View File

@ -20,7 +20,7 @@
#include "type_info.hpp" #include "type_info.hpp"
namespace chaiscript { namespace chaiscript {
class Dynamic_Cast_Conversions; class Type_Conversions;
namespace exception { namespace exception {
class bad_boxed_cast; class bad_boxed_cast;
} // namespace exception } // namespace exception
@ -53,29 +53,6 @@ namespace chaiscript
{ {
namespace detail namespace detail
{ {
template<typename ... Rest>
struct Build_Param_Type_List;
template<typename Param, typename ... Rest>
struct Build_Param_Type_List<Param, Rest...>
{
static void build(std::vector<Type_Info> &t_params)
{
t_params.push_back(chaiscript::detail::Get_Type_Info<Param>::get());
Build_Param_Type_List<Rest...>::build(t_params);
}
};
// 0th case
template<>
struct Build_Param_Type_List<>
{
static void build(std::vector<Type_Info> &)
{
}
};
/** /**
* 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.
@ -83,12 +60,8 @@ namespace chaiscript
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...))
{ {
/// \todo this code was previously using { chaiscript::detail::Get_Type_Info<Ret>::get()... } /// \note somehow this is responsible for a large part of the code generation
/// but this seems to indicate another bug with MSVC's uniform initializer lists return { user_type<Ret>(), user_type<Params>()... };
std::vector<Type_Info> params;
params.push_back(chaiscript::detail::Get_Type_Info<Ret>::get());
Build_Param_Type_List<Params...>::build(params);
return params;
} }
@ -99,7 +72,7 @@ namespace chaiscript
template<typename Param, typename ... Rest> template<typename Param, typename ... Rest>
struct Try_Cast<Param, Rest...> struct Try_Cast<Param, Rest...>
{ {
static void do_try(const std::vector<Boxed_Value> &params, int generation, const Dynamic_Cast_Conversions &t_conversions) static void do_try(const std::vector<Boxed_Value> &params, int generation, const Type_Conversions &t_conversions)
{ {
boxed_cast<Param>(params[generation], &t_conversions); boxed_cast<Param>(params[generation], &t_conversions);
Try_Cast<Rest...>::do_try(params, generation+1, t_conversions); Try_Cast<Rest...>::do_try(params, generation+1, t_conversions);
@ -110,7 +83,7 @@ namespace chaiscript
template<> template<>
struct Try_Cast<> struct Try_Cast<>
{ {
static void do_try(const std::vector<Boxed_Value> &, int, const Dynamic_Cast_Conversions &) static void do_try(const std::vector<Boxed_Value> &, int, const Type_Conversions &)
{ {
} }
}; };
@ -118,12 +91,12 @@ namespace chaiscript
/** /**
* 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 primarly 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 std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions) const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions)
{ {
try { try {
Try_Cast<Params...>::do_try(params, 0, t_conversions); Try_Cast<Params...>::do_try(params, 0, t_conversions);
@ -140,7 +113,7 @@ namespace chaiscript
template<typename ... InnerParams> template<typename ... InnerParams>
static Ret do_call(const std::function<Ret (Params...)> &f, static Ret do_call(const std::function<Ret (Params...)> &f,
const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions, InnerParams &&... innerparams) 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]); return Call_Func<Ret, count - 1, Params...>::do_call(f, params, t_conversions, std::forward<InnerParams>(innerparams)..., params[sizeof...(Params) - count]);
} }
@ -155,7 +128,7 @@ namespace chaiscript
#endif #endif
template<typename ... InnerParams> template<typename ... InnerParams>
static Ret do_call(const std::function<Ret (Params...)> &f, static Ret do_call(const std::function<Ret (Params...)> &f,
const std::vector<Boxed_Value> &, const Dynamic_Cast_Conversions &t_conversions, InnerParams &&... innerparams) const std::vector<Boxed_Value> &, const Type_Conversions &t_conversions, InnerParams &&... innerparams)
{ {
return f(boxed_cast<Params>(std::forward<InnerParams>(innerparams), &t_conversions)...); return f(boxed_cast<Params>(std::forward<InnerParams>(innerparams), &t_conversions)...);
} }
@ -166,13 +139,13 @@ namespace chaiscript
/** /**
* Used by Proxy_Function_Impl to perform typesafe execution of a function. * Used by Proxy_Function_Impl to perform typesafe execution of a function.
* The function attempts to unbox each paramter to the expected type. * The function attempts to unbox each parameter to the expected type.
* if any unboxing fails the execution of the function fails and * if any unboxing fails the execution of the function fails and
* the bad_boxed_cast is passed up to the caller. * the bad_boxed_cast is passed up to the caller.
*/ */
template<typename Ret, typename ... Params> template<typename Ret, typename ... Params>
Ret call_func(const std::function<Ret (Params...)> &f, Ret call_func(const std::function<Ret (Params...)> &f,
const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions) const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions)
{ {
if (params.size() == sizeof...(Params)) if (params.size() == sizeof...(Params))
{ {
@ -198,7 +171,7 @@ namespace chaiscript
struct Do_Call struct Do_Call
{ {
template<typename Fun> template<typename Fun>
static Boxed_Value go(const std::function<Fun> &fun, const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions) static Boxed_Value go(const std::function<Fun> &fun, const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions)
{ {
return Handle_Return<Ret>::handle(call_func(fun, params, t_conversions)); return Handle_Return<Ret>::handle(call_func(fun, params, t_conversions));
} }
@ -208,7 +181,7 @@ namespace chaiscript
struct Do_Call<void> struct Do_Call<void>
{ {
template<typename Fun> template<typename Fun>
static Boxed_Value go(const std::function<Fun> &fun, const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions) static Boxed_Value go(const std::function<Fun> &fun, const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions)
{ {
call_func(fun, params, t_conversions); call_func(fun, params, t_conversions);
return Handle_Return<void>::handle(); return Handle_Return<void>::handle();

View File

@ -0,0 +1,447 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_DYNAMIC_CAST_CONVERSION_HPP_
#define CHAISCRIPT_DYNAMIC_CAST_CONVERSION_HPP_
#include <atomic>
#include <memory>
#include <set>
#include <stdexcept>
#include <string>
#include <type_traits>
#include <typeinfo>
#include "../chaiscript_threading.hpp"
#include "bad_boxed_cast.hpp"
#include "boxed_cast_helper.hpp"
#include "boxed_value.hpp"
#include "type_info.hpp"
namespace chaiscript
{
namespace exception
{
class bad_boxed_dynamic_cast : public bad_boxed_cast
{
public:
bad_boxed_dynamic_cast(const Type_Info &t_from, const std::type_info &t_to,
const std::string &t_what) CHAISCRIPT_NOEXCEPT
: bad_boxed_cast(t_from, t_to, t_what)
{
}
bad_boxed_dynamic_cast(const Type_Info &t_from, const std::type_info &t_to) CHAISCRIPT_NOEXCEPT
: bad_boxed_cast(t_from, t_to)
{
}
bad_boxed_dynamic_cast(const std::string &w) CHAISCRIPT_NOEXCEPT
: bad_boxed_cast(w)
{
}
virtual ~bad_boxed_dynamic_cast() CHAISCRIPT_NOEXCEPT {}
};
class bad_boxed_type_cast : public bad_boxed_cast
{
public:
bad_boxed_type_cast(const Type_Info &t_from, const std::type_info &t_to,
const std::string &t_what) CHAISCRIPT_NOEXCEPT
: bad_boxed_cast(t_from, t_to, t_what)
{
}
bad_boxed_type_cast(const Type_Info &t_from, const std::type_info &t_to) CHAISCRIPT_NOEXCEPT
: bad_boxed_cast(t_from, t_to)
{
}
bad_boxed_type_cast(const std::string &w) CHAISCRIPT_NOEXCEPT
: bad_boxed_cast(w)
{
}
virtual ~bad_boxed_type_cast() CHAISCRIPT_NOEXCEPT {}
};
}
namespace detail
{
class Type_Conversion_Base
{
public:
virtual Boxed_Value convert(const Boxed_Value &from) const = 0;
virtual Boxed_Value convert_down(const Boxed_Value &to) const = 0;
const Type_Info &to() const
{
return m_to;
}
const Type_Info &from() const
{
return m_from;
}
protected:
Type_Conversion_Base(const Type_Info &t_to, const Type_Info &t_from)
: m_to(t_to), m_from(t_from)
{
}
virtual ~Type_Conversion_Base() {}
private:
Type_Info m_to;
Type_Info m_from;
};
template<typename From, typename To>
class Dynamic_Caster
{
public:
static Boxed_Value cast(const Boxed_Value &t_from)
{
if (t_from.get_type_info().bare_equal(chaiscript::user_type<From>()))
{
if (t_from.is_pointer())
{
// Dynamic cast out the contained boxed value, which we know is the type we want
if (t_from.is_const())
{
std::shared_ptr<const To> data
= std::dynamic_pointer_cast<const To>(detail::Cast_Helper<std::shared_ptr<const From> >::cast(t_from, nullptr));
if (!data)
{
throw std::bad_cast();
}
return Boxed_Value(data);
} else {
std::shared_ptr<To> data
= std::dynamic_pointer_cast<To>(detail::Cast_Helper<std::shared_ptr<From> >::cast(t_from, nullptr));
if (!data)
{
throw std::bad_cast();
}
return Boxed_Value(data);
}
} else {
// Pull the reference out of the contained boxed value, which we know is the type we want
if (t_from.is_const())
{
const From &d = detail::Cast_Helper<const From &>::cast(t_from, nullptr);
const To &data = dynamic_cast<const To &>(d);
return Boxed_Value(std::cref(data));
} else {
From &d = detail::Cast_Helper<From &>::cast(t_from, nullptr);
To &data = dynamic_cast<To &>(d);
return Boxed_Value(std::ref(data));
}
}
} else {
throw chaiscript::exception::bad_boxed_dynamic_cast(t_from.get_type_info(), typeid(To), "Unknown dynamic_cast_conversion");
}
}
};
template<typename Base, typename Derived>
class Dynamic_Conversion_Impl : public Type_Conversion_Base
{
public:
Dynamic_Conversion_Impl()
: Type_Conversion_Base(chaiscript::user_type<Base>(), chaiscript::user_type<Derived>())
{
}
virtual Boxed_Value convert_down(const Boxed_Value &t_base) const CHAISCRIPT_OVERRIDE
{
return Dynamic_Caster<Base, Derived>::cast(t_base);
}
virtual Boxed_Value convert(const Boxed_Value &t_derived) const CHAISCRIPT_OVERRIDE
{
return Dynamic_Caster<Derived, Base>::cast(t_derived);
}
};
template<typename Callable>
class Type_Conversion_Impl : public Type_Conversion_Base
{
public:
Type_Conversion_Impl(Type_Info t_from, Type_Info t_to, Callable t_func)
: Type_Conversion_Base(std::move(t_to), std::move(t_from)),
m_func(std::move(t_func))
{
}
virtual Boxed_Value convert_down(const Boxed_Value &) const CHAISCRIPT_OVERRIDE
{
throw chaiscript::exception::bad_boxed_type_cast("No conversion exists");
}
virtual Boxed_Value convert(const Boxed_Value &t_from) const CHAISCRIPT_OVERRIDE
{
/// \todo better handling of errors from the conversion function
return m_func(t_from);
}
private:
Callable m_func;
};
}
class Type_Conversions
{
public:
struct Less_Than
{
bool operator()(const std::type_info *t_lhs, const std::type_info *t_rhs) const
{
return *t_lhs != *t_rhs && t_lhs->before(*t_rhs);
}
};
Type_Conversions()
: m_num_types(0),
m_thread_cache(this),
m_conversion_saves(this)
{
}
Type_Conversions(const Type_Conversions &t_other)
: m_conversions(t_other.get_conversions()), m_num_types(m_conversions.size()),
m_thread_cache(this),
m_conversion_saves(this)
{
}
const std::set<const std::type_info *, Less_Than> &thread_cache() const
{
auto &cache = *m_thread_cache;
if (cache.size() != m_num_types)
{
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
cache = m_convertableTypes;
}
return cache;
}
void add_conversion(const std::shared_ptr<detail::Type_Conversion_Base> &conversion)
{
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
/// \todo error if a conversion already exists
m_conversions.insert(conversion);
m_convertableTypes.insert({conversion->to().bare_type_info(), conversion->from().bare_type_info()});
m_num_types = m_convertableTypes.size();
}
template<typename T>
bool convertable_type() const
{
return thread_cache().count(user_type<T>().bare_type_info()) != 0;
}
template<typename To, typename From>
bool converts() const
{
return converts(user_type<To>(), user_type<From>());
}
bool converts(const Type_Info &to, const Type_Info &from) const
{
const auto &types = thread_cache();
if (types.count(to.bare_type_info()) != 0 && types.count(from.bare_type_info()) != 0)
{
return has_conversion(to, from) || has_conversion(from, to);
} else {
return false;
}
}
template<typename To>
Boxed_Value boxed_type_conversion(const Boxed_Value &from) const
{
try {
Boxed_Value ret = get_conversion(user_type<To>(), from.get_type_info())->convert(from);
if (m_conversion_saves->enabled) m_conversion_saves->saves.push_back(ret);
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>
Boxed_Value boxed_type_down_conversion(const Boxed_Value &to) const
{
try {
Boxed_Value ret = get_conversion(to.get_type_info(), user_type<From>())->convert_down(to);
if (m_conversion_saves->enabled) m_conversion_saves->saves.push_back(ret);
return ret;
} catch (const std::out_of_range &) {
throw exception::bad_boxed_dynamic_cast(to.get_type_info(), typeid(From), "No known conversion");
} catch (const std::bad_cast &) {
throw exception::bad_boxed_dynamic_cast(to.get_type_info(), typeid(From), "Unable to perform dynamic_cast operation");
}
}
void enable_conversion_saves(bool t_val)
{
m_conversion_saves->enabled = t_val;
}
std::vector<Boxed_Value> take_saves()
{
std::vector<Boxed_Value> ret;
std::swap(ret, m_conversion_saves->saves);
return ret;
}
bool has_conversion(const Type_Info &to, const Type_Info &from) const
{
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
return find(to, from) != m_conversions.end();
}
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);
auto itr = find(to, from);
if (itr != m_conversions.end())
{
return *itr;
} else {
throw std::out_of_range("No such conversion exists from " + from.bare_name() + " to " + to.bare_name());
}
}
private:
std::set<std::shared_ptr<detail::Type_Conversion_Base> >::const_iterator find(
const Type_Info &to, const Type_Info &from) const
{
return std::find_if(m_conversions.begin(), m_conversions.end(),
[&to, &from](const std::shared_ptr<detail::Type_Conversion_Base> &conversion)
{
return conversion->to().bare_equal(to) && conversion->from().bare_equal(from);
}
);
}
std::set<std::shared_ptr<detail::Type_Conversion_Base>> get_conversions() const
{
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
return m_conversions;
}
struct Conversion_Saves
{
Conversion_Saves()
: enabled(false)
{}
bool enabled;
std::vector<Boxed_Value> saves;
};
mutable chaiscript::detail::threading::shared_mutex m_mutex;
std::set<std::shared_ptr<detail::Type_Conversion_Base>> m_conversions;
std::set<const std::type_info *, Less_Than> m_convertableTypes;
std::atomic_size_t m_num_types;
chaiscript::detail::threading::Thread_Storage<std::set<const std::type_info *, Less_Than>> m_thread_cache;
chaiscript::detail::threading::Thread_Storage<Conversion_Saves> m_conversion_saves;
};
typedef std::shared_ptr<chaiscript::detail::Type_Conversion_Base> Type_Conversion;
/// \brief Used to register a to / parent class relationship with ChaiScript. Necessary if you
/// want automatic conversions up your inheritance hierarchy.
///
/// Create a new to class registration for applying to a module or to the ChaiScript engine
/// Currently, due to limitations in module loading on Windows, and for the sake of portability,
/// if you have a type that is introduced in a loadable module and is used by multiple modules
/// (through a tertiary dll that is shared between the modules, static linking the new type
/// into both loadable modules would not be portable), you need to register the type
/// relationship in all modules that use the newly added type in a polymorphic way.
///
/// Example:
/// \code
/// class Base
/// {};
/// class Derived : public Base
/// {};
///
/// chaiscript::ChaiScript chai;
/// chai.add(chaiscript::to_class<Base, Derived>());
/// \endcode
///
template<typename Base, typename Derived>
Type_Conversion base_class()
{
//Can only be used with related polymorphic types
//may be expanded some day to support conversions other than child -> parent
static_assert(std::is_base_of<Base,Derived>::value, "Classes are not related by inheritance");
static_assert(std::is_polymorphic<Base>::value, "Base class must be polymorphic");
static_assert(std::is_polymorphic<Derived>::value, "Derived class must be polymorphic");
return std::make_shared<detail::Dynamic_Conversion_Impl<Base, Derived>>();
}
template<typename Callable>
Type_Conversion type_conversion(const Type_Info &t_from, const Type_Info &t_to,
const Callable &t_func)
{
return std::make_shared<detail::Type_Conversion_Impl<Callable>>(t_from, t_to, t_func);
}
template<typename From, typename To, typename Callable>
Type_Conversion type_conversion(const Callable &t_function)
{
auto func = [t_function](const Boxed_Value &t_bv) -> Boxed_Value {
// not even attempting to call boxed_cast so that we don't get caught in some call recursion
return chaiscript::Boxed_Value(t_function(detail::Cast_Helper<const From &>::cast(t_bv, nullptr)));
};
return std::make_shared<detail::Type_Conversion_Impl<decltype(func)>>(user_type<From>(), user_type<To>(), func);
}
template<typename From, typename To>
Type_Conversion type_conversion()
{
static_assert(std::is_convertible<From, To>::value, "Types are not automatically convertible");
auto func = [](const Boxed_Value &t_bv) -> Boxed_Value {
// not even attempting to call boxed_cast so that we don't get caught in some call recursion
std::cout << " Type conversion to : " << typeid(To).name() << " from " << typeid(From).name() << std::endl;
auto &&from = detail::Cast_Helper<From>::cast(t_bv, nullptr);
std::cout << "Ptr" << static_cast<const void *>(from) << std::endl;
std::cout << "Ptr" << from << std::endl;
To to(from);
return chaiscript::Boxed_Value(to);
};
return std::make_shared<detail::Type_Conversion_Impl<decltype(func)>>(user_type<From>(), user_type<To>(), func);
}
}
#endif

View File

@ -25,6 +25,7 @@ namespace chaiscript
}; };
} }
/// \brief Compile time deduced information about a type /// \brief Compile time deduced information about a type
class Type_Info class Type_Info
{ {
@ -38,7 +39,7 @@ namespace chaiscript
{ {
} }
Type_Info() CHAISCRIPT_CONSTEXPR Type_Info()
: m_type_info(nullptr), m_bare_type_info(nullptr), : m_type_info(nullptr), m_bare_type_info(nullptr),
m_is_const(false), m_is_reference(false), m_is_pointer(false), m_is_const(false), m_is_reference(false), m_is_pointer(false),
m_is_void(false), m_is_arithmetic(false), m_is_void(false), m_is_arithmetic(false),
@ -46,63 +47,49 @@ namespace chaiscript
{ {
} }
Type_Info(const Type_Info &ti) #if !defined(_MSC_VER) || _MSC_VER != 1800
: m_type_info(ti.m_type_info), Type_Info(Type_Info&&) = default;
m_bare_type_info(ti.m_bare_type_info), Type_Info& operator=(Type_Info&&) = default;
m_is_const(ti.m_is_const), m_is_reference(ti.m_is_reference), #endif
m_is_pointer(ti.m_is_pointer),
m_is_void(ti.m_is_void), m_is_arithmetic(ti.m_is_arithmetic),
m_is_undef(ti.m_is_undef)
{
}
Type_Info &operator=(const Type_Info &ti) Type_Info(const Type_Info&) = default;
{ Type_Info& operator=(const Type_Info&) = default;
m_type_info = ti.m_type_info;
m_bare_type_info = ti.m_bare_type_info;
m_is_const = ti.m_is_const;
m_is_reference = ti.m_is_reference;
m_is_pointer = ti.m_is_pointer;
m_is_void = ti.m_is_void;
m_is_arithmetic = ti.m_is_arithmetic;
m_is_undef = ti.m_is_undef;
return *this;
}
bool operator<(const Type_Info &ti) const
CHAISCRIPT_CONSTEXPR bool operator<(const Type_Info &ti) const CHAISCRIPT_NOEXCEPT
{ {
return m_type_info < ti.m_type_info; return m_type_info < ti.m_type_info;
} }
bool operator==(const Type_Info &ti) const CHAISCRIPT_CONSTEXPR bool operator==(const Type_Info &ti) const CHAISCRIPT_NOEXCEPT
{ {
return ti.m_type_info == m_type_info return ti.m_type_info == m_type_info
|| (ti.m_type_info && m_type_info && *ti.m_type_info == *m_type_info); || (ti.m_type_info && m_type_info && *ti.m_type_info == *m_type_info);
} }
bool operator==(const std::type_info &ti) const CHAISCRIPT_CONSTEXPR bool operator==(const std::type_info &ti) const CHAISCRIPT_NOEXCEPT
{ {
return m_type_info != nullptr && (*m_type_info) == ti; return m_type_info != nullptr && (*m_type_info) == ti;
} }
bool bare_equal(const Type_Info &ti) const CHAISCRIPT_CONSTEXPR bool bare_equal(const Type_Info &ti) const CHAISCRIPT_NOEXCEPT
{ {
return ti.m_bare_type_info == m_bare_type_info 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); || (ti.m_bare_type_info && m_bare_type_info && *ti.m_bare_type_info == *m_bare_type_info);
} }
bool bare_equal_type_info(const std::type_info &ti) const CHAISCRIPT_CONSTEXPR bool bare_equal_type_info(const std::type_info &ti) const CHAISCRIPT_NOEXCEPT
{ {
return m_bare_type_info != nullptr return m_bare_type_info != nullptr
&& (*m_bare_type_info) == ti; && (*m_bare_type_info) == ti;
} }
bool is_const() const { return m_is_const; } CHAISCRIPT_CONSTEXPR bool is_const() const CHAISCRIPT_NOEXCEPT { return m_is_const; }
bool is_reference() const { return m_is_reference; } CHAISCRIPT_CONSTEXPR bool is_reference() const CHAISCRIPT_NOEXCEPT { return m_is_reference; }
bool is_void() const { return m_is_void; } CHAISCRIPT_CONSTEXPR bool is_void() const CHAISCRIPT_NOEXCEPT { return m_is_void; }
bool is_arithmetic() const { return m_is_arithmetic; } CHAISCRIPT_CONSTEXPR bool is_arithmetic() const CHAISCRIPT_NOEXCEPT { return m_is_arithmetic; }
bool is_undef() const { return m_is_undef || m_bare_type_info == nullptr; } CHAISCRIPT_CONSTEXPR bool is_undef() const CHAISCRIPT_NOEXCEPT { return m_is_undef || m_bare_type_info == nullptr; }
bool is_pointer() const { return m_is_pointer; } CHAISCRIPT_CONSTEXPR bool is_pointer() const CHAISCRIPT_NOEXCEPT { return m_is_pointer; }
std::string name() const std::string name() const
{ {
@ -124,6 +111,11 @@ namespace chaiscript
} }
} }
CHAISCRIPT_CONSTEXPR const std::type_info *bare_type_info() const
{
return m_bare_type_info;
}
private: private:
const std::type_info *m_type_info; const std::type_info *m_type_info;
const std::type_info *m_bare_type_info; const std::type_info *m_bare_type_info;
@ -215,11 +207,6 @@ namespace chaiscript
} }
}; };
template<typename T>
struct Stripped_Type
{
typedef typename Bare_Type<typename detail::Get_Type_Info<T>::type>::type type;
};
} }
/// \brief Creates a Type_Info object representing the type passed in /// \brief Creates a Type_Info object representing the type passed in

View File

@ -69,6 +69,7 @@ namespace chaiscript
/// \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; typedef std::shared_ptr<AST_Node> AST_NodePtr;
typedef std::shared_ptr<const AST_Node> AST_NodePtr_Const;
/// \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.
@ -82,7 +83,7 @@ namespace chaiscript
File_Position end_position; File_Position end_position;
std::string filename; std::string filename;
std::string detail; std::string detail;
std::vector<AST_NodePtr> call_stack; std::vector<AST_NodePtr_Const> call_stack;
eval_error(const std::string &t_why, const File_Position &t_where, const std::string &t_fname, 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, const std::vector<Boxed_Value> &t_parameters, const std::vector<chaiscript::Const_Proxy_Function> &t_functions,
@ -425,7 +426,7 @@ namespace chaiscript
/// Prints the contents of an AST node, including its children, recursively /// Prints the contents of an AST node, including its children, recursively
std::string to_string(const std::string &t_prepend = "") { std::string to_string(const std::string &t_prepend = "") const {
std::ostringstream oss; std::ostringstream oss;
oss << t_prepend << "(" << ast_node_type_to_string(this->identifier) << ") " oss << t_prepend << "(" << ast_node_type_to_string(this->identifier) << ") "
@ -437,7 +438,7 @@ namespace chaiscript
return oss.str(); return oss.str();
} }
Boxed_Value eval(chaiscript::detail::Dispatch_Engine &t_e) Boxed_Value eval(chaiscript::detail::Dispatch_Engine &t_e) const
{ {
try { try {
return eval_internal(t_e); return eval_internal(t_e);
@ -466,7 +467,7 @@ namespace chaiscript
virtual ~AST_Node() {} virtual ~AST_Node() {}
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &) virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &) const
{ {
throw std::runtime_error("Undispatched ast_node (internal error)"); throw std::runtime_error("Undispatched ast_node (internal error)");
} }
@ -548,6 +549,11 @@ namespace chaiscript
m_de.save_function_params(t_params); m_de.save_function_params(t_params);
} }
void save_params(std::initializer_list<Boxed_Value> t_params)
{
m_de.save_function_params(std::move(t_params));
}
private: private:

View File

@ -26,7 +26,7 @@
#include "../dispatchkit/boxed_cast_helper.hpp" #include "../dispatchkit/boxed_cast_helper.hpp"
#include "../dispatchkit/boxed_value.hpp" #include "../dispatchkit/boxed_value.hpp"
#include "../dispatchkit/dispatchkit.hpp" #include "../dispatchkit/dispatchkit.hpp"
#include "../dispatchkit/dynamic_cast_conversion.hpp" #include "../dispatchkit/type_conversions.hpp"
#include "../dispatchkit/proxy_functions.hpp" #include "../dispatchkit/proxy_functions.hpp"
#include "chaiscript_common.hpp" #include "chaiscript_common.hpp"
@ -282,7 +282,7 @@ namespace chaiscript
return Boxed_Value(); return Boxed_Value();
} }
} }
catch (const chaiscript::eval::detail::Return_Value &rv) { catch (chaiscript::eval::detail::Return_Value &rv) {
return rv.retval; return rv.retval;
} }
} }
@ -345,12 +345,21 @@ namespace chaiscript
m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::function_exists, std::ref(m_engine)), "function_exists"); m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::function_exists, std::ref(m_engine)), "function_exists");
m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::get_function_objects, std::ref(m_engine)), "get_functions"); m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::get_function_objects, std::ref(m_engine)), "get_functions");
m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::get_scripting_objects, std::ref(m_engine)), "get_objects"); m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::get_scripting_objects, std::ref(m_engine)), "get_objects");
m_engine.add(Proxy_Function(new dispatch::Dynamic_Proxy_Function(std::bind(&chaiscript::detail::Dispatch_Engine::call_exists, std::ref(m_engine), std::placeholders::_1))), m_engine.add(Proxy_Function(new dispatch::Dynamic_Proxy_Function(
"call_exists"); [this](const std::vector<Boxed_Value> &t_params) {
return m_engine.call_exists(t_params);
})), "call_exists");
m_engine.add(fun<Boxed_Value (const dispatch::Proxy_Function_Base *, const std::vector<Boxed_Value> &)>(std::bind(&chaiscript::dispatch::Proxy_Function_Base::operator(), std::placeholders::_1, std::placeholders::_2, std::ref(m_engine.conversions()))), "call"); m_engine.add(fun<Boxed_Value (const dispatch::Proxy_Function_Base *, const std::vector<Boxed_Value> &)>(std::bind(&chaiscript::dispatch::Proxy_Function_Base::operator(), std::placeholders::_1, std::placeholders::_2, std::ref(m_engine.conversions()))), "call");
m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::get_type_name, std::ref(m_engine)), "name"); m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::get_type_name, std::ref(m_engine)), "name");
m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::get_type, std::ref(m_engine)), "type");
m_engine.add(fun<void (const Type_Info &, const Type_Info &, const std::function<Boxed_Value (const Boxed_Value &)> &)> (
[=](const Type_Info &t_from, const Type_Info &t_to, const std::function<Boxed_Value (const Boxed_Value &)> &t_func) {
m_engine.add(chaiscript::type_conversion(t_from, t_to, t_func));
}
), "add_type_conversion");
typedef std::string (ChaiScript::*load_mod_1)(const std::string&); typedef std::string (ChaiScript::*load_mod_1)(const std::string&);
typedef void (ChaiScript::*load_mod_2)(const std::string&, const std::string&); typedef void (ChaiScript::*load_mod_2)(const std::string&, const std::string&);
@ -382,7 +391,7 @@ namespace chaiscript
throw chaiscript::exception::file_not_found_error(t_filename); throw chaiscript::exception::file_not_found_error(t_filename);
} }
std::streampos size = infile.tellg(); const auto size = infile.tellg();
infile.seekg(0, std::ios::beg); infile.seekg(0, std::ios::beg);
assert(size >= 0); assert(size >= 0);
@ -391,7 +400,7 @@ namespace chaiscript
{ {
return std::string(); return std::string();
} else { } else {
std::vector<char> v(static_cast<unsigned int>(size)); std::vector<char> v(static_cast<size_t>(size));
infile.read(&v[0], size); infile.read(&v[0], size);
return std::string(v.begin(), v.end()); return std::string(v.begin(), v.end());
} }
@ -457,7 +466,7 @@ namespace chaiscript
u.in_ptr = &ChaiScript::use; u.in_ptr = &ChaiScript::use;
if ( dladdr((void*)(u.out_ptr), &rInfo) && rInfo.dli_fname ) { if ( dladdr((void*)(u.out_ptr), &rInfo) && rInfo.dli_fname ) {
std::string dllpath(rInfo.dli_fname); std::string dllpath(rInfo.dli_fname);
size_t lastslash = dllpath.rfind('/'); const size_t lastslash = dllpath.rfind('/');
if (lastslash != std::string::npos) if (lastslash != std::string::npos)
{ {
dllpath.erase(lastslash); dllpath.erase(lastslash);
@ -465,7 +474,7 @@ namespace chaiscript
// Let's see if this is a link that we should expand // Let's see if this is a link that we should expand
std::vector<char> buf(2048); std::vector<char> buf(2048);
size_t pathlen = readlink(dllpath.c_str(), &buf.front(), buf.size()); const size_t pathlen = readlink(dllpath.c_str(), &buf.front(), buf.size());
if (pathlen > 0 && pathlen < buf.size()) if (pathlen > 0 && pathlen < buf.size())
{ {
dllpath = std::string(&buf.front(), pathlen); dllpath = std::string(&buf.front(), pathlen);
@ -523,10 +532,10 @@ namespace chaiscript
/// \param[in] t_filename Filename to load and evaluate /// \param[in] t_filename Filename to load and evaluate
void use(const std::string &t_filename) void use(const std::string &t_filename)
{ {
for (size_t i = 0; i < m_usepaths.size(); ++i) for (const auto &path : m_usepaths)
{ {
try { try {
const std::string appendedpath = m_usepaths[i] + t_filename; const auto appendedpath = path + t_filename;
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::recursive_mutex> l(m_use_mutex); chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::recursive_mutex> l(m_use_mutex);
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l2(m_mutex); chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l2(m_mutex);
@ -541,14 +550,12 @@ namespace chaiscript
return; // return, we loaded it, or it was already loaded return; // return, we loaded it, or it was already loaded
} catch (const exception::file_not_found_error &) { } catch (const exception::file_not_found_error &) {
if (i == m_usepaths.size() - 1)
{
throw exception::file_not_found_error(t_filename);
}
// failed to load, try the next path // failed to load, try the next path
} }
} }
// failed to load by any name
throw exception::file_not_found_error(t_filename);
} }
/// \brief Adds a constant object that is available in all contexts and to all threads /// \brief Adds a constant object that is available in all contexts and to all threads
@ -679,7 +686,7 @@ namespace chaiscript
/// chaiscript::ChaiScript chai; /// chaiscript::ChaiScript chai;
/// chai.add(chaiscript::base_class<std::runtime_error, chaiscript::dispatch_error>()); /// chai.add(chaiscript::base_class<std::runtime_error, chaiscript::dispatch_error>());
/// \endcode /// \endcode
ChaiScript &add(const Dynamic_Cast_Conversion &d) ChaiScript &add(const Type_Conversion &d)
{ {
m_engine.add(d); m_engine.add(d);
return *this; return *this;
@ -716,15 +723,9 @@ namespace chaiscript
version_stripped_name.erase(version_pos); version_stripped_name.erase(version_pos);
} }
std::vector<std::string> prefixes; std::vector<std::string> prefixes{"lib", "cyg", ""};
prefixes.push_back("lib");
prefixes.push_back("cyg");
prefixes.push_back("");
std::vector<std::string> postfixes; std::vector<std::string> postfixes{".dll", ".so", ""};
postfixes.push_back(".dll");
postfixes.push_back(".so");
postfixes.push_back("");
for (auto & elem : m_modulepaths) for (auto & elem : m_modulepaths)
{ {
@ -733,7 +734,7 @@ namespace chaiscript
for (auto & postfix : postfixes) for (auto & postfix : postfixes)
{ {
try { try {
std::string name = elem + prefix + t_module_name + postfix; const auto name = elem + prefix + t_module_name + postfix;
// std::cerr << "trying location: " << name << std::endl; // std::cerr << "trying location: " << name << std::endl;
load_module(version_stripped_name, name); load_module(version_stripped_name, name);
return name; return name;
@ -845,7 +846,7 @@ namespace chaiscript
/// ///
/// \param[in] t_input Script to execute /// \param[in] t_input Script to execute
/// \param[in] t_handler Optional Exception_Handler used for automatic unboxing of script thrown exceptions /// \param[in] t_handler Optional Exception_Handler used for automatic unboxing of script thrown exceptions
/// \param[in] t_filename Optional filename to report to the user for where the error occured. Useful /// \param[in] t_filename Optional filename to report to the user for where the error occurred. Useful
/// in special cases where you are loading a file internally instead of using eval_file /// in special cases where you are loading a file internally instead of using eval_file
/// ///
/// \return result of the script execution /// \return result of the script execution

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -112,7 +112,7 @@ class Map
}; };
/// \brief A concept implemented by string, Vector and Map. It is convertable to Range, default constructable and back_insertable /// \brief A concept implemented by string, Vector and Map. It is convertible to Range, default constructable and back_insertable
class Container class Container
{ {
public: public:
@ -153,10 +153,10 @@ void print(Object o);
/// \brief ChaiScript representation of std::string. It is an std::string but only some member are exposed to ChaiScript. /// \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 convertable to and from std::string /// 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. /// using the chaiscript::boxed_cast and chaiscript::var functions.
/// ///
/// With the exception of string::trim, string::rtrim, string::ltrim, all members are direct passthroughs to the /// With the exception of string::trim, string::rtrim, string::ltrim, all members are direct pass-throughs to the
/// std::string of the same name. /// std::string of the same name.
/// ///
/// \note Object and function notations are equivalent in ChaiScript. This means that /// \note Object and function notations are equivalent in ChaiScript. This means that
@ -519,7 +519,7 @@ class Function
/// \brief Returns a vector of Type_Info objects that represent the param types for this function. /// \brief Returns a vector of Type_Info objects that represent the param types for this function.
/// The first value in the list is the return type. /// The first value in the list is the return type.
/// ///
/// If this function is a conglomeration of several functions (get_contained_values().size() > 0) /// If this function is a conglomerate of several functions (get_contained_values().size() > 0)
/// then the function returns as many Type_Info objects as it can. If the functions contained all have /// then the function returns as many Type_Info objects as it can. If the functions contained all have
/// the same arity, then it represents the arity. If they have different arities, it returns only /// the same arity, then it represents the arity. If they have different arities, it returns only
/// one value - the return type. /// one value - the return type.
@ -534,7 +534,7 @@ class Function
/// \endcode /// \endcode
Vector get_param_types() const; Vector get_param_types() const;
/// \brief Returns true if the function has a guard to it. Always returns falls for a conglomerate function /// \brief Returns true if the function has a guard to it. Always returns false for a conglomerate function
bool has_guard() const; bool has_guard() const;
/// \brief Calls the function with the given set of parameters and returns the value; /// \brief Calls the function with the given set of parameters and returns the value;

View File

@ -21,8 +21,29 @@ namespace chaiscript
namespace utility namespace utility
{ {
/// \todo Use of this utility, and uniform initializer lists, is causing memory errors in MSVC /// Single step command for registering a class with ChaiScript
///
/// \param[in,out] t_module Model to add class to
/// \param[in] t_class_name Name of the class being registered
/// \param[in] t_constructors Vector of constructors to add
/// \param[in] t_funcs Vector of methods to add
///
/// \example Adding a basic class to ChaiScript in one step
///
/// \code
/// chaiscript::utility::add_class<test>(*m,
/// "test",
/// { constructor<test ()>(),
/// constructor<test (const test &)>() },
/// { {fun(&test::function), "function"},
/// {fun(&test::function2), "function2"},
/// {fun(&test::function3), "function3"},
/// {fun(static_cast<std::string(test::*)(double)>(&test::functionoverload)), "functionoverload" },
/// {fun(static_cast<std::string(test::*)(int)>(&test::functionoverload)), "functionoverload" },
/// {fun(static_cast<test & (test::*)(const test &)>(&test::operator=)), "=" }
/// }
/// );
///
template<typename Class, typename ModuleType> template<typename Class, typename ModuleType>
void add_class(ModuleType &t_module, void add_class(ModuleType &t_module,
const std::string &t_class_name, const std::string &t_class_name,
@ -36,13 +57,11 @@ namespace chaiscript
t_module.add(ctor, t_class_name); t_module.add(ctor, t_class_name);
} }
for(auto fun: t_funcs) for(const auto &fun: t_funcs)
{ {
t_module.add(fun.first, fun.second); t_module.add(fun.first, fun.second);
} }
} }
} }
} }

View File

@ -1,6 +1,15 @@
Notes: Notes:
======= =======
Current Version: 5.4.0 Current Version: 5.5.0
### Changes since 5.4.0
* 2x performance increase
* Significant code cleanups
* Throw exception if user attempts to call function on null object
* Allow user defined type conversions
* Fix object lifetime for nested function calls made at the global scope
* Fix returning of boolean values from function calls
### Changes since 5.3.1 ### Changes since 5.3.1
* Decreased compile time and build size * Decreased compile time and build size

134
samples/inheritance.cpp Normal file
View File

@ -0,0 +1,134 @@
#include <chaiscript/chaiscript.hpp>
#include <chaiscript/chaiscript_stdlib.hpp>
class BaseClass
{
public:
BaseClass()
{
}
virtual ~BaseClass() {}
virtual std::string doSomething(float, double) const = 0;
void setValue(const std::string &t_val) {
if (validateValue(t_val))
{
m_value = t_val;
}
}
std::string getValue() const {
return m_value;
}
protected:
virtual bool validateValue(const std::string &t_val) = 0;
private:
std::string m_value;
};
class ChaiScriptDerived : public BaseClass
{
public:
ChaiScriptDerived(const std::vector<chaiscript::Boxed_Value> &t_funcs)
{
// using the range-checked .at() methods to give us an exception
// instead of a crash if the user passed in too-few params
tie(t_funcs.at(0), m_doSomethingImpl);
tie(t_funcs.at(1), m_validateValueImpl);
}
std::string doSomething(float f, double d) const CHAISCRIPT_OVERRIDE
{
assert(m_doSomethingImpl);
return m_doSomethingImpl(*this, f, d);
}
protected:
bool validateValue(const std::string &t_val) CHAISCRIPT_OVERRIDE
{
assert(m_validateValueImpl);
return m_validateValueImpl(*this, t_val);
}
private:
template<typename Param>
void tie(const chaiscript::Boxed_Value &t_func, Param &t_param)
{
t_param = chaiscript::boxed_cast<Param>(t_func);
}
std::function<std::string (const ChaiScriptDerived&, float, double)> m_doSomethingImpl;
std::function<bool (ChaiScriptDerived&, const std::string &t_val)> m_validateValueImpl;
};
int main()
{
chaiscript::ChaiScript chai(chaiscript::Std_Lib::library());
chai.add(chaiscript::fun(&BaseClass::doSomething), "doSomething");
chai.add(chaiscript::fun(&BaseClass::setValue), "setValue");
chai.add(chaiscript::fun(&BaseClass::getValue), "getValue");
chai.add(chaiscript::constructor<ChaiScriptDerived (const std::vector<chaiscript::Boxed_Value> &)>(), "ChaiScriptDerived");
chai.add(chaiscript::base_class<BaseClass, ChaiScriptDerived>());
chai.add(chaiscript::user_type<BaseClass>(), "BaseClass");
chai.add(chaiscript::user_type<ChaiScriptDerived>(), "ChaiScriptDerived");
std::string script = R""(
def MakeDerived() {
return ChaiScriptDerived(
// create a dynamically created array and pass it in to the constructor
[
fun(this, f, d) {
// see here that we are calling back into the 'this' pointer
return "${this.getValue()}${f * d}";
},
fun(this, new_val) {
if (new_val.size() < 5) {
true;
} else {
print("String ${new_val} is too long");
false;
}
}
]
);
}
var myderived := MakeDerived(); // avoid a copy by using reference assignment :=
)"";
chai.eval(script);
BaseClass &myderived = chai.eval<ChaiScriptDerived&>("myderived");
// at this point in the code myderived is both a ChaiScript variable and a C++ variable. In both cases
// it is a derivation of BaseClass, and the implementation is provided via ChaiScript functors
// assigned in the MakeDerived() factory function
//
// Notice that our validateValue() function has a requirement that the new string be < 5 characters long
myderived.setValue("1234");
assert(myderived.getValue() == "1234");
// chaiscript defined function will print out an error message and refuse to allow the setting
myderived.setValue("12345");
assert(myderived.getValue() == "1234");
chai.eval("myderived.setValue(\"new\")"); // set the value via chaiscript
assert(myderived.getValue() == "new");
// call the other derived method via chaiscript and return the value to c++ land:
std::string retval = chai.eval<std::string>("myderived.doSomething(2,4.3)");
assert(retval == "new8.6");
// The whole process is fully orthogonal
}

View File

@ -2,6 +2,8 @@
#include <chaiscript/chaiscript.hpp> #include <chaiscript/chaiscript.hpp>
#include <string> #include <string>
class TestBaseType class TestBaseType
{ {
public: public:
@ -22,6 +24,30 @@ class TestBaseType
TestBaseType &operator=(const TestBaseType &); TestBaseType &operator=(const TestBaseType &);
}; };
class Type2
{
public:
Type2(TestBaseType t_bt)
: m_bt(std::move(t_bt)),
m_str("Hello World")
{
}
int get_val() const
{
return m_bt.val;
}
const char *get_str() const
{
return m_str.c_str();
}
private:
TestBaseType m_bt;
std::string m_str;
};
enum TestEnum enum TestEnum
{ {
TestValue1 = 1 TestValue1 = 1
@ -51,12 +77,17 @@ class TestMoreDerivedType : public TestDerivedType
std::shared_ptr<TestBaseType> derived_type_factory() std::shared_ptr<TestBaseType> derived_type_factory()
{ {
return std::shared_ptr<TestBaseType>(new TestDerivedType()); return std::make_shared<TestDerivedType>();
} }
std::shared_ptr<TestBaseType> more_derived_type_factory() std::shared_ptr<TestBaseType> more_derived_type_factory()
{ {
return std::shared_ptr<TestBaseType>(new TestMoreDerivedType()); return std::make_shared<TestMoreDerivedType>();
}
std::shared_ptr<TestBaseType> null_factory()
{
return std::shared_ptr<TestBaseType>();
} }
std::string hello_world() std::string hello_world()
@ -90,6 +121,7 @@ CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_test_mo
m->add(chaiscript::user_type<TestBaseType>(), "TestBaseType"); m->add(chaiscript::user_type<TestBaseType>(), "TestBaseType");
m->add(chaiscript::user_type<TestDerivedType>(), "TestDerivedType"); m->add(chaiscript::user_type<TestDerivedType>(), "TestDerivedType");
m->add(chaiscript::user_type<TestMoreDerivedType>(), "TestMoreDerivedType"); m->add(chaiscript::user_type<TestMoreDerivedType>(), "TestMoreDerivedType");
m->add(chaiscript::user_type<Type2>(), "Type2");
m->add(chaiscript::constructor<TestBaseType ()>(), "TestBaseType"); m->add(chaiscript::constructor<TestBaseType ()>(), "TestBaseType");
// m->add(chaiscript::constructor<TestBaseType (int)>(), "TestBaseType"); // m->add(chaiscript::constructor<TestBaseType (int)>(), "TestBaseType");
@ -111,6 +143,7 @@ CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_test_mo
m->add(chaiscript::fun(&derived_type_factory), "derived_type_factory"); m->add(chaiscript::fun(&derived_type_factory), "derived_type_factory");
m->add(chaiscript::fun(&more_derived_type_factory), "more_derived_type_factory"); m->add(chaiscript::fun(&more_derived_type_factory), "more_derived_type_factory");
m->add(chaiscript::fun(&null_factory), "null_factory");
m->add(chaiscript::fun(&TestDerivedType::func), "func"); m->add(chaiscript::fun(&TestDerivedType::func), "func");
@ -129,6 +162,12 @@ CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_test_mo
m->add(chaiscript::fun(&to_int), "to_int"); m->add(chaiscript::fun(&to_int), "to_int");
m->add(chaiscript::fun(&TestBaseType::constMe), "constMe"); m->add(chaiscript::fun(&TestBaseType::constMe), "constMe");
m->add(chaiscript::type_conversion<TestBaseType, Type2>([](const TestBaseType &t_bt) { return Type2(t_bt); }));
m->add(chaiscript::fun(&Type2::get_val), "get_val");
m->add(chaiscript::fun(&Type2::get_str), "get_str");
m->add(chaiscript::type_conversion<const char *, std::string>());
m->add(chaiscript::constructor<Type2 (const TestBaseType &)>(), "Type2");
return m; return m;
} }

View File

@ -0,0 +1,13 @@
load_module("test_module")
auto o := null_factory();
try {
o.func();
} catch (e) {
exit(0);
}
assert_true(false);

View File

@ -2,6 +2,7 @@
#include <chaiscript/chaiscript_defines.hpp> #include <chaiscript/chaiscript_defines.hpp>
#include <chaiscript/dispatchkit/type_info.hpp> #include <chaiscript/dispatchkit/type_info.hpp>
#include <iostream>
#include <cstdlib> #include <cstdlib>
void test_type(const chaiscript::Type_Info &ti, bool t_is_const, bool t_is_pointer, bool t_is_reference, bool t_is_void, void test_type(const chaiscript::Type_Info &ti, bool t_is_const, bool t_is_pointer, bool t_is_reference, bool t_is_void,
@ -30,5 +31,7 @@ int main()
test_type(chaiscript::user_type<const int *>(), true, true, false, false, false); test_type(chaiscript::user_type<const int *>(), true, true, false, false, false);
test_type(chaiscript::Type_Info(), false, false, false, false, true); test_type(chaiscript::Type_Info(), false, false, false, false, true);
std::cout << "Size of Type_Info " << sizeof(chaiscript::Type_Info) << std::endl;
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }

View File

@ -0,0 +1,11 @@
add_type_conversion(type("string"), type("Type_Info"), fun(s) { return type(s); });
// This looks simple, but it takes the string "string" and using the registered
// conversion above, automatically converts that into a Type_Info object, which then
// allows the Type_Info.name() function to be called
assert_equal("string".name(), "string");

View File

@ -0,0 +1,27 @@
load_module("test_module")
auto t := TestBaseType();
// This uses the TestBaseType to Type2 user type
// conversion which was added in the module and then calls
// "get_val()" which exists on the Type2 type
//assert_equal(t.get_val(), 10);
//print("Made it past test 1");
var t2 := Type2(t);
var str = string(get_str(t2));
assert_equal("Hello World", str);
print("Made it past test 2");
assert_equal(11, size(get_str(t2)));
print("Made it past test 3");
assert_equal(11, t2.get_str().size());
print("Made it past test 4");
assert_equal(11, t.get_str().size());
print("Made it past test 5");