Compare commits

...

4 Commits

Author SHA1 Message Date
Jason Turner
59df213e66 Update version to 4.2.0 2012-11-30 20:38:17 -07:00
Jason Turner
0ea8931b21 Add ability to call functions requiring arithmetic value conversions
- Conversions are only attempted on a dispatch
 - Conversions are only attempted after a normal dispatch has failed
 - Conversions are only attempted if exactly one function matches
   the signature of the parameters passed in - excluding the mismatched
   arithmetic parameters
 - This feature should not be relied on in performance critical code
   overhead is added for each function call that requires a conversion
   to execute, see the tests performed above.
2012-11-27 21:21:37 -07:00
Jason Turner
f24d376fa5 Update for release 4.1.1 2012-11-17 20:48:25 -07:00
Jason Turner
7917ea02dc Fix linux build error discovered with 4.0.0 release 2012-11-17 20:30:53 -07:00
8 changed files with 250 additions and 23 deletions

View File

@@ -17,7 +17,7 @@ set(CPACK_RESOURCE_FILE_README "${CMAKE_CURRENT_SOURCE_DIR}/readme.md")
set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/description.txt") set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/description.txt")
set(CPACK_PACKAGE_VERSION_MAJOR 4) set(CPACK_PACKAGE_VERSION_MAJOR 4)
set(CPACK_PACKAGE_VERSION_MINOR 1) set(CPACK_PACKAGE_VERSION_MINOR 2)
set(CPACK_PACKAGE_VERSION_PATCH 0) set(CPACK_PACKAGE_VERSION_PATCH 0)
set(CPACK_PACKAGE_EXECUTABLES "chai;ChaiScript Eval") set(CPACK_PACKAGE_EXECUTABLES "chai;ChaiScript Eval")
set(CPACK_PACKAGE_VENDOR "ChaiScript.com") set(CPACK_PACKAGE_VENDOR "ChaiScript.com")
@@ -212,6 +212,10 @@ if(BUILD_TESTING)
target_link_libraries(integer_literal_test ${LIBS}) target_link_libraries(integer_literal_test ${LIBS})
add_test(NAME Integer_Literal_Test COMMAND integer_literal_test) add_test(NAME Integer_Literal_Test COMMAND integer_literal_test)
add_executable(arithmetic_conversions_test unittests/arithmetic_conversions_test.cpp)
target_link_libraries(arithmetic_conversions_test ${LIBS})
add_test(NAME Arithmetic_Conversions_Test COMMAND arithmetic_conversions_test)
if (MULTITHREAD_SUPPORT_ENABLED) if (MULTITHREAD_SUPPORT_ENABLED)
add_executable(multithreaded_test unittests/multithreaded_test.cpp) add_executable(multithreaded_test unittests/multithreaded_test.cpp)
target_link_libraries(multithreaded_test ${LIBS}) target_link_libraries(multithreaded_test ${LIBS})

View File

@@ -631,9 +631,6 @@ namespace chaiscript
typedef typename String::size_type (String::*find_func_ptr)(const String &, typename String::size_type) const; typedef typename String::size_type (String::*find_func_ptr)(const String &, typename String::size_type) const;
typedef boost::function<int (const String *, const String &, int)> find_func; typedef boost::function<int (const String *, const String &, int)> find_func;
typedef String (String::*substr_ptr)(typename String::size_type, typename String::size_type) const;
typedef boost::function<String (const String *, int, int)> substr_func;
m->add(fun(find_func(detail::return_int(static_cast<find_func_ptr>(&String::find)))), "find"); m->add(fun(find_func(detail::return_int(static_cast<find_func_ptr>(&String::find)))), "find");
m->add(fun(find_func(detail::return_int(static_cast<find_func_ptr>(&String::rfind)))), "rfind"); m->add(fun(find_func(detail::return_int(static_cast<find_func_ptr>(&String::rfind)))), "rfind");
m->add(fun(find_func(detail::return_int(static_cast<find_func_ptr>(&String::find_first_of)))), "find_first_of"); m->add(fun(find_func(detail::return_int(static_cast<find_func_ptr>(&String::find_first_of)))), "find_first_of");
@@ -641,8 +638,7 @@ namespace chaiscript
m->add(fun(find_func(detail::return_int(static_cast<find_func_ptr>(&String::find_first_not_of)))), "find_first_not_of"); m->add(fun(find_func(detail::return_int(static_cast<find_func_ptr>(&String::find_first_not_of)))), "find_first_not_of");
m->add(fun(find_func(detail::return_int(static_cast<find_func_ptr>(&String::find_last_not_of)))), "find_last_not_of"); m->add(fun(find_func(detail::return_int(static_cast<find_func_ptr>(&String::find_last_not_of)))), "find_last_not_of");
m->add(fun(&detail::substr_helper<String, &String::substr>), "substr");
m->add(fun(&detail::substr_helper<String, static_cast<substr_ptr>(&String::substr)>), "substr");
m->add(fun(&String::c_str), "c_str"); m->add(fun(&String::c_str), "c_str");
m->add(fun(&String::data), "data"); m->add(fun(&String::data), "data");

View File

@@ -332,6 +332,46 @@ namespace chaiscript
validate_boxed_number(bv); validate_boxed_number(bv);
} }
Boxed_Number get_as(const Type_Info &inp_) const
{
if (inp_.bare_equal_type_info(typeid(int))) {
return Boxed_Number(get_as<int>());
} else if (inp_.bare_equal_type_info(typeid(double))) {
return Boxed_Number(get_as<double>());
} else if (inp_.bare_equal_type_info(typeid(float))) {
return Boxed_Number(get_as<float>());
} else if (inp_.bare_equal_type_info(typeid(long double))) {
return Boxed_Number(get_as<long double>());
} else if (inp_.bare_equal_type_info(typeid(char))) {
return Boxed_Number(get_as<char>());
} else if (inp_.bare_equal_type_info(typeid(unsigned int))) {
return Boxed_Number(get_as<unsigned int>());
} else if (inp_.bare_equal_type_info(typeid(long))) {
return Boxed_Number(get_as<long>());
} else if (inp_.bare_equal_type_info(typeid(unsigned long))) {
return Boxed_Number(get_as<unsigned long>());
} else if (inp_.bare_equal_type_info(typeid(boost::int8_t))) {
return Boxed_Number(get_as<boost::int8_t>());
} else if (inp_.bare_equal_type_info(typeid(boost::int16_t))) {
return Boxed_Number(get_as<boost::int16_t>());
} else if (inp_.bare_equal_type_info(typeid(boost::int32_t))) {
return Boxed_Number(get_as<boost::int32_t>());
} else if (inp_.bare_equal_type_info(typeid(boost::int64_t))) {
return Boxed_Number(get_as<boost::int64_t>());
} else if (inp_.bare_equal_type_info(typeid(boost::uint8_t))) {
return Boxed_Number(get_as<boost::uint8_t>());
} else if (inp_.bare_equal_type_info(typeid(boost::uint16_t))) {
return Boxed_Number(get_as<boost::uint16_t>());
} else if (inp_.bare_equal_type_info(typeid(boost::uint32_t))) {
return Boxed_Number(get_as<boost::uint32_t>());
} else if (inp_.bare_equal_type_info(typeid(boost::uint64_t))) {
return Boxed_Number(get_as<boost::uint64_t>());
} else {
throw boost::bad_any_cast();
}
}
template<typename Target> Target get_as() const template<typename Target> Target get_as() const
{ {
const Type_Info &inp_ = bv.get_type_info(); const Type_Info &inp_ = bv.get_type_info();

View File

@@ -1109,6 +1109,14 @@ namespace chaiscript
vec.push_back(t_f); vec.push_back(t_f);
std::stable_sort(vec.begin(), vec.end(), &function_less_than); std::stable_sort(vec.begin(), vec.end(), &function_less_than);
func_objs[t_name] = Proxy_Function(new Dispatch_Function(vec)); func_objs[t_name] = Proxy_Function(new Dispatch_Function(vec));
} else if (t_f->has_arithmetic_param()) {
// if the function is the only function but it also contains
// arithmetic operators, we must wrap it in a dispatch function
// to allow for automatic arithmetic type conversions
std::vector<Proxy_Function> vec;
vec.push_back(t_f);
funcs.insert(std::make_pair(t_name, vec));
func_objs[t_name] = Proxy_Function(new Dispatch_Function(vec));
} else { } else {
std::vector<Proxy_Function> vec; std::vector<Proxy_Function> vec;
vec.push_back(t_f); vec.push_back(t_f);

View File

@@ -85,6 +85,11 @@ namespace chaiscript
virtual bool operator==(const Proxy_Function_Base &) const = 0; virtual bool operator==(const Proxy_Function_Base &) const = 0;
virtual bool call_match(const std::vector<Boxed_Value> &vals) const = 0; virtual bool call_match(const std::vector<Boxed_Value> &vals) const = 0;
bool has_arithmetic_param() const
{
return m_has_arithmetic_param;
}
virtual std::vector<boost::shared_ptr<const Proxy_Function_Base> > get_contained_functions() const virtual std::vector<boost::shared_ptr<const Proxy_Function_Base> > get_contained_functions() const
{ {
return std::vector<boost::shared_ptr<const Proxy_Function_Base> >(); return std::vector<boost::shared_ptr<const Proxy_Function_Base> >();
@@ -117,23 +122,8 @@ namespace chaiscript
virtual std::string annotation() const = 0; virtual std::string annotation() const = 0;
protected: static bool compare_type_to_param(const Type_Info &ti, const Boxed_Value &bv)
virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params) const = 0;
Proxy_Function_Base(const std::vector<Type_Info> &t_types)
: m_types(t_types)
{ {
}
virtual bool compare_first_type(const Boxed_Value &bv) const
{
const std::vector<Type_Info> &types = get_param_types();
if (types.size() < 2)
{
return true;
}
const Type_Info &ti = types[1];
if (ti.is_undef() if (ti.is_undef()
|| ti.bare_equal(user_type<Boxed_Value>()) || ti.bare_equal(user_type<Boxed_Value>())
|| (!bv.get_type_info().is_undef() || (!bv.get_type_info().is_undef()
@@ -150,6 +140,36 @@ namespace chaiscript
return false; return false;
} }
} }
protected:
virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params) const = 0;
Proxy_Function_Base(const std::vector<Type_Info> &t_types)
: m_types(t_types), m_has_arithmetic_param(false)
{
for (int i = 1; i < m_types.size(); ++i)
{
if (m_types[i].is_arithmetic())
{
m_has_arithmetic_param = true;
return;
}
}
}
virtual bool compare_first_type(const Boxed_Value &bv) const
{
const std::vector<Type_Info> &types = get_param_types();
if (types.size() < 2)
{
return true;
}
const Type_Info &ti = types[1];
return compare_type_to_param(ti, bv);
}
bool compare_types(const std::vector<Type_Info> &tis, const std::vector<Boxed_Value> &bvs) const bool compare_types(const std::vector<Type_Info> &tis, const std::vector<Boxed_Value> &bvs) const
{ {
@@ -170,6 +190,8 @@ namespace chaiscript
} }
std::vector<Type_Info> m_types; std::vector<Type_Info> m_types;
bool m_has_arithmetic_param;
}; };
} }
@@ -605,6 +627,92 @@ namespace chaiscript
namespace dispatch namespace dispatch
{ {
namespace detail
{
template<typename FuncType>
bool types_match_except_for_arithmetic(const FuncType &t_func, const std::vector<Boxed_Value> &plist)
{
if (t_func->get_arity() != plist.size())
{
return false;
}
const std::vector<Type_Info> &types = t_func->get_param_types();
assert(plist.size() == types.size() - 1);
for (int i = 0; i < plist.size(); ++i)
{
if (Proxy_Function_Base::compare_type_to_param(types[i+1], plist[i])
|| (types[i+1].is_arithmetic() && plist[i].get_type_info().is_arithmetic()))
{
// types continue to match
} else {
return false;
}
}
// all types match
return true;
}
template<typename InItr>
Boxed_Value dispatch_with_conversions(InItr begin, const InItr &end, const std::vector<Boxed_Value> &plist)
{
InItr orig(begin);
InItr matching_func(end);
while (begin != end)
{
if (types_match_except_for_arithmetic(*begin, plist))
{
if (matching_func == end)
{
matching_func = begin;
} else {
// More than one function matches, not attempting
throw exception::dispatch_error(plist, std::vector<Const_Proxy_Function>(orig, end));
}
}
++begin;
}
if (matching_func == end)
{
// no appropriate function to attempt arithmetic type conversion on
throw exception::dispatch_error(plist, std::vector<Const_Proxy_Function>(orig, end));
}
std::vector<Boxed_Value> newplist;
const std::vector<Type_Info> &tis = (*matching_func)->get_param_types();
for (int i = 0; i < plist.size(); ++i)
{
if (tis[i+1].is_arithmetic()
&& plist[i].get_type_info().is_arithmetic()) {
newplist.push_back(Boxed_Number(plist[i]).get_as(tis[i+1]).bv);
} else {
newplist.push_back(plist[i]);
}
}
try {
return (*(*matching_func))(newplist);
} catch (const exception::bad_boxed_cast &) {
//parameter failed to cast
} catch (const exception::arity_error &) {
//invalid num params
} catch (const exception::guard_error &) {
//guard failed to allow the function to execute
}
throw exception::dispatch_error(plist, std::vector<Const_Proxy_Function>(orig, end));
}
}
/** /**
* Take a vector of functions and a vector of parameters. Attempt to execute * Take a vector of functions and a vector of parameters. Attempt to execute
@@ -634,7 +742,7 @@ namespace chaiscript
++begin; ++begin;
} }
throw exception::dispatch_error(plist, std::vector<Const_Proxy_Function>(orig, end)); return detail::dispatch_with_conversions(orig, end, plist);
} }
/** /**

View File

@@ -99,6 +99,12 @@ namespace chaiscript
|| (ti.m_bare_type_info && m_bare_type_info && *ti.m_bare_type_info == *m_bare_type_info); || (ti.m_bare_type_info && m_bare_type_info && *ti.m_bare_type_info == *m_bare_type_info);
} }
bool bare_equal_type_info(const std::type_info &ti) const
{
return m_bare_type_info != 0
&& (*m_bare_type_info) == ti;
}
bool is_const() const { return m_is_const; } bool is_const() const { return m_is_const; }
bool is_reference() const { return m_is_reference; } bool is_reference() const { return m_is_reference; }
bool is_void() const { return m_is_void; } bool is_void() const { return m_is_void; }

View File

@@ -1,3 +1,10 @@
Changes since 4.1.1
* Add support for automatic conversion of arithmetic types when possible
and when no ambiguous method dispatch exists.
Changes since 4.1.0
* Fix missed gcc build error in 4.1.0
Changes since 4.0.0 Changes since 4.0.0
* Fix sizing of numeric constants to match that of the C++ standard * Fix sizing of numeric constants to match that of the C++ standard
* Add support for u,ll,l,f suffixes for numeric constants * Add support for u,ll,l,f suffixes for numeric constants

View File

@@ -0,0 +1,58 @@
// Tests to make sure that type conversions happen only when they should
#include <chaiscript/chaiscript.hpp>
void f1(int)
{
}
void f4(std::string)
{
}
void f2(int)
{
}
void f3(double)
{
}
int main()
{
chaiscript::ChaiScript chai;
chai.add(chaiscript::fun(&f1), "f1");
chai.add(chaiscript::fun(&f2), "f2");
chai.add(chaiscript::fun(&f3), "f2");
chai.add(chaiscript::fun(&f1), "f3");
chai.add(chaiscript::fun(&f4), "f3");
// no overloads
chai.eval("f1(0)");
chai.eval("f1(0l)");
chai.eval("f1(0ul)");
chai.eval("f1(0ll)");
chai.eval("f1(0ull)");
chai.eval("f1(0.0)");
chai.eval("f1(0.0f)");
chai.eval("f1(0.0l)");
// expected overloads
chai.eval("f2(1)");
chai.eval("f2(1.0)");
// 1 non-arithmetic overload
chai.eval("f2(1.0)");
// this is the one call we expect to fail
try {
chai.eval("f2(1.0l)");
} catch (const std::exception &) {
return EXIT_SUCCESS;
}
// if the last one did not throw, we failed
return EXIT_FAILURE;
}