Compare commits

...

6 Commits

14 changed files with 705 additions and 545 deletions

View File

@@ -19,5 +19,7 @@ if (Boost_FOUND)
#add_executable(dispatchkit_test contrib/test/dispatchkit_test.cpp)
target_link_libraries(chaiscript_eval ${Boost_LIBRARIES})
install(TARGETS chaiscript_eval DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/bin)
else(Boost_FOUND)
message(FATAL_ERROR "Can not find Boost")
endif(Boost_FOUND)

View File

@@ -635,7 +635,7 @@ namespace chaiscript
Proxy_Function f = boxed_cast<Proxy_Function >(params[0]);
return Boxed_Value(f->types_match(std::vector<Boxed_Value>(params.begin() + 1, params.end())));
return Boxed_Value(f->call_match(std::vector<Boxed_Value>(params.begin() + 1, params.end())));
}
static boost::shared_ptr<Dispatch_Engine> bootstrap2(boost::shared_ptr<Dispatch_Engine> e = boost::shared_ptr<Dispatch_Engine> (new Dispatch_Engine()))

View File

@@ -97,11 +97,6 @@ namespace chaiscript
return *this;
}
static bool get_false()
{
return false;
}
Type_Info m_type_info;
boost::any m_obj;
bool m_is_ref;
@@ -116,10 +111,15 @@ namespace chaiscript
*/
struct Object_Cache
{
Object_Cache()
: m_cullcount(0)
{
}
boost::shared_ptr<Data> get(Boxed_Value::Void_Type)
{
return boost::shared_ptr<Data> (new Data(
Get_Type_Info<void>::get(),
detail::Get_Type_Info<void>::get(),
boost::any(),
false)
);
@@ -135,7 +135,7 @@ namespace chaiscript
boost::shared_ptr<Data> get(const boost::shared_ptr<T> &obj)
{
boost::shared_ptr<Data> data(new Data(
Get_Type_Info<T>::get(),
detail::Get_Type_Info<T>::get(),
boost::any(obj),
false,
boost::shared_ptr<Data::Shared_Ptr_Proxy>(new Data::Shared_Ptr_Proxy_Impl<T>()))
@@ -164,7 +164,7 @@ namespace chaiscript
boost::shared_ptr<Data> get(boost::reference_wrapper<T> obj)
{
boost::shared_ptr<Data> data(new Data(
Get_Type_Info<T>::get(),
detail::Get_Type_Info<T>::get(),
boost::any(obj),
true)
);
@@ -192,7 +192,7 @@ namespace chaiscript
boost::shared_ptr<Data> get(const T& t)
{
boost::shared_ptr<Data> data(new Data(
Get_Type_Info<T>::get(),
detail::Get_Type_Info<T>::get(),
boost::any(boost::shared_ptr<T>(new T(t))),
false,
boost::shared_ptr<Data::Shared_Ptr_Proxy>(new Data::Shared_Ptr_Proxy_Impl<T>()))
@@ -219,6 +219,12 @@ namespace chaiscript
*/
void cull()
{
++m_cullcount;
if (m_cullcount % 10 != 0)
{
return;
}
std::map<const void *, Data >::iterator itr = m_ptrs.begin();
while (itr != m_ptrs.end())
@@ -235,6 +241,7 @@ namespace chaiscript
}
std::map<const void *, Data > m_ptrs;
int m_cullcount;
};
public:
@@ -324,175 +331,178 @@ namespace chaiscript
};
// Cast_Helper helper classes
namespace detail
{
// Cast_Helper helper classes
/**
* Generic Cast_Helper, for casting to any type
*/
template<typename Result>
struct Cast_Helper
{
typedef typename boost::reference_wrapper<typename boost::add_const<Result>::type > Result_Type;
static Result_Type cast(const Boxed_Value &ob)
/**
* Generic Cast_Helper, for casting to any type
*/
template<typename Result>
struct Cast_Helper
{
if (ob.is_ref())
typedef typename boost::reference_wrapper<typename boost::add_const<Result>::type > Result_Type;
static Result_Type cast(const Boxed_Value &ob)
{
if (!ob.get_type_info().m_is_const)
if (ob.is_ref())
{
return boost::cref((boost::any_cast<boost::reference_wrapper<Result> >(ob.get())).get());
if (!ob.get_type_info().m_is_const)
{
return boost::cref((boost::any_cast<boost::reference_wrapper<Result> >(ob.get())).get());
} else {
return boost::any_cast<boost::reference_wrapper<const Result> >(ob.get());
}
} else {
return boost::any_cast<boost::reference_wrapper<const Result> >(ob.get());
return boost::cref(*(boost::any_cast<boost::shared_ptr<Result> >(ob.get())));
}
} else {
return boost::cref(*(boost::any_cast<boost::shared_ptr<Result> >(ob.get())));
}
}
};
};
/**
* Cast_Helper for casting to a const & type
*/
template<typename Result>
struct Cast_Helper<const Result &>
{
typedef typename boost::reference_wrapper<typename boost::add_const<Result>::type > Result_Type;
static Result_Type cast(const Boxed_Value &ob)
/**
* Cast_Helper for casting to a const & type
*/
template<typename Result>
struct Cast_Helper<const Result &>
{
if (ob.is_ref())
typedef typename boost::reference_wrapper<typename boost::add_const<Result>::type > Result_Type;
static Result_Type cast(const Boxed_Value &ob)
{
if (!ob.get_type_info().m_is_const)
if (ob.is_ref())
{
return boost::cref((boost::any_cast<boost::reference_wrapper<Result> >(ob.get())).get());
if (!ob.get_type_info().m_is_const)
{
return boost::cref((boost::any_cast<boost::reference_wrapper<Result> >(ob.get())).get());
} else {
return boost::any_cast<boost::reference_wrapper<const Result> >(ob.get());
}
} else {
return boost::any_cast<boost::reference_wrapper<const Result> >(ob.get());
return boost::cref(*(boost::any_cast<boost::shared_ptr<Result> >(ob.get())));
}
} else {
return boost::cref(*(boost::any_cast<boost::shared_ptr<Result> >(ob.get())));
}
}
};
};
/**
* Cast_Helper for casting to a const * type
*/
template<typename Result>
struct Cast_Helper<const Result *>
{
typedef const Result * Result_Type;
static Result_Type cast(const Boxed_Value &ob)
/**
* Cast_Helper for casting to a const * type
*/
template<typename Result>
struct Cast_Helper<const Result *>
{
if (ob.is_ref())
typedef const Result * Result_Type;
static Result_Type cast(const Boxed_Value &ob)
{
if (!ob.get_type_info().m_is_const)
if (ob.is_ref())
{
if (!ob.get_type_info().m_is_const)
{
return (boost::any_cast<boost::reference_wrapper<Result> >(ob.get())).get_pointer();
} else {
return (boost::any_cast<boost::reference_wrapper<const Result> >(ob.get())).get_pointer();
}
} else {
return (boost::any_cast<boost::shared_ptr<Result> >(ob.get())).get();
}
}
};
/**
* Cast_Helper for casting to a * type
*/
template<typename Result>
struct Cast_Helper<Result *>
{
typedef Result * Result_Type;
static Result_Type cast(const Boxed_Value &ob)
{
if (ob.is_ref())
{
return (boost::any_cast<boost::reference_wrapper<Result> >(ob.get())).get_pointer();
} else {
return (boost::any_cast<boost::reference_wrapper<const Result> >(ob.get())).get_pointer();
return (boost::any_cast<boost::shared_ptr<Result> >(ob.get())).get();
}
} else {
return (boost::any_cast<boost::shared_ptr<Result> >(ob.get())).get();
}
}
};
};
/**
* Cast_Helper for casting to a * type
*/
template<typename Result>
struct Cast_Helper<Result *>
{
typedef Result * Result_Type;
static Result_Type cast(const Boxed_Value &ob)
/**
* Cast_Helper for casting to a & type
*/
template<typename Result>
struct Cast_Helper<Result &>
{
if (ob.is_ref())
typedef typename boost::reference_wrapper<Result> Result_Type;
static Result_Type cast(const Boxed_Value &ob)
{
return (boost::any_cast<boost::reference_wrapper<Result> >(ob.get())).get_pointer();
} else {
return (boost::any_cast<boost::shared_ptr<Result> >(ob.get())).get();
if (ob.is_ref())
{
return boost::any_cast<boost::reference_wrapper<Result> >(ob.get());
} else {
return boost::ref(*(boost::any_cast<boost::shared_ptr<Result> >(ob.get())));
}
}
}
};
};
/**
* Cast_Helper for casting to a & type
*/
template<typename Result>
struct Cast_Helper<Result &>
{
typedef typename boost::reference_wrapper<Result> Result_Type;
static Result_Type cast(const Boxed_Value &ob)
/**
* Cast_Helper for casting to a boost::shared_ptr<> type
*/
template<typename Result>
struct Cast_Helper<typename boost::shared_ptr<Result> >
{
if (ob.is_ref())
typedef typename boost::shared_ptr<Result> Result_Type;
static Result_Type cast(const Boxed_Value &ob)
{
return boost::any_cast<boost::reference_wrapper<Result> >(ob.get());
} else {
return boost::ref(*(boost::any_cast<boost::shared_ptr<Result> >(ob.get())));
return boost::any_cast<boost::shared_ptr<Result> >(ob.get());
}
}
};
};
/**
* Cast_Helper for casting to a boost::shared_ptr<> type
*/
template<typename Result>
struct Cast_Helper<typename boost::shared_ptr<Result> >
{
typedef typename boost::shared_ptr<Result> Result_Type;
static Result_Type cast(const Boxed_Value &ob)
/**
* Cast_Helper for casting to a boost::shared_ptr<> type
*/
template<typename Result>
struct Cast_Helper<const boost::shared_ptr<Result> &>
{
return boost::any_cast<boost::shared_ptr<Result> >(ob.get());
}
};
typedef typename boost::shared_ptr<Result> Result_Type;
/**
* Cast_Helper for casting to a boost::shared_ptr<> type
*/
template<typename Result>
struct Cast_Helper<const boost::shared_ptr<Result> &>
{
typedef typename boost::shared_ptr<Result> Result_Type;
static Result_Type cast(const Boxed_Value &ob)
static Result_Type cast(const Boxed_Value &ob)
{
return boost::any_cast<boost::shared_ptr<Result> >(ob.get());
}
};
/**
* Cast_Helper for casting to a Boxed_Value type
*/
template<>
struct Cast_Helper<Boxed_Value>
{
return boost::any_cast<boost::shared_ptr<Result> >(ob.get());
}
};
typedef const Boxed_Value & Result_Type;
static Result_Type cast(const Boxed_Value &ob)
{
return ob;
}
};
/**
* Cast_Helper for casting to a Boxed_Value type
*/
template<>
struct Cast_Helper<Boxed_Value>
{
typedef Boxed_Value Result_Type;
static Result_Type cast(const Boxed_Value &ob)
/**
* Cast_Helper for casting to a const Boxed_Value & type
*/
template<>
struct Cast_Helper<const Boxed_Value &>
{
return ob;
}
};
typedef const Boxed_Value & Result_Type;
/**
* Cast_Helper for casting to a const Boxed_Value & type
*/
template<>
struct Cast_Helper<const Boxed_Value &>
{
typedef Boxed_Value Result_Type;
static Result_Type cast(const Boxed_Value &ob)
{
return ob;
}
};
static Result_Type cast(const Boxed_Value &ob)
{
return ob;
}
};
}
/**
* class that is thrown in the event of a bad_boxed_cast. That is,
@@ -530,10 +540,10 @@ namespace chaiscript
* int &i = boxed_cast<int &>(boxedvalue);
*/
template<typename Type>
typename Cast_Helper<Type>::Result_Type boxed_cast(const Boxed_Value &bv)
typename detail::Cast_Helper<Type>::Result_Type boxed_cast(const Boxed_Value &bv)
{
try {
return Cast_Helper<Type>::cast(bv);
return detail::Cast_Helper<Type>::cast(bv);
} catch (const boost::bad_any_cast &) {
throw bad_boxed_cast(bv.get_type_info(), typeid(Type));
}
@@ -669,19 +679,22 @@ namespace chaiscript
bool m_isfloat;
};
/**
* Cast_Helper for converting from Boxed_Value to Boxed_POD_Value
*/
template<>
struct Cast_Helper<Boxed_POD_Value>
{
typedef Boxed_POD_Value Result_Type;
static Result_Type cast(const Boxed_Value &ob)
namespace detail
{
/**
* Cast_Helper for converting from Boxed_Value to Boxed_POD_Value
*/
template<>
struct Cast_Helper<Boxed_POD_Value>
{
return Boxed_POD_Value(ob);
}
};
typedef Boxed_POD_Value Result_Type;
static Result_Type cast(const Boxed_Value &ob)
{
return Boxed_POD_Value(ob);
}
};
}
template<typename T>
Boxed_Value var(T t)
@@ -690,7 +703,7 @@ namespace chaiscript
}
/**
* Return true if the two Boxed_Value's share the same internal type
* Return true if the two Boxed_Values share the same internal type
*/
static bool type_match(Boxed_Value l, Boxed_Value r)
{

View File

@@ -94,7 +94,12 @@ namespace chaiscript
return std::vector<Type_Info>();
}
virtual bool types_match(const std::vector<Boxed_Value> &types) const
virtual int get_arity() const
{
return -1;
}
virtual bool call_match(const std::vector<Boxed_Value> &vals) const
{
typedef std::vector<std::pair<std::string, Proxy_Function > > function_vec;
@@ -103,7 +108,7 @@ namespace chaiscript
while (begin != end)
{
if (begin->second->types_match(types))
if (begin->second->call_match(vals))
{
return true;
} else {
@@ -133,12 +138,13 @@ namespace chaiscript
public:
typedef std::map<std::string, chaiscript::Type_Info> Type_Name_Map;
typedef std::map<std::string, Boxed_Value> Scope;
typedef std::deque<Scope> Stack;
typedef boost::shared_ptr<std::deque<Scope> > Stack;
Dispatch_Engine()
: m_place_holder(boost::shared_ptr<Placeholder_Object>(new Placeholder_Object()))
: m_scopes(new Stack::element_type()),
m_place_holder(boost::shared_ptr<Placeholder_Object>(new Placeholder_Object()))
{
m_scopes.push_back(Scope());
m_scopes->push_back(Scope());
}
/**
@@ -163,12 +169,12 @@ namespace chaiscript
*/
void add(const Boxed_Value &obj, const std::string &name)
{
for (int i = m_scopes.size()-1; i >= 0; --i)
for (int i = m_scopes->size()-1; i >= 0; --i)
{
std::map<std::string, Boxed_Value>::const_iterator itr = m_scopes[i].find(name);
if (itr != m_scopes[i].end())
std::map<std::string, Boxed_Value>::const_iterator itr = (*m_scopes)[i].find(name);
if (itr != (*m_scopes)[i].end())
{
m_scopes[i][name] = Boxed_Value(obj);
(*m_scopes)[i][name] = Boxed_Value(obj);
return;
}
}
@@ -181,7 +187,7 @@ namespace chaiscript
*/
void add_object(const std::string &name, const Boxed_Value &obj)
{
m_scopes.back()[name] = Boxed_Value(obj);
m_scopes->back()[name] = Boxed_Value(obj);
}
/**
@@ -189,7 +195,7 @@ namespace chaiscript
*/
void new_scope()
{
m_scopes.push_back(Scope());
m_scopes->push_back(Scope());
}
/**
@@ -197,9 +203,9 @@ namespace chaiscript
*/
void pop_scope()
{
if (m_scopes.size() > 1)
if (m_scopes->size() > 1)
{
m_scopes.pop_back();
m_scopes->pop_back();
} else {
throw std::range_error("Unable to pop global stack");
}
@@ -218,10 +224,16 @@ namespace chaiscript
* \returns the old stack
* \param[in] s The new stack
*/
Stack set_stack(Stack s)
Stack set_stack(const Stack &s)
{
std::swap(s, m_scopes);
return s;
Stack old = m_scopes;
m_scopes = s;
return old;
}
Stack new_stack()
{
return Stack(new Stack::element_type());
}
/**
@@ -236,10 +248,10 @@ namespace chaiscript
return m_place_holder;
}
for (int i = m_scopes.size()-1; i >= 0; --i)
for (int i = m_scopes->size()-1; i >= 0; --i)
{
std::map<std::string, Boxed_Value>::const_iterator itr = m_scopes[i].find(name);
if (itr != m_scopes[i].end())
std::map<std::string, Boxed_Value>::const_iterator itr = (*m_scopes)[i].find(name);
if (itr != (*m_scopes)[i].end())
{
return itr->second;
}
@@ -377,7 +389,7 @@ namespace chaiscript
return true;
}
std::deque<Scope> m_scopes;
Stack m_scopes;
std::multimap<std::string, Proxy_Function > m_functions;
Type_Name_Map m_types;

View File

@@ -4,13 +4,6 @@
// and Jason Turner (lefticus@gmail.com)
// http://www.chaiscript.com
#include <boost/preprocessor.hpp>
#define addparam(z,n,text) params.push_back(boost::is_reference<Param ## n>::value?Boxed_Value(boost::ref(BOOST_PP_CAT(p, n))):Boxed_Value(BOOST_PP_CAT(p, n) ));
#define curry(z,n,text) BOOST_PP_CAT(_, BOOST_PP_INC(n))
#ifndef BOOST_PP_IS_ITERATING
#ifndef __function_call_hpp__
#define __function_call_hpp__
@@ -20,50 +13,7 @@
#include <string>
#include <vector>
#include "proxy_functions.hpp"
namespace chaiscript
{
/**
* Internal helper class for handling the return
* value of a build_function_caller
*/
template<typename Ret>
class Function_Caller_Ret
{
public:
Function_Caller_Ret()
{
}
Ret call(const std::vector<std::pair<std::string, Proxy_Function > > &t_funcs,
const std::vector<Boxed_Value> &params)
{
return boxed_cast<Ret>(dispatch(t_funcs, params));
}
};
/**
* Specialization for void return types
*/
template<>
class Function_Caller_Ret<void>
{
public:
Function_Caller_Ret()
{
}
void call(const std::vector<std::pair<std::string, Proxy_Function > > &t_funcs,
const std::vector<Boxed_Value> &params)
{
dispatch(t_funcs, params);
}
};
}
#define BOOST_PP_ITERATION_LIMITS ( 0, 9 )
#define BOOST_PP_FILENAME_1 <chaiscript/dispatchkit/function_call.hpp>
#include BOOST_PP_ITERATE()
#include "function_call_detail.hpp"
namespace chaiscript
{
@@ -118,39 +68,5 @@ namespace chaiscript
}
# endif
#else
# define n BOOST_PP_ITERATION()
namespace chaiscript
{
/**
* used internally for unwrapping a function call's types
*/
template<typename Ret BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param) >
Ret function_caller(const std::vector<std::pair<std::string, Proxy_Function > > &funcs
BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_BINARY_PARAMS(n, Param, p) )
{
std::vector<Boxed_Value> params;
BOOST_PP_REPEAT(n, addparam, ~)
return Function_Caller_Ret<Ret>().call(funcs, params);
}
/**
* used internally for unwrapping a function call's types
*/
template<typename Ret BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param) >
boost::function<Ret (BOOST_PP_ENUM_PARAMS(n, Param)) >
build_function_caller_helper(Ret (BOOST_PP_ENUM_PARAMS(n, Param)), const std::vector<std::pair<std::string, Proxy_Function> > &funcs)
{
return boost::bind(&function_caller<Ret BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, Param)>, funcs
BOOST_PP_ENUM_TRAILING(n, curry, ~));
}
}
#endif

View File

@@ -0,0 +1,98 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009, Jonathan Turner (jturner@minnow-lang.org)
// and Jason Turner (lefticus@gmail.com)
// http://www.chaiscript.com
#include <boost/preprocessor.hpp>
#define addparam(z,n,text) params.push_back(boost::is_reference<Param ## n>::value?Boxed_Value(boost::ref(BOOST_PP_CAT(p, n))):Boxed_Value(BOOST_PP_CAT(p, n) ));
#define curry(z,n,text) BOOST_PP_CAT(_, BOOST_PP_INC(n))
#ifndef BOOST_PP_IS_ITERATING
#ifndef __function_call_detail_hpp__
#define __function_call_detail_hpp__
#include <boost/shared_ptr.hpp>
#include <boost/bind.hpp>
#include <boost/function.hpp>
#include <string>
#include <vector>
#include "proxy_functions.hpp"
namespace chaiscript
{
namespace detail
{
/**
* Internal helper class for handling the return
* value of a build_function_caller
*/
template<typename Ret>
class Function_Caller_Ret
{
static Ret call(const std::vector<std::pair<std::string, Proxy_Function > > &t_funcs,
const std::vector<Boxed_Value> &params)
{
return boxed_cast<Ret>(dispatch(t_funcs, params));
}
};
/**
* Specialization for void return types
*/
template<>
struct Function_Caller_Ret<void>
{
static void call(const std::vector<std::pair<std::string, Proxy_Function > > &t_funcs,
const std::vector<Boxed_Value> &params)
{
dispatch(t_funcs, params);
}
};
}
}
#define BOOST_PP_ITERATION_LIMITS ( 0, 9 )
#define BOOST_PP_FILENAME_1 <chaiscript/dispatchkit/function_call_detail.hpp>
#include BOOST_PP_ITERATE()
# endif
#else
# define n BOOST_PP_ITERATION()
namespace chaiscript
{
namespace detail
{
/**
* used internally for unwrapping a function call's types
*/
template<typename Ret BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param) >
Ret function_caller(const std::vector<std::pair<std::string, Proxy_Function > > &funcs
BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_BINARY_PARAMS(n, Param, p) )
{
std::vector<Boxed_Value> params;
BOOST_PP_REPEAT(n, addparam, ~)
return Function_Caller_Ret<Ret>::call(funcs, params);
}
/**
* used internally for unwrapping a function call's types
*/
template<typename Ret BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param) >
boost::function<Ret (BOOST_PP_ENUM_PARAMS(n, Param)) >
build_function_caller_helper(Ret (BOOST_PP_ENUM_PARAMS(n, Param)), const std::vector<std::pair<std::string, Proxy_Function> > &funcs)
{
return boost::bind(&function_caller<Ret BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, Param)>, funcs
BOOST_PP_ENUM_TRAILING(n, curry, ~));
}
}
}
#endif

View File

@@ -0,0 +1,100 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009, Jonathan Turner (jturner@minnow-lang.org)
// and Jason Turner (lefticus@gmail.com)
// http://www.chaiscript.com
#ifndef __handle_return_hpp__
#define __handle_return_hpp__
#include "boxed_value.hpp"
#include "type_info.hpp"
#include <string>
#include <boost/function.hpp>
#include <stdexcept>
#include <vector>
namespace chaiscript
{
/**
* Used internally for handling a return value from a Proxy_Function call
*/
template<typename Ret>
struct Handle_Return
{
static Boxed_Value call(const boost::function<Ret ()> &f)
{
return Boxed_Value(f());
}
};
template<typename Ret>
struct Handle_Return<boost::shared_ptr<Ret> &>
{
static Boxed_Value call(const boost::function<boost::shared_ptr<Ret> & ()> &f)
{
return Boxed_Value(f());
}
};
template<typename Ret>
struct Handle_Return<const boost::shared_ptr<Ret> &>
{
static Boxed_Value call(const boost::function<const boost::shared_ptr<Ret> & ()> &f)
{
return Boxed_Value(f());
}
};
/**
* Used internally for handling a return value from a Proxy_Function call
*/
template<typename Ret>
struct Handle_Return<Ret &>
{
static Boxed_Value call(const boost::function<Ret &()> &f)
{
return Boxed_Value(boost::ref(f()));
}
};
/**
* Used internally for handling a return value from a Proxy_Function call
*/
template<>
struct Handle_Return<Boxed_Value>
{
static Boxed_Value call(const boost::function<Boxed_Value ()> &f)
{
return f();
}
};
/**
* Used internally for handling a return value from a Proxy_Function call
*/
template<>
struct Handle_Return<Boxed_Value &>
{
static Boxed_Value call(const boost::function<Boxed_Value &()> &f)
{
return f();
}
};
/**
* Used internally for handling a return value from a Proxy_Function call
*/
template<>
struct Handle_Return<void>
{
static Boxed_Value call(const boost::function<void ()> &f)
{
f();
return Boxed_Value(Boxed_Value::Void_Type());
}
};
}
#endif

View File

@@ -26,7 +26,7 @@ namespace chaiscript
Proxy_Function constructor()
{
T *f = 0;
return (build_constructor_(f));
return (detail::build_constructor_(f));
}
}
@@ -35,28 +35,31 @@ namespace chaiscript
namespace chaiscript
{
/**
* A constructor function, used for creating a new object
* of a given type with a given set of params
*/
template<typename Class BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param) >
boost::shared_ptr<Class> constructor_( BOOST_PP_ENUM_BINARY_PARAMS(n, Param, p) )
{
return boost::shared_ptr<Class>(new Class( BOOST_PP_ENUM_PARAMS(n, p) ));
}
namespace detail
{
/**
* A constructor function, used for creating a new object
* of a given type with a given set of params
*/
template<typename Class BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param) >
boost::shared_ptr<Class> constructor_( BOOST_PP_ENUM_BINARY_PARAMS(n, Param, p) )
{
return boost::shared_ptr<Class>(new Class( BOOST_PP_ENUM_PARAMS(n, p) ));
}
/**
* Helper function for build a constructor function
* example:
* dispatchengine.register_function(build_constructor<MyClass, int, const std::string&>, "MyClass");
* \todo See if it is possible to make this not be a variadic function
*/
template<typename Class BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param) >
Proxy_Function build_constructor_(Class (*)(BOOST_PP_ENUM_PARAMS(n, Param)))
{
typedef boost::shared_ptr<Class> (sig)(BOOST_PP_ENUM_PARAMS(n, Param));
return Proxy_Function(new Proxy_Function_Impl<sig>(boost::function<sig>(&(constructor_<Class BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, Param)>))));
}
/**
* Helper function for build a constructor function
* example:
* dispatchengine.register_function(build_constructor<MyClass, int, const std::string&>, "MyClass");
* \todo See if it is possible to make this not be a variadic function
*/
template<typename Class BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param) >
Proxy_Function build_constructor_(Class (*)(BOOST_PP_ENUM_PARAMS(n, Param)))
{
typedef boost::shared_ptr<Class> (sig)(BOOST_PP_ENUM_PARAMS(n, Param));
return Proxy_Function(new Proxy_Function_Impl<sig>(boost::function<sig>(&(constructor_<Class BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, Param)>))));
}
}
}
#endif

View File

@@ -4,109 +4,22 @@
// and Jason Turner (lefticus@gmail.com)
// http://www.chaiscript.com
#include <boost/preprocessor.hpp>
#define gettypeinfo(z,n,text) ti.push_back(Get_Type_Info<Param ## n>::get());
#define casthelper(z,n,text) ,chaiscript::boxed_cast< Param ## n >(params[n])
#define comparetype(z,n,text) && ((Get_Type_Info<Param ## n>::get() == params[n].get_type_info()))
#define trycast(z,n,text) chaiscript::boxed_cast<Param ## n>(params[n]);
#ifndef BOOST_PP_IS_ITERATING
#ifndef __proxy_functions_hpp__
#define __proxy_functions_hpp__
#include "boxed_value.hpp"
#include "type_info.hpp"
#include <string>
#include <boost/function.hpp>
#include <boost/bind.hpp>
#include <boost/lexical_cast.hpp>
#include <stdexcept>
#include <vector>
#include "proxy_functions_detail.hpp"
namespace chaiscript
{
/**
* Used internally for handling a return value from a Proxy_Function call
*/
template<typename Ret>
struct Handle_Return
{
Boxed_Value operator()(const boost::function<Ret ()> &f)
{
return Boxed_Value(f());
}
};
template<typename Ret>
struct Handle_Return<boost::shared_ptr<Ret> &>
{
Boxed_Value operator()(const boost::function<boost::shared_ptr<Ret> & ()> &f)
{
return Boxed_Value(f());
}
};
template<typename Ret>
struct Handle_Return<const boost::shared_ptr<Ret> &>
{
Boxed_Value operator()(const boost::function<const boost::shared_ptr<Ret> & ()> &f)
{
return Boxed_Value(f());
}
};
/**
* Used internally for handling a return value from a Proxy_Function call
*/
template<typename Ret>
struct Handle_Return<Ret &>
{
Boxed_Value operator()(const boost::function<Ret &()> &f)
{
return Boxed_Value(boost::ref(f()));
}
};
/**
* Used internally for handling a return value from a Proxy_Function call
*/
template<>
struct Handle_Return<Boxed_Value>
{
Boxed_Value operator()(const boost::function<Boxed_Value ()> &f)
{
return f();
}
};
/**
* Used internally for handling a return value from a Proxy_Function call
*/
template<>
struct Handle_Return<Boxed_Value &>
{
Boxed_Value operator()(const boost::function<Boxed_Value &()> &f)
{
return f();
}
};
/**
* Used internally for handling a return value from a Proxy_Function call
*/
template<>
struct Handle_Return<void>
{
Boxed_Value operator()(const boost::function<void ()> &f)
{
f();
return Boxed_Value(Boxed_Value::Void_Type());
}
};
/**
* Helper for building a list of parameters for calling a Proxy_Function
* it does automatic conversion to Boxed_Value types via operator<<
@@ -138,30 +51,6 @@ namespace chaiscript
std::vector<Boxed_Value> objects;
};
/**
* Exception thrown when there is a mismatch in number of
* parameters during Proxy_Function execution
*/
struct arity_error : std::range_error
{
arity_error(int t_got, int t_expected)
: std::range_error("Function dispatch arity mismatch"),
got(t_got), expected(t_expected)
{
}
virtual ~arity_error() throw() {}
int got;
int expected;
};
}
#define BOOST_PP_ITERATION_LIMITS ( 0, 10 )
#define BOOST_PP_FILENAME_1 <chaiscript/dispatchkit/proxy_functions.hpp>
#include BOOST_PP_ITERATE()
namespace chaiscript
{
/**
* Pure virtual base class for all Proxy_Function implementations
* Proxy_Functions are a type erasure of type safe C++
@@ -177,7 +66,48 @@ namespace chaiscript
virtual Boxed_Value operator()(const std::vector<Boxed_Value> &params) = 0;
virtual std::vector<Type_Info> get_param_types() const = 0;
virtual bool operator==(const Proxy_Function_Base &) const = 0;
virtual bool types_match(const std::vector<Boxed_Value> &types) const = 0;
virtual bool call_match(const std::vector<Boxed_Value> &vals) const = 0;
//! Return true if the function is a possible match
//! to the passed in values
bool filter(const std::vector<Boxed_Value> &vals) const
{
int arity = get_arity();
if (arity < 0)
{
return true;
} else if (size_t(arity) == vals.size()) {
if (arity == 0)
{
return true;
} else {
const std::vector<Type_Info> &types = get_param_types();
if (types.size() < 2)
{
return true;
}
const Type_Info &ti = types[1];
if (!ti.m_bare_type_info || !(vals[0].get_type_info().m_bare_type_info)
|| (*ti.m_bare_type_info) == (*user_type<Boxed_Value>().m_bare_type_info)
|| (*ti.m_bare_type_info) == (*user_type<Boxed_POD_Value>().m_bare_type_info)
|| (*vals[0].get_type_info().m_bare_type_info) == (*ti.m_bare_type_info))
{
return true;
} else {
return false;
}
}
} else {
return false;
}
}
virtual int get_arity() const = 0;
virtual std::string annotation() const = 0;
};
@@ -209,7 +139,8 @@ namespace chaiscript
int t_arity=-1,
const std::string &t_description = "",
const Proxy_Function &t_guard = Proxy_Function())
: m_f(t_f), m_arity(t_arity), m_description(t_description), m_guard(t_guard)
: m_f(t_f), m_arity(t_arity), m_description(t_description), m_guard(t_guard),
m_types(build_param_type_list(t_arity))
{
}
@@ -218,10 +149,10 @@ namespace chaiscript
return false;
}
virtual bool types_match(const std::vector<Boxed_Value> &types) const
virtual bool call_match(const std::vector<Boxed_Value> &vals) const
{
return (m_arity < 0 || types.size() == size_t(m_arity))
&& test_guard(types);
return (m_arity < 0 || vals.size() == size_t(m_arity))
&& test_guard(vals);
}
virtual ~Dynamic_Proxy_Function() {}
@@ -243,23 +174,14 @@ namespace chaiscript
}
}
virtual int get_arity() const
{
return m_arity;
}
virtual std::vector<Type_Info> get_param_types() const
{
std::vector<Type_Info> types;
types.push_back(Get_Type_Info<Boxed_Value>::get());
if (m_arity >= 0)
{
for (int i = 0; i < m_arity; ++i)
{
types.push_back(Get_Type_Info<Boxed_Value>::get());
}
} else {
types.push_back(Get_Type_Info<std::vector<Boxed_Value> >::get());
}
return types;
return m_types;
}
virtual std::string annotation() const
@@ -284,10 +206,30 @@ namespace chaiscript
}
}
static std::vector<Type_Info> build_param_type_list(int arity)
{
std::vector<Type_Info> types;
types.push_back(detail::Get_Type_Info<Boxed_Value>::get());
if (arity >= 0)
{
for (int i = 0; i < arity; ++i)
{
types.push_back(detail::Get_Type_Info<Boxed_Value>::get());
}
} else {
types.push_back(detail::Get_Type_Info<std::vector<Boxed_Value> >::get());
}
return types;
}
boost::function<Boxed_Value (const std::vector<Boxed_Value> &)> m_f;
int m_arity;
std::string m_description;
Proxy_Function m_guard;
std::vector<Type_Info> m_types;
};
/**
@@ -309,7 +251,7 @@ namespace chaiscript
public:
Bound_Function(const Proxy_Function &t_f,
const std::vector<Boxed_Value> &t_args)
: m_f(t_f), m_args(t_args)
: m_f(t_f), m_args(t_args), m_arity(m_f->get_arity()<0?-1:(m_f->get_arity() - m_args.size()))
{
}
@@ -320,10 +262,9 @@ namespace chaiscript
virtual ~Bound_Function() {}
virtual bool types_match(const std::vector<Boxed_Value> &types) const
virtual bool call_match(const std::vector<Boxed_Value> &vals) const
{
std::vector<Boxed_Value> params = build_param_list(types);
return m_f->types_match(params);
return m_f->call_match(build_param_list(vals));
}
virtual Boxed_Value operator()(const std::vector<Boxed_Value> &params)
@@ -343,7 +284,7 @@ namespace chaiscript
while (true)
{
while (barg != m_args.end()
&& !(barg->get_type_info() == Get_Type_Info<Placeholder_Object>::get()))
&& !(barg->get_type_info() == detail::Get_Type_Info<Placeholder_Object>::get()))
{
args.push_back(*barg);
++barg;
@@ -356,7 +297,7 @@ namespace chaiscript
}
if (barg != m_args.end()
&& barg->get_type_info() == Get_Type_Info<Placeholder_Object>::get())
&& barg->get_type_info() == detail::Get_Type_Info<Placeholder_Object>::get())
{
++barg;
}
@@ -374,6 +315,11 @@ namespace chaiscript
return std::vector<Type_Info>();
}
virtual int get_arity() const
{
return m_arity;
}
virtual std::string annotation() const
{
return "";
@@ -382,6 +328,7 @@ namespace chaiscript
private:
Proxy_Function m_f;
std::vector<Boxed_Value> m_args;
int m_arity;
};
/**
@@ -394,7 +341,7 @@ namespace chaiscript
{
public:
Proxy_Function_Impl(const boost::function<Func> &f)
: m_f(f)
: m_f(f), m_dummy_func(0), m_types(build_param_type_list(m_dummy_func))
{
}
@@ -417,14 +364,18 @@ namespace chaiscript
virtual std::vector<Type_Info> get_param_types() const
{
Func *f = 0;
return build_param_type_list(f);
return m_types;
}
virtual bool types_match(const std::vector<Boxed_Value> &types) const
virtual int get_arity() const
{
Func *f = 0;
return compare_types(f, types);
return m_types.size() - 1;
}
virtual bool call_match(const std::vector<Boxed_Value> &vals) const
{
return compare_types(m_dummy_func, vals);
}
virtual std::string annotation() const
@@ -434,6 +385,8 @@ namespace chaiscript
private:
boost::function<Func> m_f;
Func *m_dummy_func;
std::vector<Type_Info> m_types;
};
/**
@@ -465,7 +418,10 @@ namespace chaiscript
++itr)
{
try {
return (*itr->second)(plist);
if (itr->second->filter(plist))
{
return (*itr->second)(plist);
}
} catch (const bad_boxed_cast &) {
//parameter failed to cast, try again
} catch (const arity_error &) {
@@ -479,70 +435,5 @@ namespace chaiscript
}
}
# endif
#else
# define n BOOST_PP_ITERATION()
namespace chaiscript
{
/**
* Used by Proxy_Function_Impl to return a list of all param types
* it contains.
*/
template<typename Ret BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param) >
std::vector<Type_Info> build_param_type_list(Ret (*)(BOOST_PP_ENUM_PARAMS(n, Param)))
{
std::vector<Type_Info> ti;
ti.push_back(Get_Type_Info<Ret>::get());
BOOST_PP_REPEAT(n, gettypeinfo, ~)
return ti;
}
/**
* Used by Proxy_Function_Impl to perform typesafe execution of a function.
* The function attempts to unbox each paramter to the expected type.
* if any unboxing fails the execution of the function fails and
* the bad_boxed_cast is passed up to the caller.
*/
template<typename Ret BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param)>
Boxed_Value call_func(const boost::function<Ret (BOOST_PP_ENUM_PARAMS(n, Param))> &f,
const std::vector<Boxed_Value> &params)
{
if (params.size() != n)
{
throw arity_error(params.size(), n);
} else {
return Handle_Return<Ret>()(boost::bind(f BOOST_PP_REPEAT(n, casthelper, ~)));
}
}
/**
* Used by Proxy_Function_Impl to determine if it is equivalent to another
* Proxy_Function_Impl object. This function is primarly used to prevent
* registration of two functions with the exact same signatures
*/
template<typename Ret BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param)>
bool compare_types(Ret (*)(BOOST_PP_ENUM_PARAMS(n, Param)),
const std::vector<Boxed_Value> &params)
{
if (params.size() != n)
{
return false;
} else {
bool val = true BOOST_PP_REPEAT(n, comparetype, ~);
if (val) return true;
try {
BOOST_PP_REPEAT(n, trycast, ~);
} catch (const bad_boxed_cast &) {
return false;
}
return true;
}
}
}
#endif

View File

@@ -0,0 +1,121 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009, Jonathan Turner (jturner@minnow-lang.org)
// and Jason Turner (lefticus@gmail.com)
// http://www.chaiscript.com
#include <boost/preprocessor.hpp>
#define gettypeinfo(z,n,text) ti.push_back(detail::Get_Type_Info<Param ## n>::get());
#define casthelper(z,n,text) ,chaiscript::boxed_cast< Param ## n >(params[n])
#define comparetype(z,n,text) && ((detail::Get_Type_Info<Param ## n>::get() == params[n].get_type_info()))
#define trycast(z,n,text) chaiscript::boxed_cast<Param ## n>(params[n]);
#ifndef BOOST_PP_IS_ITERATING
#ifndef __proxy_functions_detail_hpp__
#define __proxy_functions_detail_hpp__
#include "boxed_value.hpp"
#include "type_info.hpp"
#include "handle_return.hpp"
#include <string>
#include <boost/function.hpp>
#include <boost/bind.hpp>
#include <boost/lexical_cast.hpp>
#include <stdexcept>
#include <vector>
namespace chaiscript
{
/**
* Exception thrown when there is a mismatch in number of
* parameters during Proxy_Function execution
*/
struct arity_error : std::range_error
{
arity_error(int t_got, int t_expected)
: std::range_error("Function dispatch arity mismatch"),
got(t_got), expected(t_expected)
{
}
virtual ~arity_error() throw() {}
int got;
int expected;
};
}
#define BOOST_PP_ITERATION_LIMITS ( 0, 10 )
#define BOOST_PP_FILENAME_1 <chaiscript/dispatchkit/proxy_functions_detail.hpp>
#include BOOST_PP_ITERATE()
# endif
#else
# define n BOOST_PP_ITERATION()
namespace chaiscript
{
/**
* Used by Proxy_Function_Impl to return a list of all param types
* it contains.
*/
template<typename Ret BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param) >
std::vector<Type_Info> build_param_type_list(Ret (*)(BOOST_PP_ENUM_PARAMS(n, Param)))
{
std::vector<Type_Info> ti;
ti.push_back(detail::Get_Type_Info<Ret>::get());
BOOST_PP_REPEAT(n, gettypeinfo, ~)
return ti;
}
/**
* Used by Proxy_Function_Impl to perform typesafe execution of a function.
* The function attempts to unbox each paramter to the expected type.
* if any unboxing fails the execution of the function fails and
* the bad_boxed_cast is passed up to the caller.
*/
template<typename Ret BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param)>
Boxed_Value call_func(const boost::function<Ret (BOOST_PP_ENUM_PARAMS(n, Param))> &f,
const std::vector<Boxed_Value> &params)
{
if (params.size() != n)
{
throw arity_error(params.size(), n);
} else {
return Handle_Return<Ret>::call(boost::bind(f BOOST_PP_REPEAT(n, casthelper, ~)));
}
}
/**
* Used by Proxy_Function_Impl to determine if it is equivalent to another
* Proxy_Function_Impl object. This function is primarly used to prevent
* registration of two functions with the exact same signatures
*/
template<typename Ret BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param)>
bool compare_types(Ret (*)(BOOST_PP_ENUM_PARAMS(n, Param)),
const std::vector<Boxed_Value> &params)
{
if (params.size() != n)
{
return false;
} else {
bool val = true BOOST_PP_REPEAT(n, comparetype, ~);
if (val) return true;
try {
BOOST_PP_REPEAT(n, trycast, ~);
} catch (const bad_boxed_cast &) {
return false;
}
return true;
}
}
}
#endif

View File

@@ -22,15 +22,17 @@ namespace chaiscript
return Proxy_Function(new Proxy_Function_Impl<T>(f));
}
/**
* Helper function for register_member function
*/
template<typename T, typename Class>
T &get_member(T Class::* m, Class *obj)
{
return (obj->*m);
}
namespace detail
{
/**
* Helper function for register_member function
*/
template<typename T, typename Class>
T &get_member(T Class::* m, Class *obj)
{
return (obj->*m);
}
}
/**
* Automatically create a get_member helper function for an object
@@ -40,7 +42,7 @@ namespace chaiscript
template<typename T, typename Class>
Proxy_Function fun(T Class::* m)
{
return fun(boost::function<T& (Class *)>(boost::bind(&get_member<T, Class>, m, _1)));
return fun(boost::function<T& (Class *)>(boost::bind(&detail::get_member<T, Class>, m, _1)));
}
}

View File

@@ -77,57 +77,59 @@ namespace chaiscript
bool m_is_unknown;
};
/**
* Helper used to create a Type_Info object
*/
template<typename T>
struct Get_Type_Info
{
static Type_Info get()
namespace detail
{
/**
* Helper used to create a Type_Info object
*/
template<typename T>
struct Get_Type_Info
{
return Type_Info(boost::is_const<T>::value, boost::is_reference<T>::value, boost::is_pointer<T>::value,
boost::is_void<T>::value,
&typeid(T),
&typeid(typename boost::remove_const<typename boost::remove_pointer<typename boost::remove_reference<T>::type>::type>::type));
}
};
static Type_Info get()
{
return Type_Info(boost::is_const<T>::value, boost::is_reference<T>::value, boost::is_pointer<T>::value,
boost::is_void<T>::value,
&typeid(T),
&typeid(typename boost::remove_const<typename boost::remove_pointer<typename boost::remove_reference<T>::type>::type>::type));
}
};
template<typename T>
struct Get_Type_Info<boost::shared_ptr<T> >
{
static Type_Info get()
template<typename T>
struct Get_Type_Info<boost::shared_ptr<T> >
{
return Type_Info(boost::is_const<T>::value, boost::is_reference<T>::value, boost::is_pointer<T>::value,
boost::is_void<T>::value,
&typeid(boost::shared_ptr<T> ),
&typeid(typename boost::remove_const<typename boost::remove_pointer<typename boost::remove_reference<T>::type>::type>::type));
}
};
static Type_Info get()
{
return Type_Info(boost::is_const<T>::value, boost::is_reference<T>::value, boost::is_pointer<T>::value,
boost::is_void<T>::value,
&typeid(boost::shared_ptr<T> ),
&typeid(typename boost::remove_const<typename boost::remove_pointer<typename boost::remove_reference<T>::type>::type>::type));
}
};
template<typename T>
struct Get_Type_Info<boost::reference_wrapper<T> >
{
static Type_Info get()
template<typename T>
struct Get_Type_Info<boost::reference_wrapper<T> >
{
return Type_Info(boost::is_const<T>::value, boost::is_reference<T>::value, boost::is_pointer<T>::value,
boost::is_void<T>::value,
&typeid(boost::reference_wrapper<T> ),
&typeid(typename boost::remove_const<typename boost::remove_pointer<typename boost::remove_reference<T>::type>::type>::type));
}
};
static Type_Info get()
{
return Type_Info(boost::is_const<T>::value, boost::is_reference<T>::value, boost::is_pointer<T>::value,
boost::is_void<T>::value,
&typeid(boost::reference_wrapper<T> ),
&typeid(typename boost::remove_const<typename boost::remove_pointer<typename boost::remove_reference<T>::type>::type>::type));
}
};
}
template<typename T>
Type_Info user_type(T)
{
return Get_Type_Info<T>::get();
return detail::Get_Type_Info<T>::get();
}
template<typename T>
Type_Info user_type()
{
return Get_Type_Info<T>::get();
return detail::Get_Type_Info<T>::get();
}

View File

@@ -405,10 +405,10 @@ namespace chaiscript
Boxed_Value retval;
Param_List_Builder plb;
Dispatch_Engine::Stack prev_stack = ss.get_stack();
Dispatch_Engine::Stack new_stack;
Dispatch_Engine::Stack new_stack = ss.new_stack();
unsigned int i;
new_stack.push_back(Dispatch_Engine::Scope());
new_stack->push_back(Dispatch_Engine::Scope());
if ((node->children.size() > 1) && (node->children[1]->identifier == Token_Type::Arg_List)) {
for (i = 0; i < node->children[1]->children.size(); ++i) {
@@ -452,10 +452,10 @@ namespace chaiscript
Boxed_Value retval;
std::vector<std::pair<std::string, Proxy_Function > > fn;
Dispatch_Engine::Stack prev_stack = ss.get_stack();
Dispatch_Engine::Stack new_stack;
Dispatch_Engine::Stack new_stack = ss.new_stack();
unsigned int i, j;
new_stack.push_back(Dispatch_Engine::Scope());
new_stack->push_back(Dispatch_Engine::Scope());
//todo: Please extract a single way of doing function calls between this and eval_fun_call

View File

@@ -2,7 +2,7 @@ var i = 0
if (i == 0) {
print("i is 0")
}
elseif (i == 1) {
else if (i == 1) {
print("i is 1")
}
else {