Add const correctness for proxy functions. Add unit tests for function variable assignment scenarios
This commit is contained in:
@@ -533,22 +533,39 @@ namespace chaiscript
|
|||||||
* function variables.
|
* function variables.
|
||||||
*/
|
*/
|
||||||
template<typename Type>
|
template<typename Type>
|
||||||
boost::shared_ptr<Type> shared_ptr_clone(boost::shared_ptr<Type> f)
|
boost::shared_ptr<Type> shared_ptr_clone(const boost::shared_ptr<Type> &p)
|
||||||
{
|
{
|
||||||
return f;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specific version of shared_ptr_clone just for Proxy_Functions
|
||||||
|
* probably not necessary, probably could just use the version above,
|
||||||
|
* but here we are.
|
||||||
|
*/
|
||||||
|
Proxy_Function proxy_function_clone(const Const_Proxy_Function &f)
|
||||||
|
{
|
||||||
|
return boost::const_pointer_cast<Proxy_Function_Base>(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Assignment function for shared_ptr objects, does not perform a copy of the
|
* Assignment function for shared_ptr objects, does not perform a copy of the
|
||||||
* object pointed to, instead maintains the shared_ptr concept.
|
* object pointed to, instead maintains the shared_ptr concept.
|
||||||
* Similar to shared_ptr_clone. Used for Proxy_Function.
|
* Similar to shared_ptr_clone. Used for Proxy_Function.
|
||||||
*/
|
*/
|
||||||
template<typename Type>
|
template<typename Type>
|
||||||
Boxed_Value ptr_assign(Boxed_Value lhs, boost::shared_ptr<Type> rhs)
|
Boxed_Value ptr_assign(Boxed_Value lhs, const boost::shared_ptr<typename boost::add_const<Type>::type> &rhs)
|
||||||
{
|
{
|
||||||
lhs.assign(Boxed_Value(rhs));
|
if (lhs.is_unknown()
|
||||||
|
|| (!lhs.get_type_info().is_const() && lhs.get_type_info().bare_equal(chaiscript::detail::Get_Type_Info<Type>::get())))
|
||||||
return lhs;
|
{
|
||||||
|
lhs.assign(Boxed_Value(rhs));
|
||||||
|
return lhs;
|
||||||
|
} else {
|
||||||
|
throw bad_boxed_cast("type mismatch in pointer assignment");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -617,9 +634,9 @@ namespace chaiscript
|
|||||||
throw arity_error(params.size(), 2);
|
throw arity_error(params.size(), 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
Proxy_Function f = boxed_cast<Proxy_Function >(params[0]);
|
Const_Proxy_Function f = boxed_cast<Const_Proxy_Function>(params[0]);
|
||||||
|
|
||||||
return Boxed_Value(Proxy_Function(new Bound_Function(f,
|
return Boxed_Value(Const_Proxy_Function(new Bound_Function(f,
|
||||||
std::vector<Boxed_Value>(params.begin() + 1, params.end()))));
|
std::vector<Boxed_Value>(params.begin() + 1, params.end()))));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -634,7 +651,7 @@ namespace chaiscript
|
|||||||
throw arity_error(params.size(), 1);
|
throw arity_error(params.size(), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
Proxy_Function f = boxed_cast<Proxy_Function >(params[0]);
|
Const_Proxy_Function f = boxed_cast<Const_Proxy_Function>(params[0]);
|
||||||
|
|
||||||
return Boxed_Value(f->call_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())));
|
||||||
}
|
}
|
||||||
@@ -703,7 +720,7 @@ namespace chaiscript
|
|||||||
m->add(Proxy_Function(new Dynamic_Proxy_Function(boost::bind(&bind_function, _1))),
|
m->add(Proxy_Function(new Dynamic_Proxy_Function(boost::bind(&bind_function, _1))),
|
||||||
"bind");
|
"bind");
|
||||||
|
|
||||||
m->add(fun(&shared_ptr_clone<Proxy_Function_Base>), "clone");
|
m->add(fun(&proxy_function_clone), "clone");
|
||||||
m->add(fun(&ptr_assign<Proxy_Function_Base>), "=");
|
m->add(fun(&ptr_assign<Proxy_Function_Base>), "=");
|
||||||
|
|
||||||
m->add(Proxy_Function(new Dynamic_Proxy_Function(boost::bind(&call_exists, _1))),
|
m->add(Proxy_Function(new Dynamic_Proxy_Function(boost::bind(&call_exists, _1))),
|
||||||
|
@@ -135,6 +135,8 @@ namespace chaiscript
|
|||||||
template<typename T>
|
template<typename T>
|
||||||
boost::shared_ptr<Data> get(const boost::shared_ptr<T> &obj)
|
boost::shared_ptr<Data> get(const boost::shared_ptr<T> &obj)
|
||||||
{
|
{
|
||||||
|
bool b_const = boost::is_const<T>::value;
|
||||||
|
|
||||||
boost::shared_ptr<Data> data(new Data(
|
boost::shared_ptr<Data> data(new Data(
|
||||||
detail::Get_Type_Info<T>::get(),
|
detail::Get_Type_Info<T>::get(),
|
||||||
boost::any(obj),
|
boost::any(obj),
|
||||||
@@ -142,14 +144,14 @@ namespace chaiscript
|
|||||||
boost::shared_ptr<Data::Shared_Ptr_Proxy>(new Data::Shared_Ptr_Proxy_Impl<T>()))
|
boost::shared_ptr<Data::Shared_Ptr_Proxy>(new Data::Shared_Ptr_Proxy_Impl<T>()))
|
||||||
);
|
);
|
||||||
|
|
||||||
std::map<const void *, Data>::iterator itr
|
std::map<std::pair<const void *, bool>, Data>::iterator itr
|
||||||
= m_ptrs.find(obj.get());
|
= m_ptrs.find(std::make_pair(obj.get(), b_const));
|
||||||
|
|
||||||
if (itr != m_ptrs.end())
|
if (itr != m_ptrs.end())
|
||||||
{
|
{
|
||||||
(*data) = (itr->second);
|
(*data) = (itr->second);
|
||||||
} else {
|
} else {
|
||||||
m_ptrs.insert(std::make_pair(obj.get(), *data));
|
m_ptrs.insert(std::make_pair(std::make_pair(obj.get(), b_const), *data));
|
||||||
}
|
}
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
@@ -164,14 +166,16 @@ namespace chaiscript
|
|||||||
template<typename T>
|
template<typename T>
|
||||||
boost::shared_ptr<Data> get(boost::reference_wrapper<T> obj)
|
boost::shared_ptr<Data> get(boost::reference_wrapper<T> obj)
|
||||||
{
|
{
|
||||||
|
bool b_const = boost::is_const<T>::value;
|
||||||
|
|
||||||
boost::shared_ptr<Data> data(new Data(
|
boost::shared_ptr<Data> data(new Data(
|
||||||
detail::Get_Type_Info<T>::get(),
|
detail::Get_Type_Info<T>::get(),
|
||||||
boost::any(obj),
|
boost::any(obj),
|
||||||
true)
|
true)
|
||||||
);
|
);
|
||||||
|
|
||||||
std::map<const void *, Data >::iterator itr
|
std::map<std::pair<const void *, bool>, Data >::iterator itr
|
||||||
= m_ptrs.find(obj.get_pointer());
|
= m_ptrs.find(std::make_pair(obj.get_pointer(), b_const) );
|
||||||
|
|
||||||
// If the ptr is found in the cache and it is the correct type,
|
// If the ptr is found in the cache and it is the correct type,
|
||||||
// return it. It may be the incorrect type when two variables share the
|
// return it. It may be the incorrect type when two variables share the
|
||||||
@@ -201,7 +205,7 @@ namespace chaiscript
|
|||||||
|
|
||||||
boost::shared_ptr<T> *ptr = boost::any_cast<boost::shared_ptr<T> >(&data->m_obj);
|
boost::shared_ptr<T> *ptr = boost::any_cast<boost::shared_ptr<T> >(&data->m_obj);
|
||||||
|
|
||||||
m_ptrs.insert(std::make_pair(ptr->get(), *data));
|
m_ptrs.insert(std::make_pair(std::make_pair(ptr->get(), false), *data));
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -228,13 +232,13 @@ namespace chaiscript
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
std::map<const void *, Data >::iterator itr = m_ptrs.begin();
|
std::map<std::pair<const void *, bool>, Data>::iterator itr = m_ptrs.begin();
|
||||||
|
|
||||||
while (itr != m_ptrs.end())
|
while (itr != m_ptrs.end())
|
||||||
{
|
{
|
||||||
if (itr->second.m_ptr_proxy->unique(&itr->second.m_obj) == 1)
|
if (itr->second.m_ptr_proxy->unique(&itr->second.m_obj) == 1)
|
||||||
{
|
{
|
||||||
std::map<const void *, Data >::iterator todel = itr;
|
std::map<std::pair<const void *, bool>, Data >::iterator todel = itr;
|
||||||
++itr;
|
++itr;
|
||||||
m_ptrs.erase(todel);
|
m_ptrs.erase(todel);
|
||||||
} else {
|
} else {
|
||||||
@@ -243,7 +247,7 @@ namespace chaiscript
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::map<const void *, Data > m_ptrs;
|
std::map<std::pair<const void *, bool>, Data > m_ptrs;
|
||||||
int m_cullcount;
|
int m_cullcount;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -87,7 +87,7 @@ namespace chaiscript
|
|||||||
|
|
||||||
virtual ~Dispatch_Function() {}
|
virtual ~Dispatch_Function() {}
|
||||||
|
|
||||||
virtual Boxed_Value operator()(const std::vector<Boxed_Value> ¶ms)
|
virtual Boxed_Value operator()(const std::vector<Boxed_Value> ¶ms) const
|
||||||
{
|
{
|
||||||
return dispatch(m_funcs.begin(), m_funcs.end(), params);
|
return dispatch(m_funcs.begin(), m_funcs.end(), params);
|
||||||
}
|
}
|
||||||
@@ -360,7 +360,7 @@ namespace chaiscript
|
|||||||
{
|
{
|
||||||
throw std::range_error("Object not known: " + name);
|
throw std::range_error("Object not known: " + name);
|
||||||
} else {
|
} else {
|
||||||
Boxed_Value f(Proxy_Function(new Dispatch_Function(funcs)));
|
Boxed_Value f(Const_Proxy_Function(new Dispatch_Function(funcs)));
|
||||||
cache[name] = f;
|
cache[name] = f;
|
||||||
return f;
|
return f;
|
||||||
}
|
}
|
||||||
|
@@ -99,7 +99,7 @@ namespace chaiscript
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Boxed_Value operator()(const std::vector<Boxed_Value> ¶ms)
|
virtual Boxed_Value operator()(const std::vector<Boxed_Value> ¶ms) const
|
||||||
{
|
{
|
||||||
if (dynamic_object_typename_match(params, m_type_name))
|
if (dynamic_object_typename_match(params, m_type_name))
|
||||||
{
|
{
|
||||||
@@ -180,7 +180,7 @@ namespace chaiscript
|
|||||||
return m_func->call_match(new_vals);
|
return m_func->call_match(new_vals);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Boxed_Value operator()(const std::vector<Boxed_Value> ¶ms)
|
virtual Boxed_Value operator()(const std::vector<Boxed_Value> ¶ms) const
|
||||||
{
|
{
|
||||||
std::vector<Boxed_Value> new_params;
|
std::vector<Boxed_Value> new_params;
|
||||||
chaiscript::Boxed_Value bv = var(Dynamic_Object(m_type_name));
|
chaiscript::Boxed_Value bv = var(Dynamic_Object(m_type_name));
|
||||||
|
@@ -62,7 +62,7 @@ namespace chaiscript
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual ~Proxy_Function_Base() {}
|
virtual ~Proxy_Function_Base() {}
|
||||||
virtual Boxed_Value operator()(const std::vector<Boxed_Value> ¶ms) = 0;
|
virtual Boxed_Value operator()(const std::vector<Boxed_Value> ¶ms) const = 0;
|
||||||
|
|
||||||
std::vector<Type_Info> get_param_types() const { return m_types; }
|
std::vector<Type_Info> get_param_types() const { return m_types; }
|
||||||
|
|
||||||
@@ -139,6 +139,7 @@ namespace chaiscript
|
|||||||
};
|
};
|
||||||
|
|
||||||
typedef boost::shared_ptr<Proxy_Function_Base> Proxy_Function;
|
typedef boost::shared_ptr<Proxy_Function_Base> Proxy_Function;
|
||||||
|
typedef boost::shared_ptr<const Proxy_Function_Base> Const_Proxy_Function;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Exception thrown if a function's guard fails to execute
|
* Exception thrown if a function's guard fails to execute
|
||||||
@@ -184,7 +185,7 @@ namespace chaiscript
|
|||||||
|
|
||||||
virtual ~Dynamic_Proxy_Function() {}
|
virtual ~Dynamic_Proxy_Function() {}
|
||||||
|
|
||||||
virtual Boxed_Value operator()(const std::vector<Boxed_Value> ¶ms)
|
virtual Boxed_Value operator()(const std::vector<Boxed_Value> ¶ms) const
|
||||||
{
|
{
|
||||||
if (m_arity < 0 || params.size() == size_t(m_arity))
|
if (m_arity < 0 || params.size() == size_t(m_arity))
|
||||||
{
|
{
|
||||||
@@ -270,7 +271,7 @@ namespace chaiscript
|
|||||||
class Bound_Function : public Proxy_Function_Base
|
class Bound_Function : public Proxy_Function_Base
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Bound_Function(const Proxy_Function &t_f,
|
Bound_Function(const Const_Proxy_Function &t_f,
|
||||||
const std::vector<Boxed_Value> &t_args)
|
const std::vector<Boxed_Value> &t_args)
|
||||||
: Proxy_Function_Base(std::vector<Type_Info>()),
|
: Proxy_Function_Base(std::vector<Type_Info>()),
|
||||||
m_f(t_f), m_args(t_args), m_arity(m_f->get_arity()<0?-1:(m_f->get_arity() - m_args.size()))
|
m_f(t_f), m_args(t_args), m_arity(m_f->get_arity()<0?-1:(m_f->get_arity() - m_args.size()))
|
||||||
@@ -289,7 +290,7 @@ namespace chaiscript
|
|||||||
return m_f->call_match(build_param_list(vals));
|
return m_f->call_match(build_param_list(vals));
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Boxed_Value operator()(const std::vector<Boxed_Value> ¶ms)
|
virtual Boxed_Value operator()(const std::vector<Boxed_Value> ¶ms) const
|
||||||
{
|
{
|
||||||
return (*m_f)(build_param_list(params));
|
return (*m_f)(build_param_list(params));
|
||||||
}
|
}
|
||||||
@@ -343,7 +344,7 @@ namespace chaiscript
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Proxy_Function m_f;
|
Const_Proxy_Function m_f;
|
||||||
std::vector<Boxed_Value> m_args;
|
std::vector<Boxed_Value> m_args;
|
||||||
int m_arity;
|
int m_arity;
|
||||||
};
|
};
|
||||||
@@ -375,7 +376,7 @@ namespace chaiscript
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Boxed_Value operator()(const std::vector<Boxed_Value> ¶ms)
|
virtual Boxed_Value operator()(const std::vector<Boxed_Value> ¶ms) const
|
||||||
{
|
{
|
||||||
return Do_Call<typename boost::function<Func>::result_type>::go(m_f, params);
|
return Do_Call<typename boost::function<Func>::result_type>::go(m_f, params);
|
||||||
}
|
}
|
||||||
|
@@ -470,7 +470,7 @@ namespace chaiscript
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
ss.set_stack(new_stack);
|
ss.set_stack(new_stack);
|
||||||
Boxed_Value retval = (*boxed_cast<Proxy_Function >(fn))(plb);
|
Boxed_Value retval = (*boxed_cast<Const_Proxy_Function>(fn))(plb);
|
||||||
ss.set_stack(prev_stack);
|
ss.set_stack(prev_stack);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
@@ -512,7 +512,7 @@ namespace chaiscript
|
|||||||
Boxed_Value fn = eval_token(ss, node->children[0]);
|
Boxed_Value fn = eval_token(ss, node->children[0]);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Boxed_Value retval = (*boxed_cast<Proxy_Function >(fn))(plb);
|
Boxed_Value retval = (*boxed_cast<Const_Proxy_Function >(fn))(plb);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
catch(const dispatch_error &e){
|
catch(const dispatch_error &e){
|
||||||
@@ -575,7 +575,7 @@ namespace chaiscript
|
|||||||
//fn = ss.get_function(fun_name);
|
//fn = ss.get_function(fun_name);
|
||||||
ss.set_stack(new_stack);
|
ss.set_stack(new_stack);
|
||||||
//retval = dispatch(fn, plb);
|
//retval = dispatch(fn, plb);
|
||||||
retval = (*boxed_cast<Proxy_Function >(fn))(plb);
|
retval = (*boxed_cast<Const_Proxy_Function >(fn))(plb);
|
||||||
ss.set_stack(prev_stack);
|
ss.set_stack(prev_stack);
|
||||||
}
|
}
|
||||||
catch(const dispatch_error &e){
|
catch(const dispatch_error &e){
|
||||||
|
3
unittests/function_reassignment.chai
Normal file
3
unittests/function_reassignment.chai
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
var x = `+`
|
||||||
|
x = `-`
|
||||||
|
print(x(5,4))
|
1
unittests/function_reassignment.txt
Normal file
1
unittests/function_reassignment.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
1
|
1
unittests/invalid_function_assignment.chai
Normal file
1
unittests/invalid_function_assignment.chai
Normal file
@@ -0,0 +1 @@
|
|||||||
|
clone = `-`
|
1
unittests/invalid_function_assignment.txt
Normal file
1
unittests/invalid_function_assignment.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
Error: "Mismatched types in equation" in 'unittests/invalid_function_assignment.chai' at (1, 7)
|
2
unittests/invalid_function_reassignment.chai
Normal file
2
unittests/invalid_function_reassignment.chai
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
var x = 5
|
||||||
|
x = `-`
|
1
unittests/invalid_function_reassignment.txt
Normal file
1
unittests/invalid_function_reassignment.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
Error: "Mismatched types in equation" in 'unittests/invalid_function_reassignment.chai' at (2, 3)
|
Reference in New Issue
Block a user