Compare commits

..

25 Commits

Author SHA1 Message Date
Jason Turner
4a3315cfd1 Merge pull request #144 from ChaiScript/develop
Merge release 5.5.0 to master
2014-11-10 12:48:25 -07:00
Jason Turner
8a30581eaf Update release notes for version 5.5.0 2014-11-10 12:45:49 -07:00
Jason Turner
a51281a5be Merge branch 'develop' of http://github.com/ChaiScript/ChaiScript into develop 2014-11-06 15:13:51 -07:00
Jason Turner
e0919f7228 Merge branch 'develop' of https://github.com/ChaiScript/ChaiScript into develop 2014-11-06 15:13:30 -07:00
Jason Turner
fa5966bd04 Enable optimizations options for LTO and profile 2014-11-06 15:12:53 -07:00
Jason Turner
f4f2391801 Add support for clang/gcc MemorySanitizer 2014-11-04 15:22:09 -07:00
Jason Turner
5daf837037 Increment version number to 5.5.0 2014-11-04 09:47:32 -07:00
Jason Turner
99396ba05c Add \r skipping code from @jespada 2014-11-03 21:37:25 -07:00
Jason Turner
f5304ac75c Merge branch 'develop' of http://github.com/ChaiScript/ChaiScript into develop 2014-11-03 18:36:10 -07:00
Jason Turner
3f460fdd20 Fix 64bit msvc warning 2014-11-03 18:34:33 -07:00
Jason Turner
4f972bcf67 Refine lifetime of parameters to functions
Fixes crash caused when making function calls in a global context, and
probably fixes other things.
2014-11-03 09:13:30 -07:00
Jason Turner
5d5e881971 Fix arity of functions
A value was being accessed after it was moved.
2014-11-03 08:24:02 -07:00
Jason Turner
5515d058bb Fix some warnings for clang / 64bit windows 2014-11-03 07:33:53 -07:00
Jason Turner
79c5f71975 Fix compilation on gcc 4.6 2014-11-02 21:47:42 -07:00
Jason Turner
c876a89030 Fix crash during user_defined_conversions_2
Temporaries created during user conversion operations were being dropped
before the result of the conversion was able to be used. This fixes that
by temporarily storing the result of the conversion inside the
current Function_Push_Pop context.
2014-11-02 21:37:01 -07:00
Jason Turner
20c0e6016e Add type_conversion helper and failing unit test 2014-11-02 14:08:57 -07:00
Jason Turner
dd12785b72 Reduce virtual calls for get_arity
Saves compiled code size and some minor runtime differences
2014-11-01 18:40:42 -06:00
Jason Turner
87cee688a8 Fix broken type conversion call implementation
- We need to properly order the function so that the one with the least
   number if type differences is the one that is tried first.
2014-11-01 15:52:02 -06:00
Jason Turner
e2cf8a48be Correct check for which types might have conversions 2014-10-29 07:07:12 -06:00
Jason Turner
7c766f87a4 Add thread specific cache of type info
Reduces the number of locks necessary to check of a user defined type
conversion should be scanned for / applied.
2014-10-28 22:12:03 -06:00
Jason Turner
e85be6eb3d Add C++ test for user defined conversion 2014-10-28 20:23:19 -06:00
Jason Turner
7b42d5307a Add ability to register a user defined type conversion
Currently this adds a fair bit of overhead. It will need to be evaluated
further before it's merged.
2014-10-28 14:52:24 -06:00
Jason Turner
43d6f0cf16 Rename dynamic_cast into type_conversion
Prep work for getting user defined type conversions implemented
2014-10-28 12:43:30 -06:00
Jason Turner
86e26966c1 More code cleanups 2014-10-28 10:53:29 -06:00
Jason Turner
9e8b833d11 Code cleanups 2014-10-18 16:18:56 -06:00
30 changed files with 963 additions and 767 deletions

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")
endif()
option(ENABLE_MEMORY_SANITIZER "Enable memory sanitizer testing in gcc/clang" FALSE)
if(ENABLE_MEMORY_SANITIZER)
add_definitions(-fsanitize=memory -g)
set(LINKER_FLAGS "${LINKER_FLAGS} -fsanitize=memory")
endif()
option(ENABLE_UNDEFINED_SANITIZER "Enable undefined behavior sanitizer testing in gcc/clang" FALSE)
if(ENABLE_UNDEFINED_SANITIZER)
add_definitions(-fsanitize=undefined -g)
set(LINKER_FLAGS "${LINKER_FLAGS} -fsanitize=undefined")
endif()
option(ENABLE_LTO "Enable Link Time Optimization" FALSE)
if (ENABLE_LTO)
add_definitions(-flto)
set(LINKER_FLAGS "${LINKER_FLAGS} -flto")
endif()
option(PROFILE_GENERATE "Generate profile data" FALSE)
if (PROFILE_GENERATE)
add_definitions(-fprofile-generate)
set(LINKER_FLAGS "${LINKER_FLAGS} -fprofile-generate")
endif()
option(PROFILE_USE "Use profile data" FALSE)
if (PROFILE_USE)
add_definitions(-fprofile-use)
set(LINKER_FLAGS "${LINKER_FLAGS} -fprofile-use")
endif()
endif()
list(APPEND CPACK_SOURCE_IGNORE_FILES "${CMAKE_CURRENT_BINARY_DIR}")
@@ -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_VERSION_MAJOR 5)
set(CPACK_PACKAGE_VERSION_MINOR 4)
set(CPACK_PACKAGE_VERSION_MINOR 5)
set(CPACK_PACKAGE_VERSION_PATCH 0)
set(CPACK_PACKAGE_EXECUTABLES "chai;ChaiScript Eval")
@@ -133,7 +160,7 @@ else()
endif()
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
option(USE_LIBCXX "Use clang's libcxx" FALSE)
option(USE_LIBCXX "Use clang's libcxx" TRUE)
if(USE_LIBCXX)
add_definitions(-stdlib=libc++)
@@ -154,7 +181,7 @@ endif()
include_directories(include)
set(Chai_INCLUDES include/chaiscript/chaiscript.hpp include/chaiscript/chaiscript_threading.hpp include/chaiscript/dispatchkit/bad_boxed_cast.hpp include/chaiscript/dispatchkit/bind_first.hpp include/chaiscript/dispatchkit/bootstrap.hpp include/chaiscript/dispatchkit/bootstrap_stl.hpp include/chaiscript/dispatchkit/boxed_cast.hpp include/chaiscript/dispatchkit/boxed_cast_helper.hpp include/chaiscript/dispatchkit/boxed_number.hpp include/chaiscript/dispatchkit/boxed_value.hpp include/chaiscript/dispatchkit/dispatchkit.hpp include/chaiscript/dispatchkit/dynamic_cast_conversion.hpp include/chaiscript/dispatchkit/dynamic_object.hpp include/chaiscript/dispatchkit/exception_specification.hpp include/chaiscript/dispatchkit/function_call.hpp include/chaiscript/dispatchkit/function_call_detail.hpp include/chaiscript/dispatchkit/handle_return.hpp include/chaiscript/dispatchkit/operators.hpp include/chaiscript/dispatchkit/proxy_constructors.hpp include/chaiscript/dispatchkit/proxy_functions.hpp include/chaiscript/dispatchkit/proxy_functions_detail.hpp include/chaiscript/dispatchkit/register_function.hpp include/chaiscript/dispatchkit/type_info.hpp include/chaiscript/language/chaiscript_algebraic.hpp include/chaiscript/language/chaiscript_common.hpp include/chaiscript/language/chaiscript_engine.hpp include/chaiscript/language/chaiscript_eval.hpp include/chaiscript/language/chaiscript_parser.hpp include/chaiscript/language/chaiscript_prelude.chai include/chaiscript/language/chaiscript_prelude_docs.hpp include/chaiscript/utility/utility.hpp)
set(Chai_INCLUDES include/chaiscript/chaiscript.hpp include/chaiscript/chaiscript_threading.hpp include/chaiscript/dispatchkit/bad_boxed_cast.hpp include/chaiscript/dispatchkit/bind_first.hpp include/chaiscript/dispatchkit/bootstrap.hpp include/chaiscript/dispatchkit/bootstrap_stl.hpp include/chaiscript/dispatchkit/boxed_cast.hpp include/chaiscript/dispatchkit/boxed_cast_helper.hpp include/chaiscript/dispatchkit/boxed_number.hpp include/chaiscript/dispatchkit/boxed_value.hpp include/chaiscript/dispatchkit/dispatchkit.hpp include/chaiscript/dispatchkit/type_conversions.hpp include/chaiscript/dispatchkit/dynamic_object.hpp include/chaiscript/dispatchkit/exception_specification.hpp include/chaiscript/dispatchkit/function_call.hpp include/chaiscript/dispatchkit/function_call_detail.hpp include/chaiscript/dispatchkit/handle_return.hpp include/chaiscript/dispatchkit/operators.hpp include/chaiscript/dispatchkit/proxy_constructors.hpp include/chaiscript/dispatchkit/proxy_functions.hpp include/chaiscript/dispatchkit/proxy_functions_detail.hpp include/chaiscript/dispatchkit/register_function.hpp include/chaiscript/dispatchkit/type_info.hpp include/chaiscript/language/chaiscript_algebraic.hpp include/chaiscript/language/chaiscript_common.hpp include/chaiscript/language/chaiscript_engine.hpp include/chaiscript/language/chaiscript_eval.hpp include/chaiscript/language/chaiscript_parser.hpp include/chaiscript/language/chaiscript_prelude.chai include/chaiscript/language/chaiscript_prelude_docs.hpp include/chaiscript/utility/utility.hpp)
set_source_files_properties(${Chai_INCLUDES} PROPERTIES HEADER_FILE_ONLY TRUE)

View File

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

View File

@@ -44,20 +44,31 @@ namespace chaiscript {
private:
struct Data
{
Data(const std::type_info &t_type)
: m_type(t_type)
{
}
Data &operator=(const Data &) = delete;
virtual ~Data() {}
virtual void *data() = 0;
const std::type_info &type() const
{
return m_type;
}
virtual std::unique_ptr<Data> clone() const = 0;
const std::type_info &m_type;
};
template<typename T>
struct Data_Impl : Data
{
explicit Data_Impl(T t_type)
: m_data(std::move(t_type))
: Data(typeid(T)),
m_data(std::move(t_type))
{
}
@@ -79,21 +90,19 @@ namespace chaiscript {
};
std::unique_ptr<Data> m_data;
mutable std::array<uint8_t, 15> m_smallSize;
bool m_isSmall = false;
const std::type_info *m_type = &typeid(void);
public:
// construct/copy/destruct
Any() = default;
Any(const Any &t_any)
: m_data(t_any.m_data?t_any.m_data->clone():nullptr),
m_smallSize(t_any.m_smallSize),
m_isSmall(t_any.m_isSmall),
m_type(t_any.m_type)
{
{
if (!t_any.empty())
{
m_data = t_any.m_data->clone();
} else {
m_data.reset();
}
}
#if _MSC_VER != 1800
@@ -102,31 +111,13 @@ namespace chaiscript {
#endif
template<typename ValueType,
typename = typename std::enable_if<!std::is_same<Any, typename std::decay<ValueType>::type>::value>::type,
typename = typename std::enable_if< std::is_trivial<typename std::decay<ValueType>::type>::value>::type,
typename = typename std::enable_if<sizeof(typename std::decay<ValueType>::type) <= sizeof(decltype(m_smallSize)) >::type>
typename = typename std::enable_if<!std::is_same<Any, typename std::decay<ValueType>::type>::value>::type>
explicit Any(ValueType &&t_value)
: m_isSmall(true), m_type(&typeid(typename std::decay<ValueType>::type))
{
m_smallSize.fill(0);
*(static_cast<typename std::decay<ValueType>::type *>(static_cast<void *>(m_smallSize.data()))) = t_value;
// std::cout << "Setting type: " << typeid(typename std::decay<ValueType>::type).name() << " " << t_value << " actual val: " << *(static_cast<typename std::decay<ValueType>::type *>(static_cast<void *>(m_smallSize.data()))) << " cast: " << cast<typename std::decay<ValueType>::type>() << "\n";
}
template<typename ValueType,
typename = typename std::enable_if<!std::is_same<Any, typename std::decay<ValueType>::type>::value>::type,
typename = typename std::enable_if<
!std::is_trivial<typename std::decay<ValueType>::type>::value
|| !(sizeof(typename std::decay<ValueType>::type) <= sizeof(decltype(m_smallSize))) >::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)))),
m_isSmall(false),
m_type(&typeid(typename std::decay<ValueType>::type))
: 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 copy(t_any);
@@ -137,20 +128,14 @@ namespace chaiscript {
template<typename ToType>
ToType &cast() const
{
if (m_isSmall && typeid(ToType) == *m_type)
if (m_data && typeid(ToType) == m_data->type())
{
return *static_cast<ToType *>(static_cast<void *>(m_smallSize.data()));
} else if (!m_isSmall && m_data && typeid(ToType) == *m_type) {
return *static_cast<ToType *>(m_data->data());
} else {
throw chaiscript::detail::exception::bad_any_cast();
}
}
const std::type_info &type() const
{
return *m_type;
}
~Any()
{
@@ -159,31 +144,25 @@ namespace chaiscript {
// modifiers
Any & swap(Any &t_other)
{
std::swap(t_other.m_smallSize, m_smallSize);
std::swap(t_other.m_isSmall, m_isSmall);
std::swap(t_other.m_data, m_data);
std::swap(t_other.m_type, m_type);
return *this;
}
// queries
bool empty() const
{
return !bool(m_data) && !m_isSmall;
return !bool(m_data);
}
void *data() const
const std::type_info & type() const
{
if (m_isSmall)
if (m_data)
{
return static_cast<void *>(m_smallSize.data());
} else if (m_data) {
return m_data->data();
return m_data->type();
} else {
return nullptr;
return typeid(void);
}
}
};
}

View File

@@ -10,6 +10,7 @@
#include <string>
#include <typeinfo>
#include "../chaiscript_defines.hpp"
#include "type_info.hpp"
namespace chaiscript {
@@ -28,14 +29,14 @@ namespace chaiscript
class bad_boxed_cast : public std::bad_cast
{
public:
bad_boxed_cast(const Type_Info &t_from, const std::type_info &t_to,
bad_boxed_cast(Type_Info t_from, const std::type_info &t_to,
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
: from(t_from), to(&t_to), m_what("Cannot perform boxed_cast")
bad_boxed_cast(Type_Info t_from, const std::type_info &t_to)
: from(std::move(t_from)), to(&t_to), m_what("Cannot perform boxed_cast")
{
}

View File

@@ -18,16 +18,16 @@ namespace chaiscript
{
static std::tuple<decltype(std::placeholders::_1),decltype(std::placeholders::_2),decltype(std::placeholders::_3),decltype(std::placeholders::_4),decltype(std::placeholders::_5),decltype(std::placeholders::_6),decltype(std::placeholders::_7),decltype(std::placeholders::_8),decltype(std::placeholders::_9),decltype(std::placeholders::_10)> placeholder() {
return std::tuple<decltype(std::placeholders::_1),decltype(std::placeholders::_2),decltype(std::placeholders::_3),decltype(std::placeholders::_4),decltype(std::placeholders::_5),decltype(std::placeholders::_6),decltype(std::placeholders::_7),decltype(std::placeholders::_8),decltype(std::placeholders::_9),decltype(std::placeholders::_10)>(std::placeholders::_1,std::placeholders::_2,std::placeholders::_3,std::placeholders::_4,std::placeholders::_5,std::placeholders::_6,std::placeholders::_7,std::placeholders::_8,std::placeholders::_9,std::placeholders::_10);
};
}
};
template<int count, int maxcount, typename Sig>
struct Bind_First
{
template<typename 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..., std::get<maxcount - count>(Placeholder::placeholder()));
return Bind_First<count - 1, maxcount, Sig>::bind(std::forward<F>(f), innerparams..., std::get<maxcount - count>(Placeholder::placeholder()));
}
};
@@ -35,37 +35,42 @@ namespace chaiscript
struct Bind_First<0, maxcount, Sig>
{
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>
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>
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>
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>
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_value.hpp"
#include "dispatchkit.hpp"
#include "dynamic_cast_conversion.hpp"
#include "type_conversions.hpp"
#include "dynamic_object.hpp"
#include "operators.hpp"
#include "proxy_constructors.hpp"
@@ -156,9 +156,7 @@ namespace chaiscript
return p;
}
/**
* Specific version of shared_ptr_clone just for Proxy_Functions
*/
/// Specific version of shared_ptr_clone just for Proxy_Functions
template<typename Type>
std::shared_ptr<typename std::remove_const<Type>::type>
shared_ptr_unconst_clone(const std::shared_ptr<typename std::add_const<Type>::type> &p)
@@ -168,11 +166,9 @@ namespace chaiscript
/**
* Assignment function for shared_ptr objects, does not perform a copy of the
* object pointed to, instead maintains the shared_ptr concept.
* Similar to shared_ptr_clone. Used for Proxy_Function.
*/
/// Assignment function for shared_ptr objects, does not perform a copy of the
/// object pointed to, instead maintains the shared_ptr concept.
/// Similar to shared_ptr_clone. Used for Proxy_Function.
template<typename Type>
Boxed_Value ptr_assign(Boxed_Value lhs, const std::shared_ptr<Type> &rhs)
{
@@ -186,10 +182,8 @@ namespace chaiscript
}
}
/**
* Class consisting of only static functions. All default bootstrapping occurs
* from this class.
*/
/// Class consisting of only static functions. All default bootstrapping occurs
/// from this class.
class Bootstrap
{
private:
@@ -217,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()))
{
m->add(fun(&Boxed_Number::equals), "==");
@@ -259,11 +251,8 @@ namespace chaiscript
}
/**
* Create a bound function object. The first param is the function to bind
* the remaining parameters are the args to bind into the
* result
*/
/// Create a bound function object. The first param is the function to bind
/// the remaining parameters are the args to bind into the result
static Boxed_Value bind_function(const std::vector<Boxed_Value> &params)
{
if (params.size() < 2)
@@ -273,7 +262,7 @@ namespace chaiscript
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()))));
}
@@ -318,9 +307,7 @@ namespace chaiscript
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)
{
if (b)
@@ -350,9 +337,7 @@ namespace chaiscript
static bool has_parse_tree(const chaiscript::Const_Proxy_Function &t_pf)
{
std::shared_ptr<const chaiscript::dispatch::Dynamic_Proxy_Function> pf
= std::dynamic_pointer_cast<const chaiscript::dispatch::Dynamic_Proxy_Function>(t_pf);
if (pf)
if (auto pf = std::dynamic_pointer_cast<const chaiscript::dispatch::Dynamic_Proxy_Function>(t_pf))
{
if (pf->get_parse_tree())
{
@@ -367,9 +352,7 @@ namespace chaiscript
static chaiscript::AST_NodePtr get_parse_tree(const chaiscript::Const_Proxy_Function &t_pf)
{
std::shared_ptr<const chaiscript::dispatch::Dynamic_Proxy_Function> pf
= std::dynamic_pointer_cast<const chaiscript::dispatch::Dynamic_Proxy_Function>(t_pf);
if (pf)
if (auto pf = std::dynamic_pointer_cast<const chaiscript::dispatch::Dynamic_Proxy_Function>(t_pf))
{
if (pf->get_parse_tree())
{

View File

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

View File

@@ -14,11 +14,11 @@
#include "bad_boxed_cast.hpp"
#include "boxed_cast_helper.hpp"
#include "boxed_value.hpp"
#include "dynamic_cast_conversion.hpp"
#include "type_conversions.hpp"
#include "type_info.hpp"
namespace chaiscript {
class Dynamic_Cast_Conversions;
class Type_Conversions;
namespace detail {
namespace exception {
class bad_any_cast;
@@ -72,7 +72,7 @@ namespace chaiscript
/// assert(i == 5);
/// \endcode
template<typename Type>
typename detail::Cast_Helper<Type>::Result_Type boxed_cast(const Boxed_Value &bv, const Dynamic_Cast_Conversions *t_conversions = nullptr)
typename detail::Cast_Helper<Type>::Result_Type boxed_cast(const Boxed_Value &bv, const Type_Conversions *t_conversions = nullptr)
{
try {
return detail::Cast_Helper<Type>::cast(bv, t_conversions);
@@ -86,18 +86,18 @@ namespace chaiscript
#pragma warning(disable : 4127)
#endif
if (std::is_polymorphic<typename detail::Bare_Type<Type>::type>::value && t_conversions)
if (t_conversions && t_conversions->convertable_type<Type>())
{
try {
// std::cout << "trying an up conversion " << typeid(Type).name() << std::endl;
// We will not catch any bad_boxed_dynamic_cast that is thrown, let the user get it
// either way, we are not responsible if it doesn't work
return detail::Cast_Helper<Type>::cast(t_conversions->boxed_dynamic_cast<Type>(bv), t_conversions);
return detail::Cast_Helper<Type>::cast(t_conversions->boxed_type_conversion<Type>(bv), t_conversions);
} catch (...) {
try {
// std::cout << "trying a down conversion " << typeid(Type).name() << std::endl;
// try going the other way - down the inheritance graph
return detail::Cast_Helper<Type>::cast(t_conversions->boxed_dynamic_down_cast<Type>(bv), t_conversions);
return detail::Cast_Helper<Type>::cast(t_conversions->boxed_type_down_conversion<Type>(bv), t_conversions);
} catch (const chaiscript::detail::exception::bad_any_cast &) {
throw exception::bad_boxed_cast(bv.get_type_info(), typeid(Type));
}

View File

@@ -17,7 +17,7 @@
namespace chaiscript
{
class Dynamic_Cast_Conversions;
class Type_Conversions;
namespace detail
{
@@ -36,7 +36,7 @@ namespace chaiscript
{
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.get_type_info().bare_equal_type_info(typeid(Result)))
{
@@ -63,7 +63,7 @@ namespace chaiscript
struct Cast_Helper_Inner<const Result *>
{
typedef 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.is_ref())
{
@@ -89,7 +89,7 @@ namespace chaiscript
struct Cast_Helper_Inner<Result *>
{
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())
{
@@ -107,7 +107,7 @@ namespace chaiscript
{
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.get_type_info().is_const() && ob.get_type_info().bare_equal_type_info(typeid(Result)))
{
@@ -124,7 +124,7 @@ namespace chaiscript
{
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> >();
}
@@ -136,7 +136,7 @@ namespace chaiscript
{
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())
{
@@ -178,7 +178,7 @@ namespace chaiscript
{
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;
}
@@ -190,7 +190,7 @@ namespace chaiscript
{
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);
}
@@ -246,7 +246,7 @@ namespace chaiscript
{
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);
}

View File

@@ -19,7 +19,7 @@
#include "type_info.hpp"
namespace chaiscript {
class Dynamic_Cast_Conversions;
class Type_Conversions;
} // namespace chaiscript
namespace chaiscript
@@ -826,31 +826,25 @@ namespace chaiscript
namespace detail
{
/**
* Cast_Helper for converting from Boxed_Value to Boxed_Number
*/
/// Cast_Helper for converting from Boxed_Value to Boxed_Number
template<>
struct Cast_Helper<Boxed_Number>
{
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);
}
};
/**
* Cast_Helper for converting from Boxed_Value to Boxed_Number
*/
/// Cast_Helper for converting from Boxed_Value to Boxed_Number
template<>
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<>
struct Cast_Helper<const Boxed_Number> : Cast_Helper<Boxed_Number>
{

View File

@@ -13,6 +13,7 @@
#include <type_traits>
#include "../chaiscript_threading.hpp"
#include "../chaiscript_defines.hpp"
#include "any.hpp"
#include "type_info.hpp"
@@ -66,6 +67,7 @@ namespace chaiscript
Data &operator=(Data &&rhs) = default;
#endif
Type_Info m_type_info;
chaiscript::detail::Any m_obj;
void *m_data_ptr;
@@ -76,7 +78,7 @@ namespace chaiscript
struct Object_Data
{
static std::shared_ptr<Data> get(Boxed_Value::Void_Type, bool, bool)
static std::shared_ptr<Data> get(Boxed_Value::Void_Type)
{
return std::make_shared<Data>(
detail::Get_Type_Info<void>::get(),
@@ -87,13 +89,13 @@ namespace chaiscript
}
template<typename T>
static std::shared_ptr<Data> get(const std::shared_ptr<T> *obj, bool, bool)
static std::shared_ptr<Data> get(const std::shared_ptr<T> *obj)
{
return get(*obj);
}
template<typename T>
static std::shared_ptr<Data> get(const std::shared_ptr<T> &obj, bool, bool)
static std::shared_ptr<Data> get(const std::shared_ptr<T> &obj)
{
return std::make_shared<Data>(
detail::Get_Type_Info<T>::get(),
@@ -104,7 +106,7 @@ namespace chaiscript
}
template<typename T>
static std::shared_ptr<Data> get(std::shared_ptr<T> &&obj, bool, bool)
static std::shared_ptr<Data> get(std::shared_ptr<T> &&obj)
{
auto ptr = obj.get();
return std::make_shared<Data>(
@@ -122,7 +124,14 @@ namespace chaiscript
}
template<typename T>
static std::shared_ptr<Data> get(std::reference_wrapper<T> obj, bool, bool)
static std::shared_ptr<Data> get(const T *t)
{
return get(std::cref(*t));
}
template<typename T>
static std::shared_ptr<Data> get(std::reference_wrapper<T> obj)
{
auto p = &obj.get();
return std::make_shared<Data>(
@@ -134,57 +143,22 @@ namespace chaiscript
}
template<typename T>
static std::shared_ptr<Data> get(T t, bool t_value_type, bool t_make_const)
static std::shared_ptr<Data> get(T t)
{
typedef typename std::add_const<T>::type const_type;
if (t_make_const)
{
if (t_value_type)
{
chaiscript::detail::Any a(std::move(t));
return std::make_shared<Data>(
detail::Get_Type_Info<const_type>::get(),
std::move(a),
false,
nullptr
);
} else {
auto p = std::make_shared<const_type>(std::move(t));
auto ptr = p.get();
return std::make_shared<Data>(
detail::Get_Type_Info<const_type>::get(),
chaiscript::detail::Any(std::move(p)),
false,
ptr
);
}
} else {
if (t_value_type)
{
chaiscript::detail::Any a(std::move(t));
return std::make_shared<Data>(
detail::Get_Type_Info<T>::get(),
std::move(a),
false,
nullptr
);
} else {
auto p = std::make_shared<T>(std::move(t));
auto ptr = p.get();
return std::make_shared<Data>(
detail::Get_Type_Info<T>::get(),
chaiscript::detail::Any(std::move(p)),
false,
ptr
);
}
}
auto p = std::make_shared<T>(std::move(t));
auto ptr = p.get();
return std::make_shared<Data>(
detail::Get_Type_Info<T>::get(),
chaiscript::detail::Any(std::move(p)),
false,
ptr
);
}
static std::shared_ptr<Data> get()
{
return std::make_shared<Data>(
Type_Info(),
Type_Info(),
chaiscript::detail::Any(),
false,
nullptr
@@ -197,10 +171,9 @@ namespace chaiscript
/// Basic Boxed_Value constructor
template<typename T,
typename = typename std::enable_if<!std::is_same<Boxed_Value, typename std::decay<T>::type>::value>::type>
explicit Boxed_Value(T &&t, bool t_make_const=false, bool t_value_type = std::is_trivial<typename std::decay<T>::type>::value)
: m_data(Object_Data::get(std::forward<T>(t), t_make_const, t_value_type))
explicit Boxed_Value(T &&t)
: m_data(Object_Data::get(std::forward<T>(t)))
{
//std::cout << "typeid: " << typeid(T).name() << " is trivial " << std::is_trivial<typename std::decay<T>::type>::value << "\n";
}
/// Unknown-type constructor
@@ -273,22 +246,12 @@ namespace chaiscript
void *get_ptr() const CHAISCRIPT_NOEXCEPT
{
if (m_data->m_data_ptr)
{
return m_data->m_data_ptr;
} else {
return m_data->m_obj.data();
}
return m_data->m_data_ptr;
}
const void *get_const_ptr() const CHAISCRIPT_NOEXCEPT
{
if (m_data->m_const_data_ptr)
{
return m_data->m_const_data_ptr;
} else {
return m_data->m_obj.data();
}
return m_data->m_const_data_ptr;
}
Boxed_Value get_attr(const std::string &t_name)
@@ -349,7 +312,7 @@ namespace chaiscript
template<typename T>
Boxed_Value const_var_impl(const T &t)
{
return Boxed_Value(std::make_shared<typename std::add_const<T>::type >(t), true);
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.

View File

@@ -27,7 +27,7 @@
#include "boxed_cast.hpp"
#include "boxed_cast_helper.hpp"
#include "boxed_value.hpp"
#include "dynamic_cast_conversion.hpp"
#include "type_conversions.hpp"
#include "dynamic_object.hpp"
#include "proxy_constructors.hpp"
#include "proxy_functions.hpp"
@@ -141,7 +141,7 @@ namespace chaiscript
return *this;
}
Module &add(Dynamic_Cast_Conversion d)
Module &add(Type_Conversion d)
{
m_conversions.push_back(std::move(d));
return *this;
@@ -157,7 +157,7 @@ namespace chaiscript
{
if (!t_bv.is_const())
{
// throw chaiscript::exception::global_non_const();
throw chaiscript::exception::global_non_const();
}
m_globals.emplace_back(std::move(t_bv), std::move(t_name));
@@ -166,9 +166,9 @@ namespace chaiscript
//Add a bit of ChaiScript to eval during module implementation
Module &eval(std::string str)
Module &eval(const std::string &str)
{
m_evals.push_back(std::move(str));
m_evals.push_back(str);
return *this;
}
@@ -197,7 +197,7 @@ namespace chaiscript
std::vector<std::pair<Proxy_Function, std::string> > m_funcs;
std::vector<std::pair<Boxed_Value, std::string> > m_globals;
std::vector<std::string> m_evals;
std::vector<Dynamic_Cast_Conversion> m_conversions;
std::vector<Type_Conversion> m_conversions;
template<typename T, typename InItr>
static void apply(InItr begin, const InItr end, T &t)
@@ -257,7 +257,7 @@ namespace chaiscript
{
public:
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(std::move(t_funcs))
{
}
@@ -265,7 +265,7 @@ namespace chaiscript
virtual bool operator==(const dispatch::Proxy_Function_Base &rhs) const CHAISCRIPT_OVERRIDE
{
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;
} catch (const std::bad_cast &) {
return false;
@@ -280,15 +280,15 @@ namespace chaiscript
}
virtual int get_arity() const CHAISCRIPT_OVERRIDE
static int calculate_arity(const std::vector<Proxy_Function> &t_funcs)
{
if (m_funcs.empty()) {
if (t_funcs.empty()) {
return -1;
}
const int arity = m_funcs.front()->get_arity();
const auto arity = t_funcs.front()->get_arity();
for (const auto &func : m_funcs)
for (const auto &func : t_funcs)
{
if (arity != func->get_arity())
{
@@ -300,17 +300,10 @@ namespace chaiscript
return arity;
}
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
{
for (const auto &func : m_funcs)
{
if (func->call_match(vals, t_conversions))
{
return true;
}
}
return false;
return std::any_of(m_funcs.cbegin(), m_funcs.cend(),
[&vals, &t_conversions](const Proxy_Function &f){ return f->call_match(vals, t_conversions); });
}
virtual std::string annotation() const CHAISCRIPT_OVERRIDE
@@ -319,9 +312,9 @@ namespace chaiscript
}
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:
@@ -329,10 +322,8 @@ namespace chaiscript
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.begin();
const function_vec::const_iterator end = t_funcs.end();
auto begin = t_funcs.cbegin();
const auto &end = t_funcs.cend();
if (begin != end)
{
@@ -380,10 +371,8 @@ namespace chaiscript
namespace detail
{
/**
* Main class for the dispatchkit. Handles management
* of the object stack, functions and registered types.
*/
/// Main class for the dispatchkit. Handles management
/// of the object stack, functions and registered types.
class Dispatch_Engine
{
public:
@@ -420,7 +409,7 @@ namespace chaiscript
}
/// Add a new conversion for upcasting to a base class
void add(const Dynamic_Cast_Conversion &d)
void add(const Type_Conversion &d)
{
m_conversions.add_conversion(d);
}
@@ -437,12 +426,12 @@ namespace chaiscript
void add(const Boxed_Value &obj, const std::string &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)
{
const auto itr = stack[i].find(name);
if (itr != stack[i].end())
auto itr = stack_elem->find(name);
if (itr != stack_elem->end())
{
itr->second = std::move(obj);
return;
@@ -456,15 +445,15 @@ namespace chaiscript
/// Adds a named object to the current scope
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);
const Scope &scope = stack.back();
auto &scope = stack.back();
if (scope.find(name) != scope.end())
{
throw chaiscript::exception::name_conflict_error(name);
} else {
stack.back().insert(std::make_pair(name, std::move(obj)));
scope.insert(std::make_pair(name, obj));
}
}
@@ -474,7 +463,7 @@ namespace chaiscript
validate_object_name(name);
if (!obj.is_const())
{
// throw chaiscript::exception::global_non_const();
throw chaiscript::exception::global_non_const();
}
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l(m_global_object_mutex);
@@ -546,13 +535,13 @@ namespace chaiscript
return m_place_holder;
}
StackData &stack = get_stack_data();
auto &stack = get_stack_data();
// 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)
{
const auto stackitr = stack[i].find(name);
if (stackitr != stack[i].end())
const auto stackitr = stack_elem->find(name);
if (stackitr != stack_elem->end())
{
return stackitr->second;
}
@@ -672,7 +661,7 @@ namespace chaiscript
/// the current scope.
std::map<std::string, Boxed_Value> get_parent_locals() const
{
StackData &stack = get_stack_data();
auto &stack = get_stack_data();
if (stack.size() > 1)
{
return stack[1];
@@ -684,8 +673,8 @@ namespace chaiscript
/// \returns All values in the local thread state, added through the add() function
std::map<std::string, Boxed_Value> get_locals() const
{
StackData &stack = get_stack_data();
Scope &scope = stack.front();
auto &stack = get_stack_data();
auto &scope = stack.front();
return scope;
}
@@ -696,8 +685,8 @@ namespace chaiscript
/// 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)
{
StackData &stack = get_stack_data();
Scope &scope = stack.front();
auto &stack = get_stack_data();
auto &scope = stack.front();
scope = t_locals;
}
@@ -779,16 +768,14 @@ namespace chaiscript
m_state.m_reserved_words.insert(name);
}
const Dynamic_Cast_Conversions &conversions() const
const Type_Conversions &conversions() const
{
return m_conversions;
}
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(functions.begin(), functions.end(), params, m_conversions);
return dispatch::dispatch(get_function(t_name), params, m_conversions);
}
Boxed_Value call_function(const std::string &t_name) const
@@ -850,7 +837,7 @@ namespace chaiscript
/// (the function) with the remaining parameters as its arguments.
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);
}
@@ -928,6 +915,22 @@ namespace chaiscript
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)
{
Stack_Holder &s = *m_stack_holder;
@@ -936,7 +939,15 @@ namespace chaiscript
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;
save_function_params(m_conversions.take_saves());
}
void pop_function_call()
@@ -951,6 +962,7 @@ namespace chaiscript
/// \todo Critical: this needs to be smarter, memory can expand quickly
/// in tight loops involving function calls
s.call_params.clear();
m_conversions.enable_conversion_saves(false);
}
}
@@ -984,17 +996,17 @@ namespace chaiscript
static bool function_less_than(const Proxy_Function &lhs, const Proxy_Function &rhs)
{
const std::vector<Type_Info> &lhsparamtypes = lhs->get_param_types();
const std::vector<Type_Info> &rhsparamtypes = rhs->get_param_types();
const auto &lhsparamtypes = lhs->get_param_types();
const auto &rhsparamtypes = rhs->get_param_types();
const size_t lhssize = lhsparamtypes.size();
const size_t rhssize = rhsparamtypes.size();
const auto lhssize = lhsparamtypes.size();
const auto rhssize = rhsparamtypes.size();
const Type_Info boxed_type = user_type<Boxed_Value>();
const Type_Info boxed_pod_type = user_type<Boxed_Number>();
CHAISCRIPT_CONSTEXPR auto boxed_type = user_type<Boxed_Value>();
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));
std::shared_ptr<const dispatch::Dynamic_Proxy_Function> dynamic_rhs(std::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(rhs));
auto dynamic_lhs(std::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(lhs));
auto dynamic_rhs(std::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(rhs));
if (dynamic_lhs && dynamic_rhs)
{
@@ -1149,7 +1161,7 @@ namespace chaiscript
int call_depth;
};
Dynamic_Cast_Conversions m_conversions;
Type_Conversions m_conversions;
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"
namespace chaiscript {
class Dynamic_Cast_Conversions;
class Type_Conversions;
namespace dispatch {
class Proxy_Function_Base;
} // namespace dispatch
@@ -64,18 +64,16 @@ namespace chaiscript
namespace detail
{
/**
* A Proxy_Function implementation designed for calling a function
* that is automatically guarded based on the first param based on the
* param's type name
*/
/// A Proxy_Function implementation designed for calling a function
/// that is automatically guarded based on the first param based on the
/// param's type name
class Dynamic_Object_Function : public Proxy_Function_Base
{
public:
Dynamic_Object_Function(
std::string t_type_name,
const Proxy_Function &t_func)
: Proxy_Function_Base(t_func->get_param_types()),
: 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>())
{
assert( (t_func->get_arity() > 0 || t_func->get_arity() < 0)
@@ -86,7 +84,7 @@ namespace chaiscript
std::string t_type_name,
const Proxy_Function &t_func,
const Type_Info &t_ti)
: Proxy_Function_Base(build_param_types(t_func->get_param_types(), t_ti)),
: 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>())
{
assert( (t_func->get_arity() > 0 || t_func->get_arity() < 0)
@@ -96,11 +94,11 @@ namespace chaiscript
virtual ~Dynamic_Object_Function() {}
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
{
const Dynamic_Object_Function *df = dynamic_cast<const Dynamic_Object_Function *>(&f);
if (df)
if (const auto *df = dynamic_cast<const Dynamic_Object_Function *>(&f))
{
return df->m_type_name == m_type_name && (*df->m_func) == (*m_func);
} else {
@@ -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))
{
@@ -123,12 +121,6 @@ namespace chaiscript
return {m_func};
}
virtual int get_arity() const CHAISCRIPT_OVERRIDE
{
return m_func->get_arity();
}
virtual std::string annotation() const CHAISCRIPT_OVERRIDE
{
return m_func->annotation();
@@ -136,7 +128,7 @@ namespace chaiscript
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))
{
@@ -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);
}
@@ -164,7 +156,7 @@ namespace chaiscript
}
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))
{
@@ -186,7 +178,7 @@ namespace chaiscript
}
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)
{
@@ -198,7 +190,7 @@ namespace chaiscript
std::string m_type_name;
Proxy_Function m_func;
std::shared_ptr<Type_Info> m_ti;
std::unique_ptr<Type_Info> m_ti;
const Type_Info m_doti;
@@ -217,7 +209,7 @@ namespace chaiscript
Dynamic_Object_Constructor(
std::string t_type_name,
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)
{
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;
new_vals.push_back(Boxed_Value(Dynamic_Object(m_type_name)));
std::vector<Boxed_Value> new_vals{Boxed_Value(Dynamic_Object(m_type_name))};
new_vals.insert(new_vals.end(), vals.begin(), vals.end());
return m_func->call_match(new_vals, t_conversions);
}
virtual int get_arity() const CHAISCRIPT_OVERRIDE
{
// "this" is not considered part of the arity
return m_func->get_arity() - 1;
}
virtual std::string annotation() const CHAISCRIPT_OVERRIDE
{
return m_func->annotation();
}
protected:
virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
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;
chaiscript::Boxed_Value bv = var(Dynamic_Object(m_type_name));
new_params.push_back(bv);
auto bv = var(Dynamic_Object(m_type_name));
std::vector<Boxed_Value> new_params{bv};
new_params.insert(new_params.end(), params.begin(), params.end());
(*m_func)(new_params, t_conversions);

View File

@@ -18,7 +18,7 @@
namespace chaiscript {
class Boxed_Value;
class Dynamic_Cast_Conversions;
class Type_Conversions;
namespace detail {
template <typename T> struct Cast_Helper;
} // namespace detail
@@ -28,66 +28,56 @@ namespace chaiscript
{
namespace dispatch
{
/**
* Build a function caller that knows how to dispatch on a set of functions
* example:
* std::function<void (int)> f =
* build_function_caller(dispatchkit.get_function("print"));
* \returns A std::function object for dispatching
* \param[in] funcs the set of functions to dispatch on.
*/
/// Build a function caller that knows how to dispatch on a set of functions
/// example:
/// std::function<void (int)> f =
/// build_function_caller(dispatchkit.get_function("print"));
/// \returns A std::function object for dispatching
/// \param[in] funcs the set of functions to dispatch on.
template<typename FunctionType>
std::function<FunctionType>
functor(const std::vector<Const_Proxy_Function> &funcs, const Dynamic_Cast_Conversions *t_conversions)
functor(const std::vector<Const_Proxy_Function> &funcs, const Type_Conversions *t_conversions)
{
FunctionType *p=nullptr;
return detail::build_function_caller_helper(p, funcs, t_conversions);
}
/**
* Build a function caller for a particular Proxy_Function object
* useful in the case that a function is being pass out from scripting back
* into code
* example:
* void my_function(Proxy_Function f)
* {
* std::function<void (int)> local_f =
* build_function_caller(f);
* }
* \returns A std::function object for dispatching
* \param[in] func A function to execute.
*/
/// Build a function caller for a particular Proxy_Function object
/// useful in the case that a function is being pass out from scripting back
/// into code
/// example:
/// void my_function(Proxy_Function f)
/// {
/// std::function<void (int)> local_f =
/// build_function_caller(f);
/// }
/// \returns A std::function object for dispatching
/// \param[in] func A function to execute.
template<typename FunctionType>
std::function<FunctionType>
functor(Const_Proxy_Function func, const Dynamic_Cast_Conversions *t_conversions)
functor(Const_Proxy_Function func, const Type_Conversions *t_conversions)
{
std::vector<Const_Proxy_Function> funcs;
funcs.push_back(func);
return functor<FunctionType>(funcs, t_conversions);
return functor<FunctionType>(std::vector<Const_Proxy_Function>({func}), t_conversions);
}
/**
* Helper for automatically unboxing a Boxed_Value that contains a function object
* and creating a typesafe C++ function caller from it.
*/
/// Helper for automatically unboxing a Boxed_Value that contains a function object
/// and creating a typesafe C++ function caller from it.
template<typename FunctionType>
std::function<FunctionType>
functor(const Boxed_Value &bv, const Dynamic_Cast_Conversions *t_conversions)
functor(const Boxed_Value &bv, const Type_Conversions *t_conversions)
{
return functor<FunctionType>(boxed_cast<Const_Proxy_Function >(bv, t_conversions), t_conversions);
}
}
namespace detail{
/**
* Cast helper to handle automatic casting to const std::function &
*/
/// Cast helper to handle automatic casting to const std::function &
template<typename Signature>
struct Cast_Helper<const std::function<Signature> &>
{
typedef std::function<Signature> Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *t_conversions)
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *t_conversions)
{
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>
struct Cast_Helper<std::function<Signature> >
{
typedef std::function<Signature> Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *t_conversions)
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *t_conversions)
{
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>
struct Cast_Helper<const std::function<Signature> >
{
typedef std::function<Signature> Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *t_conversions)
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *t_conversions)
{
if (ob.get_type_info().bare_equal(user_type<Const_Proxy_Function>()))
{

View File

@@ -17,7 +17,7 @@
#include "boxed_cast.hpp"
#include "boxed_number.hpp"
#include "boxed_value.hpp"
#include "dynamic_cast_conversion.hpp"
#include "type_conversions.hpp"
#include "proxy_functions.hpp"
namespace chaiscript
@@ -26,15 +26,13 @@ namespace chaiscript
{
namespace detail
{
/**
* Internal helper class for handling the return
* value of a build_function_caller
*/
/// Internal helper class for handling the return
/// value of a build_function_caller
template<typename Ret, bool is_arithmetic>
struct Function_Caller_Ret
{
static Ret call(const std::vector<Const_Proxy_Function> &t_funcs,
const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions)
const std::vector<Boxed_Value> &params, const Type_Conversions &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>
{
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>();
}
@@ -61,7 +59,7 @@ namespace chaiscript
struct Function_Caller_Ret<void, false>
{
static void call(const std::vector<Const_Proxy_Function> &t_funcs,
const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions)
const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions)
{
dispatch::dispatch(t_funcs, params, t_conversions);
}
@@ -73,7 +71,7 @@ namespace chaiscript
template<typename Ret, typename ... Param>
struct Build_Function_Caller_Helper
{
Build_Function_Caller_Helper(std::vector<Const_Proxy_Function> t_funcs, const Dynamic_Cast_Conversions &t_conversions)
Build_Function_Caller_Helper(std::vector<Const_Proxy_Function> t_funcs, const Type_Conversions &t_conversions)
: m_funcs(std::move(t_funcs)),
m_conversions(t_conversions)
{
@@ -90,13 +88,13 @@ namespace chaiscript
}
std::vector<Const_Proxy_Function> m_funcs;
Dynamic_Cast_Conversions m_conversions;
Type_Conversions m_conversions;
};
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)
{
@@ -112,7 +110,7 @@ namespace chaiscript
// 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>
struct Handle_Return<std::shared_ptr<Ret> &>
{

View File

@@ -26,7 +26,7 @@
#include "type_info.hpp"
namespace chaiscript {
class Dynamic_Cast_Conversions;
class Type_Conversions;
namespace exception {
class bad_boxed_cast;
struct arity_error;
@@ -55,7 +55,7 @@ namespace chaiscript
public:
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);
return bv;
@@ -68,7 +68,7 @@ namespace chaiscript
const std::vector<Type_Info> &get_param_types() const { return m_types; }
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
{
@@ -82,15 +82,13 @@ namespace chaiscript
//! Return true if the function is a possible match
//! 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 (arity < 0)
if (m_arity < 0)
{
return true;
} else if (size_t(arity) == vals.size()) {
if (arity == 0)
} else if (size_t(m_arity) == vals.size()) {
if (m_arity == 0)
{
return true;
} else {
@@ -102,11 +100,14 @@ namespace chaiscript
}
/// \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;
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()
|| ti.bare_equal(user_type<Boxed_Value>())
@@ -114,7 +115,7 @@ namespace chaiscript
&& (ti.bare_equal(user_type<Boxed_Number>())
|| ti.bare_equal(bv.get_type_info())
|| 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:
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)
: m_types(std::move(t_types)), m_has_arithmetic_param(false)
Proxy_Function_Base(std::vector<Type_Info> t_types, int t_arity)
: 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)
{
@@ -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();
@@ -175,7 +176,7 @@ namespace chaiscript
std::vector<Type_Info> m_types;
bool m_has_arithmetic_param;
int m_arity;
};
}
@@ -216,7 +217,7 @@ namespace chaiscript
AST_NodePtr t_parsenode = AST_NodePtr(),
std::string t_description = "",
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))
{
}
@@ -233,16 +234,12 @@ namespace chaiscript
&& !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))
&& test_guard(vals, t_conversions);
}
virtual int get_arity() const CHAISCRIPT_OVERRIDE
{
return m_arity;
}
Proxy_Function get_guard() const
{
@@ -260,7 +257,7 @@ namespace chaiscript
}
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))
{
@@ -278,7 +275,7 @@ namespace chaiscript
}
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)
{
@@ -338,8 +335,8 @@ namespace chaiscript
public:
Bound_Function(const Const_Proxy_Function &t_f,
const std::vector<Boxed_Value> &t_args)
: Proxy_Function_Base(build_param_type_info(t_f, t_args)),
m_f(t_f), m_args(t_args), m_arity(t_f->get_arity()<0?-1:static_cast<int>(get_param_types().size())-1)
: 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)
{
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 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);
}
@@ -395,11 +392,6 @@ namespace chaiscript
return args;
}
virtual int get_arity() const CHAISCRIPT_OVERRIDE
{
return m_arity;
}
virtual std::string annotation() const CHAISCRIPT_OVERRIDE
{
return "Bound: " + m_f->annotation();
@@ -429,7 +421,7 @@ namespace chaiscript
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);
}
@@ -437,30 +429,24 @@ namespace chaiscript
private:
Const_Proxy_Function m_f;
std::vector<Boxed_Value> m_args;
int m_arity;
};
class Proxy_Function_Impl_Base : public Proxy_Function_Base
{
public:
Proxy_Function_Impl_Base(std::vector<Type_Info> t_types)
: Proxy_Function_Base(std::move(t_types))
Proxy_Function_Impl_Base(const std::vector<Type_Info> &t_types)
: Proxy_Function_Base(t_types, static_cast<int>(t_types.size()) - 1)
{
}
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
{
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())
{
@@ -470,7 +456,7 @@ namespace chaiscript
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 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);
}
@@ -506,7 +492,7 @@ namespace chaiscript
}
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);
}
@@ -524,8 +510,8 @@ namespace chaiscript
{
public:
Attribute_Access(T Class::* t_attr)
: Proxy_Function_Base(param_types()),
m_attr(t_attr)
: Proxy_Function_Base(param_types(), 1),
m_attr(t_attr)
{
}
@@ -543,13 +529,7 @@ namespace chaiscript
}
}
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
virtual bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions &) const CHAISCRIPT_OVERRIDE
{
if (vals.size() != 1)
{
@@ -565,7 +545,7 @@ namespace chaiscript
}
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)
{
@@ -622,7 +602,7 @@ namespace chaiscript
{
template<typename FuncType>
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()))
{
@@ -650,7 +630,7 @@ namespace chaiscript
template<typename InItr>
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);
@@ -712,17 +692,42 @@ namespace chaiscript
* 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 InItr>
Boxed_Value dispatch(InItr begin, const InItr &end,
const std::vector<Boxed_Value> &plist, const Dynamic_Cast_Conversions &t_conversions)
template<typename Funcs>
Boxed_Value dispatch(const Funcs &funcs,
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 {
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 &) {
//parameter failed to cast, try again
@@ -732,22 +737,9 @@ namespace chaiscript
//guard failed to allow the function to execute,
//try again
}
++begin;
}
return detail::dispatch_with_conversions(orig, end, 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);
return detail::dispatch_with_conversions(funcs.cbegin(), funcs.cend(), plist, t_conversions);
}
}
}

View File

@@ -20,7 +20,7 @@
#include "type_info.hpp"
namespace chaiscript {
class Dynamic_Cast_Conversions;
class Type_Conversions;
namespace exception {
class bad_boxed_cast;
} // namespace exception
@@ -72,7 +72,7 @@ namespace chaiscript
template<typename Param, typename ... Rest>
struct Try_Cast<Param, Rest...>
{
static void do_try(const std::vector<Boxed_Value> &params, int generation, const Dynamic_Cast_Conversions &t_conversions)
static void do_try(const std::vector<Boxed_Value> &params, int generation, const Type_Conversions &t_conversions)
{
boxed_cast<Param>(params[generation], &t_conversions);
Try_Cast<Rest...>::do_try(params, generation+1, t_conversions);
@@ -83,7 +83,7 @@ namespace chaiscript
template<>
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 &)
{
}
};
@@ -96,7 +96,7 @@ namespace chaiscript
*/
template<typename Ret, typename ... Params>
bool compare_types_cast(Ret (*)(Params...),
const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions)
const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions)
{
try {
Try_Cast<Params...>::do_try(params, 0, t_conversions);
@@ -113,7 +113,7 @@ namespace chaiscript
template<typename ... InnerParams>
static Ret do_call(const std::function<Ret (Params...)> &f,
const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions, InnerParams &&... innerparams)
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]);
}
@@ -128,7 +128,7 @@ namespace chaiscript
#endif
template<typename ... InnerParams>
static Ret do_call(const std::function<Ret (Params...)> &f,
const std::vector<Boxed_Value> &, const Dynamic_Cast_Conversions &t_conversions, InnerParams &&... innerparams)
const std::vector<Boxed_Value> &, const Type_Conversions &t_conversions, InnerParams &&... innerparams)
{
return f(boxed_cast<Params>(std::forward<InnerParams>(innerparams), &t_conversions)...);
}
@@ -145,7 +145,7 @@ namespace chaiscript
*/
template<typename Ret, typename ... Params>
Ret call_func(const std::function<Ret (Params...)> &f,
const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions)
const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions)
{
if (params.size() == sizeof...(Params))
{
@@ -171,7 +171,7 @@ namespace chaiscript
struct Do_Call
{
template<typename Fun>
static Boxed_Value go(const std::function<Fun> &fun, const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions)
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));
}
@@ -181,7 +181,7 @@ namespace chaiscript
struct Do_Call<void>
{
template<typename Fun>
static Boxed_Value go(const std::function<Fun> &fun, const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions)
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);
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

@@ -111,6 +111,11 @@ namespace chaiscript
}
}
CHAISCRIPT_CONSTEXPR const std::type_info *bare_type_info() const
{
return m_bare_type_info;
}
private:
const std::type_info *m_type_info;
const std::type_info *m_bare_type_info;

View File

@@ -549,6 +549,11 @@ namespace chaiscript
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:

View File

@@ -26,7 +26,7 @@
#include "../dispatchkit/boxed_cast_helper.hpp"
#include "../dispatchkit/boxed_value.hpp"
#include "../dispatchkit/dispatchkit.hpp"
#include "../dispatchkit/dynamic_cast_conversion.hpp"
#include "../dispatchkit/type_conversions.hpp"
#include "../dispatchkit/proxy_functions.hpp"
#include "chaiscript_common.hpp"
@@ -353,6 +353,13 @@ namespace chaiscript
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 void (ChaiScript::*load_mod_2)(const std::string&, const std::string&);
@@ -679,7 +686,7 @@ namespace chaiscript
/// chaiscript::ChaiScript chai;
/// chai.add(chaiscript::base_class<std::runtime_error, chaiscript::dispatch_error>());
/// \endcode
ChaiScript &add(const Dynamic_Cast_Conversion &d)
ChaiScript &add(const Type_Conversion &d)
{
m_engine.add(d);
return *this;

View File

@@ -292,6 +292,7 @@ namespace chaiscript
virtual ~Inplace_Fun_Call_AST_Node() {}
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE{
std::vector<Boxed_Value> params;
chaiscript::eval::detail::Function_Push_Pop fpp(t_ss);
if ((this->children.size() > 1) && (this->children[1]->identifier == AST_Node_Type::Arg_List)) {
for (const auto &child : this->children[1]->children) {
@@ -595,10 +596,10 @@ namespace chaiscript
virtual ~Dot_Access_AST_Node() {}
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE{
Boxed_Value retval = this->children[0]->eval(t_ss);
chaiscript::eval::detail::Function_Push_Pop fpp(t_ss);
if (this->children.size() > 1) {
for (size_t i = 2; i < this->children.size(); i+=2) {
chaiscript::eval::detail::Function_Push_Pop fpp(t_ss);
std::vector<Boxed_Value> params{retval};
if (this->children[i]->children.size() > 1) {

View File

@@ -266,16 +266,27 @@ namespace chaiscript
return false;
}
/// Skips ChaiScript whitespace, which means space and tab, but not cr/lf
/// jespada: Modified SkipWS to skip optionally CR ('\n')
bool SkipWS(const bool skip_cr=false) {
/// jespada: Modified SkipWS to skip optionally CR ('\n') and/or LF+CR ("\r\n")
bool SkipWS(bool skip_cr=false) {
bool retval = false;
while (has_more_input()) {
if ( char_in_alphabet(*m_input_pos,detail::white_alphabet) || (skip_cr && (*m_input_pos == '\n'))) {
if(*m_input_pos == '\n') {
auto end_line = (*m_input_pos != 0) && ((*m_input_pos == '\n') || (*m_input_pos == '\r' && *(m_input_pos+1) == '\n'));
if ( char_in_alphabet(*m_input_pos,detail::white_alphabet) || (skip_cr && end_line)) {
if(end_line) {
m_col = 1;
++m_line;
} else {
if(*(m_input_pos) == '\r') {
// discards lf
++m_input_pos;
}
}
else {
++m_col;
}
++m_input_pos;
@@ -284,14 +295,14 @@ namespace chaiscript
}
else if (SkipComment()) {
retval = true;
}
else {
} else {
break;
}
}
return retval;
}
/// Reads a floating point value from input, without skipping initial whitespace
bool Float_() {
if (has_more_input() && char_in_alphabet(*m_input_pos,detail::float_alphabet) ) {

View File

@@ -1,6 +1,15 @@
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
* Decreased compile time and build size

View File

@@ -8,7 +8,7 @@ class BaseClass
{
}
virtual ~BaseClass() = default;
virtual ~BaseClass() {}
virtual std::string doSomething(float, double) const = 0;
@@ -42,14 +42,14 @@ class ChaiScriptDerived : public BaseClass
tie(t_funcs.at(1), m_validateValueImpl);
}
std::string doSomething(float f, double d) const override
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) override
bool validateValue(const std::string &t_val) CHAISCRIPT_OVERRIDE
{
assert(m_validateValueImpl);
return m_validateValueImpl(*this, t_val);

View File

@@ -2,6 +2,8 @@
#include <chaiscript/chaiscript.hpp>
#include <string>
class TestBaseType
{
public:
@@ -22,6 +24,30 @@ class 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
{
TestValue1 = 1
@@ -95,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<TestDerivedType>(), "TestDerivedType");
m->add(chaiscript::user_type<TestMoreDerivedType>(), "TestMoreDerivedType");
m->add(chaiscript::user_type<Type2>(), "Type2");
m->add(chaiscript::constructor<TestBaseType ()>(), "TestBaseType");
// m->add(chaiscript::constructor<TestBaseType (int)>(), "TestBaseType");
@@ -135,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(&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;
}

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");