Compare commits
8 Commits
Release-5.
...
Release-5.
Author | SHA1 | Date | |
---|---|---|---|
![]() |
e4f4b64cc8 | ||
![]() |
59df213e66 | ||
![]() |
691e002f90 | ||
![]() |
47ab27fd11 | ||
![]() |
0ea8931b21 | ||
![]() |
f24d376fa5 | ||
![]() |
4754462048 | ||
![]() |
7917ea02dc |
@@ -2,7 +2,13 @@ cmake_minimum_required(VERSION 2.8)
|
||||
|
||||
project(chaiscript)
|
||||
|
||||
option(MULTITHREAD_SUPPORT_ENABLED "Multithreaded Support Enabled" TRUE)
|
||||
# MINGW does not yet support C++11's concurrency features
|
||||
if (MINGW)
|
||||
option(MULTITHREAD_SUPPORT_ENABLED "Multithreaded Support Enabled" FALSE)
|
||||
else()
|
||||
option(MULTITHREAD_SUPPORT_ENABLED "Multithreaded Support Enabled" TRUE)
|
||||
endif()
|
||||
|
||||
option(BUILD_MODULES "Build Extra Modules (stl, reflection)" TRUE)
|
||||
option(BUILD_SAMPLES "Build Samples Folder" FALSE)
|
||||
|
||||
@@ -17,8 +23,9 @@ 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 1)
|
||||
set(CPACK_PACKAGE_VERSION_MINOR 2)
|
||||
set(CPACK_PACKAGE_VERSION_PATCH 0)
|
||||
|
||||
set(CPACK_PACKAGE_EXECUTABLES "chai;ChaiScript Eval")
|
||||
set(CPACK_PACKAGE_VENDOR "ChaiScript.com")
|
||||
set(CPACK_PACKAGE_CONTACT "contact@chaiscript.com")
|
||||
@@ -39,7 +46,9 @@ include(CPack)
|
||||
|
||||
include(cmake/CheckCXX11Features.cmake)
|
||||
|
||||
find_library(READLINE_LIBRARY NAMES readline PATH /usr/lib /usr/local/lib /opt/local/lib)
|
||||
if(NOT MINGW)
|
||||
find_library(READLINE_LIBRARY NAMES readline PATH /usr/lib /usr/local/lib /opt/local/lib)
|
||||
endif()
|
||||
|
||||
if(HAS_CXX11_VARIADIC_TEMPLATES)
|
||||
message(STATUS "Variadic Template support detected")
|
||||
@@ -68,7 +77,7 @@ if(MSVC)
|
||||
endif()
|
||||
else()
|
||||
add_definitions(-Wall -Wextra -Wshadow -pedantic -std=c++0x)
|
||||
|
||||
|
||||
if (APPLE)
|
||||
add_definitions(-Wno-sign-compare)
|
||||
endif()
|
||||
@@ -88,6 +97,12 @@ else()
|
||||
set (EXTRA_LINKER_FLAGS )
|
||||
endif()
|
||||
|
||||
# limitations in MinGW require us to make an optimized build
|
||||
# for the sake of object sizes or something
|
||||
if (MINGW)
|
||||
add_definitions(-O3)
|
||||
endif()
|
||||
|
||||
include_directories(include)
|
||||
|
||||
|
||||
@@ -224,6 +239,10 @@ if(BUILD_TESTING)
|
||||
target_link_libraries(integer_literal_test ${LIBS})
|
||||
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)
|
||||
add_executable(multithreaded_test unittests/multithreaded_test.cpp)
|
||||
target_link_libraries(multithreaded_test ${LIBS})
|
||||
|
@@ -335,6 +335,46 @@ namespace chaiscript
|
||||
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(int8_t))) {
|
||||
return Boxed_Number(get_as<int8_t>());
|
||||
} else if (inp_.bare_equal_type_info(typeid(int16_t))) {
|
||||
return Boxed_Number(get_as<int16_t>());
|
||||
} else if (inp_.bare_equal_type_info(typeid(int32_t))) {
|
||||
return Boxed_Number(get_as<int32_t>());
|
||||
} else if (inp_.bare_equal_type_info(typeid(int64_t))) {
|
||||
return Boxed_Number(get_as<int64_t>());
|
||||
} else if (inp_.bare_equal_type_info(typeid(uint8_t))) {
|
||||
return Boxed_Number(get_as<uint8_t>());
|
||||
} else if (inp_.bare_equal_type_info(typeid(uint16_t))) {
|
||||
return Boxed_Number(get_as<uint16_t>());
|
||||
} else if (inp_.bare_equal_type_info(typeid(uint32_t))) {
|
||||
return Boxed_Number(get_as<uint32_t>());
|
||||
} else if (inp_.bare_equal_type_info(typeid(uint64_t))) {
|
||||
return Boxed_Number(get_as<uint64_t>());
|
||||
} else {
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
template<typename Target> Target get_as() const
|
||||
{
|
||||
const Type_Info &inp_ = bv.get_type_info();
|
||||
|
@@ -1116,6 +1116,14 @@ namespace chaiscript
|
||||
vec.push_back(t_f);
|
||||
std::stable_sort(vec.begin(), vec.end(), &function_less_than);
|
||||
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 {
|
||||
std::vector<Proxy_Function> vec;
|
||||
vec.push_back(t_f);
|
||||
|
@@ -54,12 +54,16 @@ namespace chaiscript
|
||||
virtual bool operator==(const Proxy_Function_Base &) 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<std::shared_ptr<const Proxy_Function_Base> > get_contained_functions() const
|
||||
{
|
||||
return std::vector<std::shared_ptr<const Proxy_Function_Base> >();
|
||||
}
|
||||
|
||||
|
||||
//! Return true if the function is a possible match
|
||||
//! to the passed in values
|
||||
bool filter(const std::vector<Boxed_Value> &vals) const
|
||||
@@ -86,23 +90,8 @@ namespace chaiscript
|
||||
|
||||
virtual std::string annotation() const = 0;
|
||||
|
||||
protected:
|
||||
virtual Boxed_Value do_call(const std::vector<Boxed_Value> ¶ms) const = 0;
|
||||
|
||||
Proxy_Function_Base(const std::vector<Type_Info> &t_types)
|
||||
: m_types(t_types)
|
||||
static bool compare_type_to_param(const Type_Info &ti, const Boxed_Value &bv)
|
||||
{
|
||||
}
|
||||
|
||||
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()
|
||||
|| ti.bare_equal(user_type<Boxed_Value>())
|
||||
|| (!bv.get_type_info().is_undef()
|
||||
@@ -119,6 +108,36 @@ namespace chaiscript
|
||||
return false;
|
||||
}
|
||||
}
|
||||
protected:
|
||||
virtual Boxed_Value do_call(const std::vector<Boxed_Value> ¶ms) 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
|
||||
{
|
||||
@@ -139,6 +158,8 @@ namespace chaiscript
|
||||
}
|
||||
|
||||
std::vector<Type_Info> m_types;
|
||||
bool m_has_arithmetic_param;
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
@@ -572,6 +593,92 @@ namespace chaiscript
|
||||
|
||||
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
|
||||
@@ -601,7 +708,7 @@ namespace chaiscript
|
||||
++begin;
|
||||
}
|
||||
|
||||
throw exception::dispatch_error(plist, std::vector<Const_Proxy_Function>(orig, end));
|
||||
return detail::dispatch_with_conversions(orig, end, plist);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -90,6 +90,12 @@ namespace chaiscript
|
||||
|| (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_reference() const { return m_is_reference; }
|
||||
bool is_void() const { return m_is_void; }
|
||||
|
@@ -1,3 +1,7 @@
|
||||
Changes since 5.1.0
|
||||
* Add support for automatic conversion of arithmetic types when possible
|
||||
and when no ambiguous method dispatch exists.
|
||||
|
||||
Changes since 5.0.0
|
||||
* Fix sizing of numeric constants to match that of the C++ standard
|
||||
* Add support for u,ll,l,f suffixes for numeric constants
|
||||
|
@@ -5,6 +5,7 @@
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#include <iostream>
|
||||
#include <ctime>
|
||||
|
||||
#include <chaiscript/chaiscript.hpp>
|
||||
#include <chaiscript/dispatchkit/bootstrap_stl.hpp>
|
||||
|
14
src/main.cpp
14
src/main.cpp
@@ -15,16 +15,20 @@
|
||||
#include <readline/readline.h>
|
||||
#include <readline/history.h>
|
||||
#else
|
||||
|
||||
char *mystrdup (const char *s) {
|
||||
char *d = static_cast<char*>(malloc (strlen (s) + 1)); // Space for length plus nul
|
||||
if (d == nullptr) return nullptr; // No memory
|
||||
strcpy (d,s); // Copy the characters
|
||||
return d; // Return the new string
|
||||
}
|
||||
|
||||
char* readline(const char* p)
|
||||
{
|
||||
std::string retval;
|
||||
std::cout << p ;
|
||||
std::getline(std::cin, retval);
|
||||
#ifdef CHAISCRIPT_MSVC
|
||||
return std::cin.eof() ? NULL : _strdup(retval.c_str());
|
||||
#else
|
||||
return std::cin.eof() ? NULL : strdup(retval.c_str());
|
||||
#endif
|
||||
return std::cin.eof() ? NULL : mystrdup(retval.c_str());
|
||||
}
|
||||
void add_history(const char*){}
|
||||
void using_history(){}
|
||||
|
58
unittests/arithmetic_conversions_test.cpp
Normal file
58
unittests/arithmetic_conversions_test.cpp
Normal 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;
|
||||
}
|
@@ -1,6 +1,7 @@
|
||||
// Tests to make sure that the order in which function dispatches occur is correct
|
||||
|
||||
#include <chaiscript/dispatchkit/type_info.hpp>
|
||||
#include <cstdlib>
|
||||
|
||||
void test_type(const chaiscript::Type_Info &ti, bool t_is_const, bool t_is_pointer, bool t_is_reference, bool t_is_void,
|
||||
bool t_is_undef)
|
||||
|
Reference in New Issue
Block a user