mirror of
https://github.com/ChaiScript/ChaiScript.git
synced 2025-12-06 08:46:53 +08:00
Merge branch 'best_practices' into develop
This commit is contained in:
commit
d0d08d2ed9
@ -145,13 +145,7 @@ endif()
|
||||
if(CMAKE_COMPILER_IS_GNUCC)
|
||||
execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpversion OUTPUT_VARIABLE GCC_VERSION)
|
||||
|
||||
if(GCC_VERSION VERSION_LESS 4.9)
|
||||
set(CPP14_FLAG "-std=c++1y")
|
||||
else()
|
||||
set(CPP14_FLAG "-std=c++1z")
|
||||
endif()
|
||||
else()
|
||||
set(CPP14_FLAG "-std=c++1z")
|
||||
set(CPP17_FLAG "-std=c++1z")
|
||||
endif()
|
||||
|
||||
if(MSVC)
|
||||
@ -178,7 +172,7 @@ if(MSVC)
|
||||
# how to workaround or fix the error. So I'm disabling it globally.
|
||||
add_definitions(/wd4503)
|
||||
else()
|
||||
add_definitions(-Wall -Wextra -Wconversion -Wshadow -Wnon-virtual-dtor -Wold-style-cast -Wcast-align -Wcast-qual -Wunused -Woverloaded-virtual -Wno-noexcept-type -Wpedantic ${CPP14_FLAG})
|
||||
add_definitions(-Wall -Wextra -Wconversion -Wshadow -Wnon-virtual-dtor -Wold-style-cast -Wcast-align -Wcast-qual -Wunused -Woverloaded-virtual -Wno-noexcept-type -Wpedantic ${CPP17_FLAG})
|
||||
|
||||
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
|
||||
add_definitions(-Weverything -Wno-c++98-compat-pedantic -Wno-c++98-compat -Wno-documentation -Wno-switch-enum -Wno-weak-vtables -Wno-missing-prototypes -Wno-padded -Wno-missing-noreturn -Wno-exit-time-destructors -Wno-documentation-unknown-command -Wno-unused-template -Wno-undef )
|
||||
@ -196,12 +190,12 @@ if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
|
||||
|
||||
if(USE_LIBCXX)
|
||||
add_definitions(-stdlib=libc++)
|
||||
set(LINKER_FLAGS "${LINKER_FLAGS} ${CPP14_FLAG} -stdlib=libc++")
|
||||
set(LINKER_FLAGS "${LINKER_FLAGS} ${CPP17_FLAG} -stdlib=libc++")
|
||||
else()
|
||||
set(LINKER_FLAGS "${LINKER_FLAGS} ${CPP14_FLAG}")
|
||||
set(LINKER_FLAGS "${LINKER_FLAGS} ${CPP17_FLAG}")
|
||||
endif()
|
||||
elseif(CMAKE_COMPILER_IS_GNUCC)
|
||||
set(LINKER_FLAGS "${LINKER_FLAGS} ${CPP14_FLAG}")
|
||||
set(LINKER_FLAGS "${LINKER_FLAGS} ${CPP17_FLAG}")
|
||||
endif()
|
||||
|
||||
# limitations in MinGW require us to make an optimized build
|
||||
@ -267,8 +261,8 @@ add_executable(chai src/main.cpp ${Chai_INCLUDES})
|
||||
target_link_libraries(chai ${LIBS} ${CHAISCRIPT_LIBS})
|
||||
|
||||
if(BUILD_SAMPLES)
|
||||
add_executable(example samples/example.cpp)
|
||||
target_link_libraries(example ${LIBS})
|
||||
add_executable(sanity_checks src/sanity_checks.cpp)
|
||||
target_link_libraries(sanity_checks ${LIBS})
|
||||
add_executable(test_num_exceptions samples/test_num_exceptions.cpp)
|
||||
target_link_libraries(test_num_exceptions ${LIBS} ${CHAISCRIPT_LIBS})
|
||||
add_executable(memory_leak_test samples/memory_leak_test.cpp)
|
||||
@ -329,37 +323,6 @@ endif()
|
||||
|
||||
if(BUILD_TESTING)
|
||||
|
||||
# Add catch tests macro
|
||||
macro(ADD_CATCH_TESTS executable)
|
||||
if (MSVC)
|
||||
file(TO_NATIVE_PATH "${QT_LIBRARY_DIR}" QT_LIB_PATH)
|
||||
set(NEWPATH "${QT_LIB_PATH};$ENV{PATH}")
|
||||
else()
|
||||
set(NEWPATH $ENV{PATH})
|
||||
endif()
|
||||
|
||||
get_target_property(target_files ${executable} SOURCES)
|
||||
|
||||
foreach(source ${target_files})
|
||||
if(NOT "${source}" MATCHES "/moc_.*cxx")
|
||||
string(REGEX MATCH .*cpp source "${source}")
|
||||
if(source)
|
||||
file(READ "${source}" contents)
|
||||
string(REGEX MATCHALL "TEST_CASE\\([ ]*\"[^\"]+\"" found_tests ${contents})
|
||||
foreach(hit ${found_tests})
|
||||
string(REGEX REPLACE "TEST_CASE\\([ ]*(\"[^\"]+\").*" "\\1" test_name ${hit})
|
||||
add_test(compiled.${test_name} "${executable}" ${test_name})
|
||||
set_tests_properties(compiled.${test_name} PROPERTIES TIMEOUT 660 ENVIRONMENT "PATH=${NEWPATH}")
|
||||
endforeach()
|
||||
endif()
|
||||
endif()
|
||||
endforeach()
|
||||
endmacro()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
option(UNIT_TEST_LIGHT "Unit tests light (expect module loading failures)" FALSE)
|
||||
|
||||
add_test(version_check chai -c "if(\"\\\${ version() };\\\${version_major()};\\\${version_minor()};\\\${version_patch()}\" != \"${CHAI_VERSION};${CPACK_PACKAGE_VERSION_MAJOR};${CPACK_PACKAGE_VERSION_MINOR};${CPACK_PACKAGE_VERSION_PATCH}\") { exit(-1) }")
|
||||
|
||||
@ -105,47 +105,47 @@ namespace chaiscript {
|
||||
}
|
||||
|
||||
struct Build_Info {
|
||||
constexpr static int version_major() noexcept
|
||||
[[nodiscard]] constexpr static int version_major() noexcept
|
||||
{
|
||||
return chaiscript::version_major;
|
||||
}
|
||||
|
||||
constexpr static int version_minor() noexcept
|
||||
[[nodiscard]] constexpr static int version_minor() noexcept
|
||||
{
|
||||
return chaiscript::version_minor;
|
||||
}
|
||||
|
||||
constexpr static int version_patch() noexcept
|
||||
[[nodiscard]] constexpr static int version_patch() noexcept
|
||||
{
|
||||
return chaiscript::version_patch;
|
||||
}
|
||||
|
||||
static std::string version()
|
||||
[[nodiscard]] static std::string version()
|
||||
{
|
||||
return std::to_string(version_major()) + '.' + std::to_string(version_minor()) + '.' + std::to_string(version_patch());
|
||||
}
|
||||
|
||||
static std::string compiler_id()
|
||||
[[nodiscard]] static std::string compiler_id()
|
||||
{
|
||||
return compiler_name() + '-' + compiler_version();
|
||||
}
|
||||
|
||||
static std::string build_id()
|
||||
[[nodiscard]] static std::string build_id()
|
||||
{
|
||||
return compiler_id() + (debug_build()?"-Debug":"-Release");
|
||||
}
|
||||
|
||||
static std::string compiler_version()
|
||||
[[nodiscard]] static std::string compiler_version()
|
||||
{
|
||||
return chaiscript::compiler_version;
|
||||
}
|
||||
|
||||
static std::string compiler_name()
|
||||
[[nodiscard]] static std::string compiler_name()
|
||||
{
|
||||
return chaiscript::compiler_name;
|
||||
}
|
||||
|
||||
constexpr static bool debug_build() noexcept
|
||||
[[nodiscard]] constexpr static bool debug_build() noexcept
|
||||
{
|
||||
return chaiscript::debug_build;
|
||||
}
|
||||
@ -153,7 +153,7 @@ namespace chaiscript {
|
||||
|
||||
|
||||
template<typename T>
|
||||
constexpr auto parse_num(const std::string_view t_str) noexcept -> typename std::enable_if<std::is_integral<T>::value, T>::type
|
||||
[[nodiscard]] constexpr auto parse_num(const std::string_view t_str) noexcept -> typename std::enable_if<std::is_integral<T>::value, T>::type
|
||||
{
|
||||
T t = 0;
|
||||
for (const auto c : t_str) {
|
||||
@ -168,7 +168,7 @@ namespace chaiscript {
|
||||
|
||||
|
||||
template<typename T>
|
||||
auto parse_num(const std::string_view t_str) -> typename std::enable_if<!std::is_integral<T>::value, T>::type
|
||||
[[nodiscard]] auto parse_num(const std::string_view t_str) -> typename std::enable_if<!std::is_integral<T>::value, T>::type
|
||||
{
|
||||
T t = 0;
|
||||
T base{};
|
||||
@ -217,16 +217,26 @@ namespace chaiscript {
|
||||
}
|
||||
}
|
||||
return exponent ? base * std::pow(T(10), t * static_cast<T>(exponent)) : t;
|
||||
|
||||
|
||||
}
|
||||
|
||||
struct str_equal {
|
||||
[[nodiscard]] bool operator()(const std::string &t_lhs, const std::string &t_rhs) const noexcept {
|
||||
return t_lhs == t_rhs;
|
||||
}
|
||||
template<typename LHS, typename RHS>
|
||||
[[nodiscard]] constexpr bool operator()(const LHS &t_lhs, const RHS &t_rhs) const noexcept {
|
||||
return std::equal(t_lhs.begin(), t_lhs.end(), t_rhs.begin(), t_rhs.end());
|
||||
}
|
||||
struct is_transparent{};
|
||||
};
|
||||
|
||||
|
||||
struct str_less {
|
||||
bool operator()(const std::string &t_lhs, const std::string &t_rhs) const noexcept {
|
||||
[[nodiscard]] bool operator()(const std::string &t_lhs, const std::string &t_rhs) const noexcept {
|
||||
return t_lhs < t_rhs;
|
||||
}
|
||||
template<typename LHS, typename RHS>
|
||||
constexpr bool operator()(const LHS &t_lhs, const RHS &t_rhs) const noexcept {
|
||||
[[nodiscard]] constexpr bool operator()(const LHS &t_lhs, const RHS &t_rhs) const noexcept {
|
||||
return std::lexicographical_compare(t_lhs.begin(), t_lhs.end(), t_rhs.begin(), t_rhs.end());
|
||||
}
|
||||
struct is_transparent{};
|
||||
@ -240,6 +250,37 @@ namespace chaiscript {
|
||||
External_Scripts
|
||||
};
|
||||
|
||||
template<typename From, typename To>
|
||||
struct is_nothrow_forward_constructible
|
||||
: std::bool_constant<noexcept(To{std::declval<From>()})>
|
||||
{
|
||||
};
|
||||
|
||||
template< class From, class To >
|
||||
inline constexpr bool is_nothrow_forward_constructible_v
|
||||
= is_nothrow_forward_constructible<From, To>::value;
|
||||
|
||||
template<typename Container, typename ... T>
|
||||
[[nodiscard]] constexpr auto make_container(T && ... t)
|
||||
{
|
||||
Container c;
|
||||
c.reserve(sizeof...(t));
|
||||
(c.push_back(std::forward<T>(t)), ...);
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
template<typename ... T>
|
||||
[[nodiscard]] auto make_vector(T && ... t)
|
||||
{
|
||||
using container_type =
|
||||
std::vector<std::common_type_t<std::decay_t<T>...>>;
|
||||
|
||||
return make_container<container_type>(std::forward<T>(t)...);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static inline std::vector<Options> default_options()
|
||||
{
|
||||
#ifdef CHAISCRIPT_NO_DYNLOAD
|
||||
|
||||
@ -42,7 +42,7 @@ namespace chaiscript
|
||||
{
|
||||
public:
|
||||
|
||||
static ModulePtr library()
|
||||
[[nodiscard]] static ModulePtr library()
|
||||
{
|
||||
auto lib = std::make_shared<Module>();
|
||||
bootstrap::Bootstrap::bootstrap(*lib);
|
||||
|
||||
@ -83,7 +83,7 @@ namespace chaiscript {
|
||||
public:
|
||||
// construct/copy/destruct
|
||||
constexpr Any() noexcept = default;
|
||||
Any(Any &&) = default;
|
||||
Any(Any &&) noexcept = default;
|
||||
Any &operator=(Any &&t_any) = default;
|
||||
|
||||
Any(const Any &t_any)
|
||||
@ -128,7 +128,7 @@ namespace chaiscript {
|
||||
// queries
|
||||
bool empty() const noexcept
|
||||
{
|
||||
return !bool(m_data);
|
||||
return !static_cast<bool>(m_data);
|
||||
}
|
||||
|
||||
const std::type_info & type() const noexcept
|
||||
|
||||
@ -152,7 +152,7 @@ namespace chaiscript
|
||||
|
||||
/// 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)
|
||||
std::shared_ptr<std::remove_const_t<Type>> shared_ptr_unconst_clone(const std::shared_ptr<std::add_const_t<Type>> &p)
|
||||
{
|
||||
return std::const_pointer_cast<typename std::remove_const<Type>::type>(p);
|
||||
}
|
||||
@ -242,7 +242,7 @@ 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
|
||||
static Boxed_Value bind_function(const std::vector<Boxed_Value> ¶ms)
|
||||
static Boxed_Value bind_function(const Function_Params ¶ms)
|
||||
{
|
||||
if (params.empty()) {
|
||||
throw exception::arity_error(0, 1);
|
||||
|
||||
@ -178,13 +178,6 @@ namespace chaiscript
|
||||
detail::input_range_type_impl<Bidir_Range<ContainerType, typename ContainerType::iterator> >(type,m);
|
||||
detail::input_range_type_impl<Bidir_Range<const ContainerType, typename ContainerType::const_iterator> >("Const_" + type,m);
|
||||
}
|
||||
template<typename ContainerType>
|
||||
ModulePtr input_range_type(const std::string &type)
|
||||
{
|
||||
auto m = std::make_shared<Module>();
|
||||
input_range_type<ContainerType>(type, *m);
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
/// Add random_access_container concept to the given ContainerType
|
||||
@ -197,7 +190,7 @@ namespace chaiscript
|
||||
m.add(
|
||||
fun(
|
||||
[](ContainerType &c, int index) -> typename ContainerType::reference {
|
||||
/// \todo we are prefering to keep the key as 'int' to avoid runtime conversions
|
||||
/// \todo we are preferring to keep the key as 'int' to avoid runtime conversions
|
||||
/// during dispatch. reevaluate
|
||||
return c.at(static_cast<typename ContainerType::size_type>(index));
|
||||
}), "[]");
|
||||
@ -205,19 +198,11 @@ namespace chaiscript
|
||||
m.add(
|
||||
fun(
|
||||
[](const ContainerType &c, int index) -> typename ContainerType::const_reference {
|
||||
/// \todo we are prefering to keep the key as 'int' to avoid runtime conversions
|
||||
/// \todo we are preferring to keep the key as 'int' to avoid runtime conversions
|
||||
/// during dispatch. reevaluate
|
||||
return c.at(static_cast<typename ContainerType::size_type>(index));
|
||||
}), "[]");
|
||||
}
|
||||
template<typename ContainerType>
|
||||
ModulePtr random_access_container_type(const std::string &type)
|
||||
{
|
||||
auto m = std::make_shared<Module>();
|
||||
random_access_container_type<ContainerType>(type, *m);
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// Add assignable concept to the given ContainerType
|
||||
@ -228,14 +213,6 @@ namespace chaiscript
|
||||
copy_constructor<ContainerType>(type, m);
|
||||
operators::assign<ContainerType>(m);
|
||||
}
|
||||
template<typename ContainerType>
|
||||
ModulePtr assignable_type(const std::string &type)
|
||||
{
|
||||
auto m = std::make_shared<Module>();
|
||||
assignable_type<ContainerType>(type, *m);
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
/// Add container resize concept to the given ContainerType
|
||||
/// http://www.cplusplus.com/reference/stl/
|
||||
@ -245,14 +222,6 @@ namespace chaiscript
|
||||
m.add(fun([](ContainerType *a, typename ContainerType::size_type n, const typename ContainerType::value_type& val) { return a->resize(n, val); } ), "resize");
|
||||
m.add(fun([](ContainerType *a, typename ContainerType::size_type n) { return a->resize(n); } ), "resize");
|
||||
}
|
||||
template<typename ContainerType>
|
||||
ModulePtr resizable_type(const std::string &type)
|
||||
{
|
||||
auto m = std::make_shared<Module>();
|
||||
resizable_type<ContainerType>(type, *m);
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
/// Add container reserve concept to the given ContainerType
|
||||
/// http://www.cplusplus.com/reference/stl/
|
||||
@ -262,14 +231,6 @@ namespace chaiscript
|
||||
m.add(fun([](ContainerType *a, typename ContainerType::size_type n) { return a->reserve(n); } ), "reserve");
|
||||
m.add(fun([](const ContainerType *a) { return a->capacity(); } ), "capacity");
|
||||
}
|
||||
template<typename ContainerType>
|
||||
ModulePtr reservable_type(const std::string &type)
|
||||
{
|
||||
auto m = std::make_shared<Module>();
|
||||
reservable_type<ContainerType>(type, *m);
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
/// Add container concept to the given ContainerType
|
||||
/// http://www.sgi.com/tech/stl/Container.html
|
||||
@ -280,14 +241,6 @@ namespace chaiscript
|
||||
m.add(fun([](const ContainerType *a) { return a->empty(); } ), "empty");
|
||||
m.add(fun([](ContainerType *a) { a->clear(); } ), "clear");
|
||||
}
|
||||
template <typename ContainerType>
|
||||
ModulePtr container_type(const std::string& type)
|
||||
{
|
||||
auto m = std::make_shared<Module>();
|
||||
container_type<ContainerType>(type, *m);
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
/// Add default constructable concept to the given Type
|
||||
/// http://www.sgi.com/tech/stl/DefaultConstructible.html
|
||||
@ -296,15 +249,6 @@ namespace chaiscript
|
||||
{
|
||||
m.add(constructor<Type ()>(), type);
|
||||
}
|
||||
template <typename Type>
|
||||
ModulePtr default_constructible_type(const std::string& type)
|
||||
{
|
||||
auto m = std::make_shared<Module>();
|
||||
default_constructible_type<Type>(type, *m);
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// Add sequence concept to the given ContainerType
|
||||
/// http://www.sgi.com/tech/stl/Sequence.html
|
||||
@ -322,13 +266,6 @@ namespace chaiscript
|
||||
|
||||
m.add(fun(&detail::erase_at<ContainerType>), "erase_at");
|
||||
}
|
||||
template <typename ContainerType>
|
||||
ModulePtr sequence_type(const std::string &type)
|
||||
{
|
||||
auto m = std::make_shared<Module>();
|
||||
sequence_type<ContainerType>(type, *m);
|
||||
return m;
|
||||
}
|
||||
|
||||
/// Add back insertion sequence concept to the given ContainerType
|
||||
/// http://www.sgi.com/tech/stl/BackInsertionSequence.html
|
||||
@ -380,14 +317,6 @@ namespace chaiscript
|
||||
|
||||
m.add(fun(&ContainerType::pop_back), "pop_back");
|
||||
}
|
||||
template<typename ContainerType>
|
||||
ModulePtr back_insertion_sequence_type(const std::string &type)
|
||||
{
|
||||
auto m = std::make_shared<Module>();
|
||||
back_insertion_sequence_type<ContainerType>(type, *m);
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// Front insertion sequence
|
||||
@ -442,14 +371,6 @@ namespace chaiscript
|
||||
|
||||
m.add(fun(static_cast<pop_ptr>(&ContainerType::pop_front)), "pop_front");
|
||||
}
|
||||
template<typename ContainerType>
|
||||
ModulePtr front_insertion_sequence_type(const std::string &type)
|
||||
{
|
||||
auto m = std::make_shared<Module>();
|
||||
front_insertion_sequence_type<ContainerType>(type, *m);
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
/// bootstrap a given PairType
|
||||
/// http://www.sgi.com/tech/stl/pair.html
|
||||
@ -464,14 +385,6 @@ namespace chaiscript
|
||||
basic_constructors<PairType>(type, m);
|
||||
m.add(constructor<PairType (const typename PairType::first_type &, const typename PairType::second_type &)>(), type);
|
||||
}
|
||||
template<typename PairType>
|
||||
ModulePtr pair_type(const std::string &type)
|
||||
{
|
||||
auto m = std::make_shared<Module>();
|
||||
pair_type<PairType>(type, *m);
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// Add pair associative container concept to the given ContainerType
|
||||
@ -482,14 +395,6 @@ namespace chaiscript
|
||||
{
|
||||
pair_type<typename ContainerType::value_type>(type + "_Pair", m);
|
||||
}
|
||||
template<typename ContainerType>
|
||||
ModulePtr pair_associative_container_type(const std::string &type)
|
||||
{
|
||||
auto m = std::make_shared<Module>();
|
||||
pair_associative_container_type<ContainerType>(type, *m);
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
/// Add unique associative container concept to the given ContainerType
|
||||
/// http://www.sgi.com/tech/stl/UniqueAssociativeContainer.html
|
||||
@ -513,14 +418,6 @@ namespace chaiscript
|
||||
}
|
||||
}());
|
||||
}
|
||||
template<typename ContainerType>
|
||||
ModulePtr unique_associative_container_type(const std::string &type)
|
||||
{
|
||||
auto m = std::make_shared<Module>();
|
||||
unique_associative_container_type<ContainerType>(type, *m);
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
/// Add a MapType container
|
||||
/// http://www.sgi.com/tech/stl/Map.html
|
||||
@ -568,14 +465,6 @@ namespace chaiscript
|
||||
pair_associative_container_type<MapType>(type, m);
|
||||
input_range_type<MapType>(type, m);
|
||||
}
|
||||
template<typename MapType>
|
||||
ModulePtr map_type(const std::string &type)
|
||||
{
|
||||
auto m = std::make_shared<Module>();
|
||||
map_type<MapType>(type, *m);
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
/// http://www.sgi.com/tech/stl/List.html
|
||||
template<typename ListType>
|
||||
@ -592,14 +481,6 @@ namespace chaiscript
|
||||
assignable_type<ListType>(type, m);
|
||||
input_range_type<ListType>(type, m);
|
||||
}
|
||||
template<typename ListType>
|
||||
ModulePtr list_type(const std::string &type)
|
||||
{
|
||||
auto m = std::make_shared<Module>();
|
||||
list_type<ListType>(type, m);
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
/// Create a vector type with associated concepts
|
||||
/// http://www.sgi.com/tech/stl/Vector.html
|
||||
@ -665,13 +546,6 @@ namespace chaiscript
|
||||
);
|
||||
}
|
||||
}
|
||||
template<typename VectorType>
|
||||
ModulePtr vector_type(const std::string &type)
|
||||
{
|
||||
auto m = std::make_shared<Module>();
|
||||
vector_type<VectorType>(type, *m);
|
||||
return m;
|
||||
}
|
||||
|
||||
/// Add a String container
|
||||
/// http://www.sgi.com/tech/stl/basic_string.html
|
||||
@ -717,14 +591,6 @@ namespace chaiscript
|
||||
m.add(fun([](const String *s) { return s->data(); } ), "data");
|
||||
m.add(fun([](const String *s, size_t pos, size_t len) { return s->substr(pos, len); } ), "substr");
|
||||
}
|
||||
template<typename String>
|
||||
ModulePtr string_type(const std::string &type)
|
||||
{
|
||||
auto m = std::make_shared<Module>();
|
||||
string_type<String>(type, *m);
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// Add a MapType container
|
||||
@ -738,13 +604,6 @@ namespace chaiscript
|
||||
m.add(fun([](FutureType &t) { return t.get(); }), "get");
|
||||
m.add(fun(&FutureType::wait), "wait");
|
||||
}
|
||||
template<typename FutureType>
|
||||
ModulePtr future_type(const std::string &type)
|
||||
{
|
||||
auto m = std::make_shared<Module>();
|
||||
future_type<FutureType>(type, *m);
|
||||
return m;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -194,7 +194,7 @@ namespace chaiscript
|
||||
public:
|
||||
/// Basic Boxed_Value constructor
|
||||
template<typename T,
|
||||
typename = typename std::enable_if<!std::is_same<Boxed_Value, typename std::decay<T>::type>::value>::type>
|
||||
typename = std::enable_if_t<!std::is_same_v<Boxed_Value, std::decay_t<T>>>>
|
||||
explicit Boxed_Value(T &&t, bool t_return_value = false)
|
||||
: m_data(Object_Data::get(std::forward<T>(t), t_return_value))
|
||||
{
|
||||
|
||||
@ -36,6 +36,7 @@
|
||||
#include "proxy_functions.hpp"
|
||||
#include "type_info.hpp"
|
||||
#include "short_alloc.hpp"
|
||||
#include "../utility/quick_flat_map.hpp"
|
||||
|
||||
namespace chaiscript {
|
||||
class Boxed_Number;
|
||||
@ -313,14 +314,14 @@ namespace chaiscript
|
||||
return arity;
|
||||
}
|
||||
|
||||
bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const noexcept override
|
||||
bool call_match(const Function_Params &vals, const Type_Conversions_State &t_conversions) const noexcept override
|
||||
{
|
||||
return std::any_of(std::begin(m_funcs), std::end(m_funcs),
|
||||
[&vals, &t_conversions](const Proxy_Function &f){ return f->call_match(vals, t_conversions); });
|
||||
}
|
||||
|
||||
protected:
|
||||
Boxed_Value do_call(const std::vector<Boxed_Value> ¶ms, const Type_Conversions_State &t_conversions) const override
|
||||
Boxed_Value do_call(const Function_Params ¶ms, const Type_Conversions_State &t_conversions) const override
|
||||
{
|
||||
return dispatch::dispatch(m_funcs, params, t_conversions);
|
||||
}
|
||||
@ -388,7 +389,7 @@ namespace chaiscript
|
||||
using SmallVector = std::vector<T>;
|
||||
|
||||
|
||||
using Scope = SmallVector<std::pair<std::string, Boxed_Value>>;
|
||||
using Scope = utility::QuickFlatMap<std::string, Boxed_Value, str_equal>;
|
||||
using StackData = SmallVector<Scope>;
|
||||
using Stacks = SmallVector<StackData>;
|
||||
using Call_Param_List = SmallVector<Boxed_Value>;
|
||||
@ -409,24 +410,13 @@ namespace chaiscript
|
||||
void push_stack()
|
||||
{
|
||||
stacks.emplace_back(1);
|
||||
// stacks.emplace_back(StackData(1, Scope(scope_allocator), stack_data_allocator));
|
||||
}
|
||||
|
||||
void push_call_params()
|
||||
{
|
||||
call_params.emplace_back();
|
||||
// call_params.emplace_back(Call_Param_List(call_param_list_allocator));
|
||||
}
|
||||
|
||||
//Scope::allocator_type::arena_type scope_allocator;
|
||||
//StackData::allocator_type::arena_type stack_data_allocator;
|
||||
//Stacks::allocator_type::arena_type stacks_allocator;
|
||||
//Call_Param_List::allocator_type::arena_type call_param_list_allocator;
|
||||
//Call_Params::allocator_type::arena_type call_params_allocator;
|
||||
|
||||
// Stacks stacks = Stacks(stacks_allocator);
|
||||
// Call_Params call_params = Call_Params(call_params_allocator);
|
||||
|
||||
Stacks stacks;
|
||||
Call_Params call_params;
|
||||
|
||||
@ -440,14 +430,14 @@ namespace chaiscript
|
||||
|
||||
public:
|
||||
using Type_Name_Map = std::map<std::string, chaiscript::Type_Info, str_less>;
|
||||
using Scope = std::vector<std::pair<std::string, Boxed_Value>>;
|
||||
using Scope = utility::QuickFlatMap<std::string, Boxed_Value, str_equal>;
|
||||
using StackData = Stack_Holder::StackData;
|
||||
|
||||
struct State
|
||||
{
|
||||
std::vector<std::pair<std::string, std::shared_ptr<std::vector<Proxy_Function>>>> m_functions;
|
||||
std::vector<std::pair<std::string, Proxy_Function>> m_function_objects;
|
||||
std::vector<std::pair<std::string, Boxed_Value>> m_boxed_functions;
|
||||
utility::QuickFlatMap<std::string, std::shared_ptr<std::vector<Proxy_Function>>, str_equal> m_functions;
|
||||
utility::QuickFlatMap<std::string, Proxy_Function, str_equal> m_function_objects;
|
||||
utility::QuickFlatMap<std::string, Boxed_Value, str_equal> m_boxed_functions;
|
||||
std::map<std::string, Boxed_Value, str_less> m_global_objects;
|
||||
Type_Name_Map m_types;
|
||||
};
|
||||
@ -486,12 +476,7 @@ namespace chaiscript
|
||||
|
||||
for (auto stack_elem = stack.rbegin(); stack_elem != stack.rend(); ++stack_elem)
|
||||
{
|
||||
auto itr = std::find_if(stack_elem->begin(), stack_elem->end(),
|
||||
[&](const std::pair<std::string, Boxed_Value> &o) {
|
||||
return o.first == name;
|
||||
});
|
||||
|
||||
if (itr != stack_elem->end())
|
||||
if (auto itr = stack_elem->find(name); itr != stack_elem->end())
|
||||
{
|
||||
itr->second = std::move(obj);
|
||||
return;
|
||||
@ -504,38 +489,32 @@ namespace chaiscript
|
||||
/// Adds a named object to the current scope
|
||||
/// \warning This version does not check the validity of the name
|
||||
/// it is meant for internal use only
|
||||
Boxed_Value &add_get_object(const std::string &t_name, Boxed_Value obj, Stack_Holder &t_holder)
|
||||
Boxed_Value &add_get_object(std::string t_name, Boxed_Value obj, Stack_Holder &t_holder)
|
||||
{
|
||||
auto &stack_elem = get_stack_data(t_holder).back();
|
||||
|
||||
if (std::any_of(stack_elem.begin(), stack_elem.end(),
|
||||
[&](const std::pair<std::string, Boxed_Value> &o) {
|
||||
return o.first == t_name;
|
||||
}))
|
||||
if (auto result = stack_elem.insert(std::pair{std::move(t_name), std::move(obj)}); result.second)
|
||||
{
|
||||
throw chaiscript::exception::name_conflict_error(t_name);
|
||||
return result.first->second;
|
||||
} else {
|
||||
//insert failed
|
||||
throw chaiscript::exception::name_conflict_error(result.first->first);
|
||||
}
|
||||
|
||||
return stack_elem.emplace_back(t_name, std::move(obj)).second;
|
||||
}
|
||||
|
||||
|
||||
/// Adds a named object to the current scope
|
||||
/// \warning This version does not check the validity of the name
|
||||
/// it is meant for internal use only
|
||||
void add_object(const std::string &t_name, Boxed_Value obj, Stack_Holder &t_holder)
|
||||
void add_object(std::string t_name, Boxed_Value obj, Stack_Holder &t_holder)
|
||||
{
|
||||
auto &stack_elem = get_stack_data(t_holder).back();
|
||||
|
||||
if (std::any_of(stack_elem.begin(), stack_elem.end(),
|
||||
[&](const std::pair<std::string, Boxed_Value> &o) {
|
||||
return o.first == t_name;
|
||||
}))
|
||||
if (auto result = stack_elem.insert(std::pair{std::move(t_name), std::move(obj)}); !result.second)
|
||||
{
|
||||
throw chaiscript::exception::name_conflict_error(t_name);
|
||||
//insert failed
|
||||
throw chaiscript::exception::name_conflict_error(result.first->first);
|
||||
}
|
||||
|
||||
stack_elem.emplace_back(t_name, std::move(obj));
|
||||
}
|
||||
|
||||
|
||||
@ -566,46 +545,30 @@ namespace chaiscript
|
||||
}
|
||||
|
||||
/// Adds a new global (non-const) shared object, between all the threads
|
||||
Boxed_Value add_global_no_throw(const Boxed_Value &obj, const std::string &name)
|
||||
Boxed_Value add_global_no_throw(Boxed_Value obj, std::string name)
|
||||
{
|
||||
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
|
||||
|
||||
const auto itr = m_state.m_global_objects.find(name);
|
||||
if (itr == m_state.m_global_objects.end())
|
||||
{
|
||||
m_state.m_global_objects.insert(std::make_pair(name, obj));
|
||||
return obj;
|
||||
} else {
|
||||
return itr->second;
|
||||
}
|
||||
return m_state.m_global_objects.insert(std::pair{std::move(name), std::move(obj)}).first->second;
|
||||
}
|
||||
|
||||
|
||||
/// Adds a new global (non-const) shared object, between all the threads
|
||||
void add_global(const Boxed_Value &obj, const std::string &name)
|
||||
void add_global(Boxed_Value obj, std::string name)
|
||||
{
|
||||
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
|
||||
|
||||
if (m_state.m_global_objects.find(name) != m_state.m_global_objects.end())
|
||||
{
|
||||
throw chaiscript::exception::name_conflict_error(name);
|
||||
} else {
|
||||
m_state.m_global_objects.insert(std::make_pair(name, obj));
|
||||
if (auto result = m_state.m_global_objects.insert(std::pair{std::move(name), std::move(obj)}); !result.second) {
|
||||
// insert failed
|
||||
throw chaiscript::exception::name_conflict_error(result.first->first);
|
||||
}
|
||||
}
|
||||
|
||||
/// Updates an existing global shared object or adds a new global shared object if not found
|
||||
void set_global(const Boxed_Value &obj, const std::string &name)
|
||||
void set_global(Boxed_Value obj, std::string name)
|
||||
{
|
||||
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
|
||||
|
||||
const auto itr = m_state.m_global_objects.find(name);
|
||||
if (itr != m_state.m_global_objects.end())
|
||||
{
|
||||
itr->second.assign(obj);
|
||||
} else {
|
||||
m_state.m_global_objects.insert(std::make_pair(name, obj));
|
||||
}
|
||||
m_state.m_global_objects.insert_or_assign(std::move(name), std::move(obj));
|
||||
}
|
||||
|
||||
/// Adds a new scope to the stack
|
||||
@ -688,7 +651,7 @@ namespace chaiscript
|
||||
} else if ((loc & static_cast<uint_fast32_t>(Loc::is_local)) != 0u) {
|
||||
auto &stack = get_stack_data(t_holder);
|
||||
|
||||
return stack[stack.size() - 1 - ((loc & static_cast<uint_fast32_t>(Loc::stack_mask)) >> 16)][loc & static_cast<uint_fast32_t>(Loc::loc_mask)].second;
|
||||
return stack[stack.size() - 1 - ((loc & static_cast<uint_fast32_t>(Loc::stack_mask)) >> 16)].at_index(loc & static_cast<uint_fast32_t>(Loc::loc_mask));
|
||||
}
|
||||
|
||||
// Is the value we are looking for a global or function?
|
||||
@ -782,9 +745,7 @@ namespace chaiscript
|
||||
|
||||
const auto &funs = get_functions_int();
|
||||
|
||||
auto itr = find_keyed_value(funs, t_name, t_hint);
|
||||
|
||||
if (itr != funs.end())
|
||||
if (const auto itr = funs.find(t_name, t_hint); itr != funs.end())
|
||||
{
|
||||
return std::make_pair(std::distance(funs.begin(), itr), itr->second);
|
||||
} else {
|
||||
@ -808,9 +769,7 @@ namespace chaiscript
|
||||
{
|
||||
const auto &funs = get_boxed_functions_int();
|
||||
|
||||
auto itr = find_keyed_value(funs, t_name, t_hint);
|
||||
|
||||
if (itr != funs.end())
|
||||
if (const auto itr = funs.find(t_name, t_hint); itr != funs.end())
|
||||
{
|
||||
return std::make_pair(std::distance(funs.begin(), itr), itr->second);
|
||||
} else {
|
||||
@ -824,8 +783,7 @@ namespace chaiscript
|
||||
{
|
||||
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
|
||||
|
||||
const auto &functions = get_functions_int();
|
||||
return find_keyed_value(functions, name) != functions.end();
|
||||
return get_functions_int().count(name) > 0;
|
||||
}
|
||||
|
||||
/// \returns All values in the local thread state in the parent scope, or if it doesn't exist,
|
||||
@ -935,7 +893,7 @@ namespace chaiscript
|
||||
return m_conversions;
|
||||
}
|
||||
|
||||
static bool is_attribute_call(const std::vector<Proxy_Function> &t_funs, const std::vector<Boxed_Value> &t_params,
|
||||
static bool is_attribute_call(const std::vector<Proxy_Function> &t_funs, const Function_Params &t_params,
|
||||
bool t_has_params, const Type_Conversions_State &t_conversions) noexcept
|
||||
{
|
||||
if (!t_has_params || t_params.empty()) {
|
||||
@ -956,17 +914,17 @@ namespace chaiscript
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4715)
|
||||
#endif
|
||||
Boxed_Value call_member(const std::string &t_name, std::atomic_uint_fast32_t &t_loc, const std::vector<Boxed_Value> ¶ms, bool t_has_params,
|
||||
Boxed_Value call_member(const std::string &t_name, std::atomic_uint_fast32_t &t_loc, const Function_Params ¶ms, bool t_has_params,
|
||||
const Type_Conversions_State &t_conversions)
|
||||
{
|
||||
uint_fast32_t loc = t_loc;
|
||||
const auto funs = get_function(t_name, loc);
|
||||
if (funs.first != loc) { t_loc = uint_fast32_t(funs.first); }
|
||||
|
||||
const auto do_attribute_call =
|
||||
[this](int l_num_params, const std::vector<Boxed_Value> &l_params, const std::vector<Proxy_Function> &l_funs, const Type_Conversions_State &l_conversions)->Boxed_Value
|
||||
const auto do_attribute_call =
|
||||
[this](int l_num_params, Function_Params l_params, const std::vector<Proxy_Function> &l_funs, const Type_Conversions_State &l_conversions)->Boxed_Value
|
||||
{
|
||||
std::vector<Boxed_Value> attr_params{l_params.begin(), l_params.begin() + l_num_params};
|
||||
Function_Params attr_params(l_params.begin(), l_params.begin() + l_num_params);
|
||||
Boxed_Value bv = dispatch::dispatch(l_funs, attr_params, l_conversions);
|
||||
if (l_num_params < int(l_params.size()) || bv.get_type_info().bare_equal(user_type<dispatch::Proxy_Function_Base>())) {
|
||||
struct This_Foist {
|
||||
@ -1049,11 +1007,12 @@ namespace chaiscript
|
||||
if (!functions.empty()) {
|
||||
try {
|
||||
if (is_no_param) {
|
||||
auto tmp_params(params);
|
||||
auto tmp_params = params.to_vector();
|
||||
tmp_params.insert(tmp_params.begin() + 1, var(t_name));
|
||||
return do_attribute_call(2, tmp_params, functions, t_conversions);
|
||||
return do_attribute_call(2, Function_Params(tmp_params), functions, t_conversions);
|
||||
} else {
|
||||
return dispatch::dispatch(functions, {params[0], var(t_name), var(std::vector<Boxed_Value>(params.begin()+1, params.end()))}, t_conversions);
|
||||
std::array<Boxed_Value, 3> p{params[0], var(t_name), var(std::vector<Boxed_Value>(params.begin()+1, params.end()))};
|
||||
return dispatch::dispatch(functions, Function_Params{p}, t_conversions);
|
||||
}
|
||||
} catch (const dispatch::option_explicit_set &e) {
|
||||
throw chaiscript::exception::dispatch_error(params, std::vector<Const_Proxy_Function>(funs.second->begin(), funs.second->end()),
|
||||
@ -1076,7 +1035,7 @@ namespace chaiscript
|
||||
|
||||
|
||||
|
||||
Boxed_Value call_function(const std::string_view &t_name, std::atomic_uint_fast32_t &t_loc, const std::vector<Boxed_Value> ¶ms,
|
||||
Boxed_Value call_function(const std::string_view &t_name, std::atomic_uint_fast32_t &t_loc, const Function_Params ¶ms,
|
||||
const Type_Conversions_State &t_conversions) const
|
||||
{
|
||||
uint_fast32_t loc = t_loc;
|
||||
@ -1124,7 +1083,7 @@ namespace chaiscript
|
||||
|
||||
/// Returns true if a call can be made that consists of the first parameter
|
||||
/// (the function) with the remaining parameters as its arguments.
|
||||
Boxed_Value call_exists(const std::vector<Boxed_Value> ¶ms) const
|
||||
Boxed_Value call_exists(const Function_Params ¶ms) const
|
||||
{
|
||||
if (params.empty())
|
||||
{
|
||||
@ -1134,7 +1093,7 @@ namespace chaiscript
|
||||
const auto &f = this->boxed_cast<Const_Proxy_Function>(params[0]);
|
||||
const Type_Conversions_State convs(m_conversions, m_conversions.conversion_saves());
|
||||
|
||||
return const_var(f->call_match(std::vector<Boxed_Value>(params.begin() + 1, params.end()), convs));
|
||||
return const_var(f->call_match(Function_Params(params.begin() + 1, params.end()), convs));
|
||||
}
|
||||
|
||||
/// Dump all system info to stdout
|
||||
@ -1195,11 +1154,6 @@ namespace chaiscript
|
||||
m_state = t_state;
|
||||
}
|
||||
|
||||
static void save_function_params(Stack_Holder &t_s, std::initializer_list<Boxed_Value> t_params)
|
||||
{
|
||||
t_s.call_params.back().insert(t_s.call_params.back().begin(), t_params);
|
||||
}
|
||||
|
||||
static void save_function_params(Stack_Holder &t_s, std::vector<Boxed_Value> &&t_params)
|
||||
{
|
||||
for (auto &¶m : t_params)
|
||||
@ -1208,22 +1162,17 @@ namespace chaiscript
|
||||
}
|
||||
}
|
||||
|
||||
static void save_function_params(Stack_Holder &t_s, const std::vector<Boxed_Value> &t_params)
|
||||
static void save_function_params(Stack_Holder &t_s, const Function_Params &t_params)
|
||||
{
|
||||
t_s.call_params.back().insert(t_s.call_params.back().begin(), t_params.begin(), t_params.end());
|
||||
}
|
||||
|
||||
void save_function_params(std::initializer_list<Boxed_Value> t_params)
|
||||
{
|
||||
save_function_params(*m_stack_holder, t_params);
|
||||
}
|
||||
|
||||
void save_function_params(std::vector<Boxed_Value> &&t_params)
|
||||
{
|
||||
save_function_params(*m_stack_holder, std::move(t_params));
|
||||
}
|
||||
|
||||
void save_function_params(const std::vector<Boxed_Value> &t_params)
|
||||
void save_function_params(const Function_Params &t_params)
|
||||
{
|
||||
save_function_params(*m_stack_holder, t_params);
|
||||
}
|
||||
@ -1292,32 +1241,32 @@ namespace chaiscript
|
||||
|
||||
private:
|
||||
|
||||
const std::vector<std::pair<std::string, Boxed_Value>> &get_boxed_functions_int() const noexcept
|
||||
const decltype(State::m_boxed_functions) &get_boxed_functions_int() const noexcept
|
||||
{
|
||||
return m_state.m_boxed_functions;
|
||||
}
|
||||
|
||||
std::vector<std::pair<std::string, Boxed_Value>> &get_boxed_functions_int() noexcept
|
||||
decltype(State::m_boxed_functions) &get_boxed_functions_int() noexcept
|
||||
{
|
||||
return m_state.m_boxed_functions;
|
||||
}
|
||||
|
||||
const std::vector<std::pair<std::string, Proxy_Function>> &get_function_objects_int() const noexcept
|
||||
const decltype(State::m_function_objects) &get_function_objects_int() const noexcept
|
||||
{
|
||||
return m_state.m_function_objects;
|
||||
}
|
||||
|
||||
std::vector<std::pair<std::string, Proxy_Function>> &get_function_objects_int() noexcept
|
||||
decltype(State::m_function_objects) &get_function_objects_int() noexcept
|
||||
{
|
||||
return m_state.m_function_objects;
|
||||
}
|
||||
|
||||
const std::vector<std::pair<std::string, std::shared_ptr<std::vector<Proxy_Function>>>> &get_functions_int() const noexcept
|
||||
const decltype(State::m_functions) &get_functions_int() const noexcept
|
||||
{
|
||||
return m_state.m_functions;
|
||||
}
|
||||
|
||||
std::vector<std::pair<std::string, std::shared_ptr<std::vector<Proxy_Function>>>> &get_functions_int() noexcept
|
||||
decltype(State::m_functions) &get_functions_int() noexcept
|
||||
{
|
||||
return m_state.m_functions;
|
||||
}
|
||||
@ -1406,63 +1355,17 @@ namespace chaiscript
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<typename Container, typename Key, typename Value>
|
||||
static void add_keyed_value(Container &t_c, const Key &t_key, Value &&t_value)
|
||||
{
|
||||
auto itr = find_keyed_value(t_c, t_key);
|
||||
|
||||
if (itr == t_c.end()) {
|
||||
t_c.reserve(t_c.size() + 1); // tightly control growth of memory usage here
|
||||
t_c.emplace_back(t_key, std::forward<Value>(t_value));
|
||||
} else {
|
||||
using value_type = typename Container::value_type;
|
||||
*itr = value_type(t_key, std::forward<Value>(t_value));
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Container, typename Key>
|
||||
static typename Container::iterator find_keyed_value(Container &t_c, const Key &t_key) noexcept
|
||||
{
|
||||
return std::find_if(t_c.begin(), t_c.end(),
|
||||
[&t_key](const typename Container::value_type &o) {
|
||||
return o.first == t_key;
|
||||
});
|
||||
}
|
||||
|
||||
template<typename Container, typename Key>
|
||||
static typename Container::const_iterator find_keyed_value(const Container &t_c, const Key &t_key) noexcept
|
||||
{
|
||||
return std::find_if(t_c.begin(), t_c.end(),
|
||||
[&t_key](const typename Container::value_type &o) {
|
||||
return std::equal(o.first.begin(), o.first.end(), t_key.begin(), t_key.end());
|
||||
});
|
||||
}
|
||||
|
||||
template<typename Container, typename Key>
|
||||
static typename Container::const_iterator find_keyed_value(const Container &t_c, const Key &t_key, const size_t t_hint) noexcept
|
||||
{
|
||||
if (t_c.size() > t_hint && t_c[t_hint].first == t_key) {
|
||||
return std::next(t_c.begin(), static_cast<typename std::iterator_traits<typename Container::const_iterator>::difference_type>(t_hint));
|
||||
} else {
|
||||
return find_keyed_value(t_c, t_key);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Implementation detail for adding a function.
|
||||
/// \throws exception::name_conflict_error if there's a function matching the given one being added
|
||||
void add_function(const Proxy_Function &t_f, const std::string &t_name)
|
||||
{
|
||||
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
|
||||
|
||||
auto &funcs = get_functions_int();
|
||||
|
||||
auto itr = find_keyed_value(funcs, t_name);
|
||||
|
||||
Proxy_Function new_func =
|
||||
[&]() -> Proxy_Function {
|
||||
auto &funcs = get_functions_int();
|
||||
auto itr = funcs.find(t_name);
|
||||
|
||||
if (itr != funcs.end())
|
||||
{
|
||||
auto vec = *itr->second;
|
||||
@ -1483,17 +1386,21 @@ namespace chaiscript
|
||||
// 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({t_f});
|
||||
funcs.emplace_back(t_name, std::make_shared<std::vector<Proxy_Function>>(vec));
|
||||
std::vector<Proxy_Function> vec;
|
||||
vec.push_back(t_f);
|
||||
funcs.insert(std::pair{t_name, std::make_shared<std::vector<Proxy_Function>>(vec)});
|
||||
return std::make_shared<Dispatch_Function>(std::move(vec));
|
||||
} else {
|
||||
funcs.emplace_back(t_name, std::make_shared<std::vector<Proxy_Function>>(std::initializer_list<Proxy_Function>({t_f})));
|
||||
auto vec = std::make_shared<std::vector<Proxy_Function>>();
|
||||
vec->push_back(t_f);
|
||||
funcs.insert(std::pair{t_name, vec});
|
||||
return t_f;
|
||||
}
|
||||
}();
|
||||
|
||||
add_keyed_value(get_boxed_functions_int(), t_name, const_var(new_func));
|
||||
add_keyed_value(get_function_objects_int(), t_name, std::move(new_func));
|
||||
|
||||
get_boxed_functions_int().insert_or_assign(t_name, const_var(new_func));
|
||||
get_function_objects_int().insert_or_assign(t_name, std::move(new_func));
|
||||
}
|
||||
|
||||
mutable chaiscript::detail::threading::shared_mutex m_mutex;
|
||||
|
||||
@ -83,7 +83,7 @@ namespace chaiscript
|
||||
|
||||
bool is_attribute_function() const noexcept override { return m_is_attribute; }
|
||||
|
||||
bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const noexcept override
|
||||
bool call_match(const Function_Params &vals, const Type_Conversions_State &t_conversions) const noexcept override
|
||||
{
|
||||
if (dynamic_object_typename_match(vals, m_type_name, m_ti, t_conversions))
|
||||
{
|
||||
@ -99,7 +99,7 @@ namespace chaiscript
|
||||
}
|
||||
|
||||
protected:
|
||||
Boxed_Value do_call(const std::vector<Boxed_Value> ¶ms, const Type_Conversions_State &t_conversions) const override
|
||||
Boxed_Value do_call(const Function_Params ¶ms, const Type_Conversions_State &t_conversions) const override
|
||||
{
|
||||
if (dynamic_object_typename_match(params, m_type_name, m_ti, t_conversions))
|
||||
{
|
||||
@ -148,7 +148,7 @@ namespace chaiscript
|
||||
|
||||
}
|
||||
|
||||
bool dynamic_object_typename_match(const std::vector<Boxed_Value> &bvs, const std::string &name,
|
||||
bool dynamic_object_typename_match(const Function_Params &bvs, const std::string &name,
|
||||
const std::unique_ptr<Type_Info> &ti, const Type_Conversions_State &t_conversions) const noexcept
|
||||
{
|
||||
if (!bvs.empty())
|
||||
@ -205,22 +205,22 @@ namespace chaiscript
|
||||
return (dc != nullptr) && dc->m_type_name == m_type_name && (*dc->m_func) == (*m_func);
|
||||
}
|
||||
|
||||
bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const override
|
||||
bool call_match(const Function_Params &vals, const Type_Conversions_State &t_conversions) const override
|
||||
{
|
||||
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);
|
||||
return m_func->call_match(Function_Params{new_vals}, t_conversions);
|
||||
}
|
||||
|
||||
protected:
|
||||
Boxed_Value do_call(const std::vector<Boxed_Value> ¶ms, const Type_Conversions_State &t_conversions) const override
|
||||
Boxed_Value do_call(const Function_Params ¶ms, const Type_Conversions_State &t_conversions) const override
|
||||
{
|
||||
auto bv = Boxed_Value(Dynamic_Object(m_type_name), true);
|
||||
std::vector<Boxed_Value> new_params{bv};
|
||||
new_params.insert(new_params.end(), params.begin(), params.end());
|
||||
|
||||
(*m_func)(new_params, t_conversions);
|
||||
(*m_func)(Function_Params{new_params}, t_conversions);
|
||||
|
||||
return bv;
|
||||
}
|
||||
|
||||
@ -29,66 +29,7 @@ namespace chaiscript
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
/// 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> ¶ms, const Type_Conversions_State *t_conversions)
|
||||
{
|
||||
if (t_conversions != nullptr) {
|
||||
return boxed_cast<Ret>(dispatch::dispatch(t_funcs, params, *t_conversions), t_conversions);
|
||||
} else {
|
||||
Type_Conversions conv;
|
||||
Type_Conversions_State state(conv, conv.conversion_saves());
|
||||
return boxed_cast<Ret>(dispatch::dispatch(t_funcs, params, state), t_conversions);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Specialization for arithmetic return types
|
||||
*/
|
||||
template<typename Ret>
|
||||
struct Function_Caller_Ret<Ret, true>
|
||||
{
|
||||
static Ret call(const std::vector<Const_Proxy_Function> &t_funcs,
|
||||
const std::vector<Boxed_Value> ¶ms, const Type_Conversions_State *t_conversions)
|
||||
{
|
||||
if (t_conversions != nullptr) {
|
||||
return Boxed_Number(dispatch::dispatch(t_funcs, params, *t_conversions)).get_as<Ret>();
|
||||
} else {
|
||||
Type_Conversions conv;
|
||||
Type_Conversions_State state(conv, conv.conversion_saves());
|
||||
return Boxed_Number(dispatch::dispatch(t_funcs, params, state)).get_as<Ret>();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Specialization for void return types
|
||||
*/
|
||||
template<>
|
||||
struct Function_Caller_Ret<void, false>
|
||||
{
|
||||
static void call(const std::vector<Const_Proxy_Function> &t_funcs,
|
||||
const std::vector<Boxed_Value> ¶ms, const Type_Conversions_State *t_conversions)
|
||||
{
|
||||
if (t_conversions != nullptr) {
|
||||
dispatch::dispatch(t_funcs, params, *t_conversions);
|
||||
} else {
|
||||
Type_Conversions conv;
|
||||
Type_Conversions_State state(conv, conv.conversion_saves());
|
||||
dispatch::dispatch(t_funcs, params, state);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* used internally for unwrapping a function call's types
|
||||
*/
|
||||
/// used internally for unwrapping a function call's types
|
||||
template<typename Ret, typename ... Param>
|
||||
struct Build_Function_Caller_Helper
|
||||
{
|
||||
@ -98,41 +39,44 @@ namespace chaiscript
|
||||
{
|
||||
}
|
||||
|
||||
Ret call(const Function_Params ¶ms, const Type_Conversions_State &t_state)
|
||||
{
|
||||
if constexpr (std::is_arithmetic_v<Ret>) {
|
||||
return Boxed_Number(dispatch::dispatch(m_funcs, params, t_state)).get_as<Ret>();
|
||||
} else if constexpr (std::is_same_v<void, Ret>) {
|
||||
dispatch::dispatch(m_funcs, params, t_state);
|
||||
} else {
|
||||
return boxed_cast<Ret>(dispatch::dispatch(m_funcs, params, t_state), &t_state);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename ... P>
|
||||
Ret operator()(P&& ... param)
|
||||
{
|
||||
std::array<Boxed_Value, sizeof...(P)> params{box<P>(std::forward<P>(param))...};
|
||||
|
||||
if (m_conversions) {
|
||||
Type_Conversions_State state(*m_conversions, m_conversions->conversion_saves());
|
||||
return Function_Caller_Ret<Ret, std::is_arithmetic<Ret>::value && !std::is_same<Ret, bool>::value>::call(m_funcs, {
|
||||
box<P>(std::forward<P>(param))...
|
||||
}, &state
|
||||
);
|
||||
return call(Function_Params{params}, state);
|
||||
} else {
|
||||
return Function_Caller_Ret<Ret, std::is_arithmetic<Ret>::value && !std::is_same<Ret, bool>::value>::call(m_funcs, {
|
||||
box<P>(std::forward<P>(param))...
|
||||
}, nullptr
|
||||
);
|
||||
Type_Conversions conv;
|
||||
Type_Conversions_State state(conv, conv.conversion_saves());
|
||||
return call(Function_Params{params}, state);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
template<typename P, typename Q>
|
||||
static auto box(Q&& q) -> typename std::enable_if<std::is_reference<P>::value&&!std::is_same<chaiscript::Boxed_Value, typename std::remove_const<typename std::remove_reference<P>::type>::type>::value, Boxed_Value>::type
|
||||
{
|
||||
return Boxed_Value(std::ref(std::forward<Q>(q)));
|
||||
}
|
||||
|
||||
template<typename P, typename Q>
|
||||
static auto box(Q&& q) -> typename std::enable_if<!std::is_reference<P>::value&&!std::is_same<chaiscript::Boxed_Value, typename std::remove_const<typename std::remove_reference<P>::type>::type>::value, Boxed_Value>::type
|
||||
{
|
||||
return Boxed_Value(std::forward<Q>(q));
|
||||
}
|
||||
|
||||
template<typename P>
|
||||
static Boxed_Value box(Boxed_Value bv) noexcept
|
||||
{
|
||||
return bv;
|
||||
}
|
||||
static Boxed_Value box(Q &&q) {
|
||||
if constexpr (std::is_same_v<chaiscript::Boxed_Value, std::decay_t<Q>>) {
|
||||
return std::forward<Q>(q);
|
||||
} else if constexpr (std::is_reference_v<P>) {
|
||||
return Boxed_Value(std::ref(std::forward<Q>(q)));
|
||||
} else {
|
||||
return Boxed_Value(std::forward<Q>(q));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::vector<Const_Proxy_Function> m_funcs;
|
||||
|
||||
81
include/chaiscript/dispatchkit/function_params.hpp
Normal file
81
include/chaiscript/dispatchkit/function_params.hpp
Normal file
@ -0,0 +1,81 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
||||
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
||||
|
||||
|
||||
#ifndef CHAISCRIPT_FUNCTION_PARAMS_HPP
|
||||
#define CHAISCRIPT_FUNCTION_PARAMS_HPP
|
||||
|
||||
|
||||
#include "boxed_value.hpp"
|
||||
|
||||
namespace chaiscript {
|
||||
|
||||
class Function_Params
|
||||
{
|
||||
public:
|
||||
constexpr Function_Params(const Boxed_Value * const t_begin, const Boxed_Value * const t_end)
|
||||
: m_begin(t_begin), m_end(t_end)
|
||||
{
|
||||
}
|
||||
|
||||
explicit Function_Params(const Boxed_Value &bv)
|
||||
: m_begin(&bv), m_end(m_begin + 1)
|
||||
{
|
||||
}
|
||||
|
||||
explicit Function_Params(const std::vector<Boxed_Value> &vec)
|
||||
: m_begin(&vec.front()), m_end(&vec.front() + vec.size())
|
||||
{
|
||||
}
|
||||
|
||||
template<size_t Size>
|
||||
constexpr explicit Function_Params(const std::array<Boxed_Value, Size> &a)
|
||||
: m_begin(std::begin(a)), m_end(std::end(a))
|
||||
{
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr const Boxed_Value &operator[](const std::size_t t_i) const noexcept {
|
||||
return m_begin[t_i];
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr const Boxed_Value *begin() const noexcept {
|
||||
return m_begin;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr const Boxed_Value &front() const noexcept {
|
||||
return *m_begin;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr const Boxed_Value *end() const noexcept {
|
||||
return m_end;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr std::size_t size() const noexcept {
|
||||
return m_end - m_begin;
|
||||
}
|
||||
|
||||
std::vector<Boxed_Value> to_vector() const {
|
||||
return std::vector<Boxed_Value>{m_begin, m_end};
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr bool empty() const noexcept {
|
||||
return m_begin == m_end;
|
||||
}
|
||||
|
||||
private:
|
||||
const Boxed_Value *m_begin = nullptr;
|
||||
const Boxed_Value *m_end = nullptr;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@ -36,14 +36,14 @@ namespace chaiscript
|
||||
struct Handle_Return
|
||||
{
|
||||
template<typename T,
|
||||
typename = typename std::enable_if<std::is_pod<typename std::decay<T>::type>::value>::type>
|
||||
typename = std::enable_if_t<std::is_pod_v<std::decay_t<T>>>>
|
||||
static Boxed_Value handle(T r)
|
||||
{
|
||||
return Boxed_Value(std::move(r), true);
|
||||
}
|
||||
|
||||
template<typename T,
|
||||
typename = typename std::enable_if<!std::is_pod<typename std::decay<T>::type>::value>::type>
|
||||
typename = std::enable_if_t<!std::is_pod_v<std::decay_t<T>>>>
|
||||
static Boxed_Value handle(T &&r)
|
||||
{
|
||||
return Boxed_Value(std::make_shared<T>(std::forward<T>(r)), true);
|
||||
|
||||
@ -27,6 +27,7 @@
|
||||
#include "proxy_functions_detail.hpp"
|
||||
#include "type_info.hpp"
|
||||
#include "dynamic_object.hpp"
|
||||
#include "function_params.hpp"
|
||||
|
||||
namespace chaiscript {
|
||||
class Type_Conversions;
|
||||
@ -73,8 +74,9 @@ namespace chaiscript
|
||||
return m_types == t_rhs.m_types;
|
||||
}
|
||||
|
||||
std::vector<Boxed_Value> convert(std::vector<Boxed_Value> vals, const Type_Conversions_State &t_conversions) const
|
||||
std::vector<Boxed_Value> convert(Function_Params t_params, const Type_Conversions_State &t_conversions) const
|
||||
{
|
||||
auto vals = t_params.to_vector();
|
||||
constexpr auto dynamic_object_type_info = user_type<Dynamic_Object>();
|
||||
for (size_t i = 0; i < vals.size(); ++i)
|
||||
{
|
||||
@ -113,7 +115,7 @@ namespace chaiscript
|
||||
|
||||
// first result: is a match
|
||||
// second result: needs conversions
|
||||
std::pair<bool, bool> match(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const noexcept
|
||||
std::pair<bool, bool> match(const Function_Params &vals, const Type_Conversions_State &t_conversions) const noexcept
|
||||
{
|
||||
constexpr auto dynamic_object_type_info = user_type<Dynamic_Object>();
|
||||
bool needs_conversion = false;
|
||||
@ -136,7 +138,7 @@ namespace chaiscript
|
||||
}
|
||||
} catch (const std::bad_cast &) {
|
||||
return std::make_pair(false, false);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const auto &ti = m_types[i].second;
|
||||
if (!ti.is_undef())
|
||||
@ -196,7 +198,7 @@ namespace chaiscript
|
||||
public:
|
||||
virtual ~Proxy_Function_Base() = default;
|
||||
|
||||
Boxed_Value operator()(const std::vector<Boxed_Value> ¶ms, const chaiscript::Type_Conversions_State &t_conversions) const
|
||||
Boxed_Value operator()(const Function_Params ¶ms, const chaiscript::Type_Conversions_State &t_conversions) const
|
||||
{
|
||||
if (m_arity < 0 || size_t(m_arity) == params.size()) {
|
||||
return do_call(params, t_conversions);
|
||||
@ -208,11 +210,11 @@ namespace chaiscript
|
||||
/// Returns a vector containing all of the types of the parameters the function returns/takes
|
||||
/// if the function is variadic or takes no arguments (arity of 0 or -1), the returned
|
||||
/// value contains exactly 1 Type_Info object: the return type
|
||||
/// \returns the types of all parameters.
|
||||
/// \returns the types of all parameters.
|
||||
const std::vector<Type_Info> &get_param_types() const noexcept { return m_types; }
|
||||
|
||||
virtual bool operator==(const Proxy_Function_Base &) const noexcept = 0;
|
||||
virtual bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const = 0;
|
||||
virtual bool call_match(const Function_Params &vals, const Type_Conversions_State &t_conversions) const = 0;
|
||||
|
||||
virtual bool is_attribute_function() const noexcept { return false; }
|
||||
|
||||
@ -228,7 +230,7 @@ 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 Type_Conversions_State &t_conversions) const noexcept
|
||||
bool filter(const Function_Params &vals, const Type_Conversions_State &t_conversions) const noexcept
|
||||
{
|
||||
assert(m_arity == -1 || (m_arity > 0 && static_cast<int>(vals.size()) == m_arity));
|
||||
|
||||
@ -254,13 +256,13 @@ namespace chaiscript
|
||||
constexpr auto boxed_number_ti = user_type<Boxed_Number>();
|
||||
constexpr auto function_ti = user_type<std::shared_ptr<const Proxy_Function_Base>>();
|
||||
|
||||
if (ti.is_undef()
|
||||
if (ti.is_undef()
|
||||
|| ti.bare_equal(boxed_value_ti)
|
||||
|| (!bv.get_type_info().is_undef()
|
||||
&& ( (ti.bare_equal(boxed_number_ti) && bv.get_type_info().is_arithmetic())
|
||||
|| ti.bare_equal(bv.get_type_info())
|
||||
|| bv.get_type_info().bare_equal(function_ti)
|
||||
|| t_conversions->converts(ti, bv.get_type_info())
|
||||
|| t_conversions->converts(ti, bv.get_type_info())
|
||||
)
|
||||
)
|
||||
)
|
||||
@ -278,7 +280,7 @@ namespace chaiscript
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual Boxed_Value do_call(const std::vector<Boxed_Value> ¶ms, const Type_Conversions_State &t_conversions) const = 0;
|
||||
virtual Boxed_Value do_call(const Function_Params ¶ms, const Type_Conversions_State &t_conversions) const = 0;
|
||||
|
||||
Proxy_Function_Base(std::vector<Type_Info> t_types, int t_arity)
|
||||
: m_types(std::move(t_types)), m_arity(t_arity), m_has_arithmetic_param(false)
|
||||
@ -295,7 +297,7 @@ namespace chaiscript
|
||||
}
|
||||
|
||||
|
||||
static bool compare_types(const std::vector<Type_Info> &tis, const std::vector<Boxed_Value> &bvs,
|
||||
static bool compare_types(const std::vector<Type_Info> &tis, const Function_Params &bvs,
|
||||
const Type_Conversions_State &t_conversions) noexcept
|
||||
{
|
||||
if (tis.size() - 1 != bvs.size())
|
||||
@ -342,10 +344,8 @@ namespace chaiscript
|
||||
|
||||
namespace dispatch
|
||||
{
|
||||
/**
|
||||
* A Proxy_Function implementation that is not type safe, the called function
|
||||
* is expecting a vector<Boxed_Value> that it works with how it chooses.
|
||||
*/
|
||||
/// A Proxy_Function implementation that is not type safe, the called function
|
||||
/// is expecting a vector<Boxed_Value> that it works with how it chooses.
|
||||
class Dynamic_Proxy_Function : public Proxy_Function_Base
|
||||
{
|
||||
public:
|
||||
@ -373,7 +373,7 @@ namespace chaiscript
|
||||
&& this->m_param_types == prhs->m_param_types);
|
||||
}
|
||||
|
||||
bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const override
|
||||
bool call_match(const Function_Params &vals, const Type_Conversions_State &t_conversions) const override
|
||||
{
|
||||
return call_match_internal(vals, t_conversions).first;
|
||||
}
|
||||
@ -403,7 +403,7 @@ namespace chaiscript
|
||||
|
||||
|
||||
protected:
|
||||
bool test_guard(const std::vector<Boxed_Value> ¶ms, const Type_Conversions_State &t_conversions) const
|
||||
bool test_guard(const Function_Params ¶ms, const Type_Conversions_State &t_conversions) const
|
||||
{
|
||||
if (m_guard)
|
||||
{
|
||||
@ -421,7 +421,7 @@ namespace chaiscript
|
||||
|
||||
// first result: is a match
|
||||
// second result: needs conversions
|
||||
std::pair<bool, bool> call_match_internal(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const
|
||||
std::pair<bool, bool> call_match_internal(const Function_Params &vals, const Type_Conversions_State &t_conversions) const
|
||||
{
|
||||
const auto comparison_result = [&](){
|
||||
if (m_arity < 0) {
|
||||
@ -434,7 +434,7 @@ namespace chaiscript
|
||||
}();
|
||||
|
||||
return std::make_pair(
|
||||
comparison_result.first && test_guard(vals, t_conversions),
|
||||
comparison_result.first && test_guard(vals, t_conversions),
|
||||
comparison_result.second
|
||||
);
|
||||
}
|
||||
@ -472,7 +472,7 @@ namespace chaiscript
|
||||
{
|
||||
public:
|
||||
Dynamic_Proxy_Function_Impl(
|
||||
Callable t_f,
|
||||
Callable t_f,
|
||||
int t_arity=-1,
|
||||
std::shared_ptr<AST_Node> t_parsenode = AST_NodePtr(),
|
||||
Param_Types t_param_types = Param_Types(),
|
||||
@ -489,13 +489,13 @@ namespace chaiscript
|
||||
|
||||
|
||||
protected:
|
||||
Boxed_Value do_call(const std::vector<Boxed_Value> ¶ms, const Type_Conversions_State &t_conversions) const override
|
||||
Boxed_Value do_call(const Function_Params ¶ms, const Type_Conversions_State &t_conversions) const override
|
||||
{
|
||||
const auto match_results = call_match_internal(params, t_conversions);
|
||||
if (match_results.first)
|
||||
const auto [is_a_match, needs_conversions] = call_match_internal(params, t_conversions);
|
||||
if (is_a_match)
|
||||
{
|
||||
if (match_results.second) {
|
||||
return m_f(m_param_types.convert(params, t_conversions));
|
||||
if (needs_conversions) {
|
||||
return m_f(Function_Params{m_param_types.convert(params, t_conversions)});
|
||||
} else {
|
||||
return m_f(params);
|
||||
}
|
||||
@ -528,7 +528,7 @@ namespace chaiscript
|
||||
class Bound_Function final : public Proxy_Function_Base
|
||||
{
|
||||
public:
|
||||
Bound_Function(const Const_Proxy_Function &t_f,
|
||||
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), (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)
|
||||
@ -542,9 +542,9 @@ namespace chaiscript
|
||||
}
|
||||
|
||||
|
||||
bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const override
|
||||
bool call_match(const Function_Params &vals, const Type_Conversions_State &t_conversions) const override
|
||||
{
|
||||
return m_f->call_match(build_param_list(vals), t_conversions);
|
||||
return m_f->call_match(Function_Params(build_param_list(vals)), t_conversions);
|
||||
}
|
||||
|
||||
std::vector<Const_Proxy_Function> get_contained_functions() const override
|
||||
@ -553,7 +553,7 @@ namespace chaiscript
|
||||
}
|
||||
|
||||
|
||||
std::vector<Boxed_Value> build_param_list(const std::vector<Boxed_Value> ¶ms) const
|
||||
std::vector<Boxed_Value> build_param_list(const Function_Params ¶ms) const
|
||||
{
|
||||
auto parg = params.begin();
|
||||
auto barg = m_args.begin();
|
||||
@ -562,7 +562,7 @@ namespace chaiscript
|
||||
|
||||
while (!(parg == params.end() && barg == m_args.end()))
|
||||
{
|
||||
while (barg != m_args.end()
|
||||
while (barg != m_args.end()
|
||||
&& !(barg->get_type_info() == chaiscript::detail::Get_Type_Info<Placeholder_Object>::get()))
|
||||
{
|
||||
args.push_back(*barg);
|
||||
@ -575,18 +575,18 @@ namespace chaiscript
|
||||
++parg;
|
||||
}
|
||||
|
||||
if (barg != m_args.end()
|
||||
if (barg != m_args.end()
|
||||
&& barg->get_type_info() == chaiscript::detail::Get_Type_Info<Placeholder_Object>::get())
|
||||
{
|
||||
++barg;
|
||||
}
|
||||
}
|
||||
}
|
||||
return args;
|
||||
}
|
||||
|
||||
|
||||
protected:
|
||||
static std::vector<Type_Info> build_param_type_info(const Const_Proxy_Function &t_f,
|
||||
static std::vector<Type_Info> build_param_type_info(const Const_Proxy_Function &t_f,
|
||||
const std::vector<Boxed_Value> &t_args)
|
||||
{
|
||||
assert(t_f->get_arity() < 0 || t_f->get_arity() == static_cast<int>(t_args.size()));
|
||||
@ -610,9 +610,9 @@ namespace chaiscript
|
||||
return retval;
|
||||
}
|
||||
|
||||
Boxed_Value do_call(const std::vector<Boxed_Value> ¶ms, const Type_Conversions_State &t_conversions) const override
|
||||
Boxed_Value do_call(const Function_Params ¶ms, const Type_Conversions_State &t_conversions) const override
|
||||
{
|
||||
return (*m_f)(build_param_list(params), t_conversions);
|
||||
return (*m_f)(Function_Params{build_param_list(params)}, t_conversions);
|
||||
}
|
||||
|
||||
private:
|
||||
@ -628,13 +628,13 @@ namespace chaiscript
|
||||
{
|
||||
}
|
||||
|
||||
bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const noexcept override
|
||||
bool call_match(const Function_Params &vals, const Type_Conversions_State &t_conversions) const noexcept override
|
||||
{
|
||||
return static_cast<int>(vals.size()) == get_arity()
|
||||
return static_cast<int>(vals.size()) == get_arity()
|
||||
&& (compare_types(m_types, vals, t_conversions) && compare_types_with_cast(vals, t_conversions));
|
||||
}
|
||||
|
||||
virtual bool compare_types_with_cast(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const noexcept = 0;
|
||||
virtual bool compare_types_with_cast(const Function_Params &vals, const Type_Conversions_State &t_conversions) const noexcept = 0;
|
||||
};
|
||||
|
||||
|
||||
@ -650,7 +650,7 @@ namespace chaiscript
|
||||
{
|
||||
}
|
||||
|
||||
bool compare_types_with_cast(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const noexcept override
|
||||
bool compare_types_with_cast(const Function_Params &vals, const Type_Conversions_State &t_conversions) const noexcept override
|
||||
{
|
||||
return detail::compare_types_cast(static_cast<Func *>(nullptr), vals, t_conversions);
|
||||
}
|
||||
@ -662,7 +662,7 @@ namespace chaiscript
|
||||
|
||||
|
||||
protected:
|
||||
Boxed_Value do_call(const std::vector<Boxed_Value> ¶ms, const Type_Conversions_State &t_conversions) const override
|
||||
Boxed_Value do_call(const Function_Params ¶ms, const Type_Conversions_State &t_conversions) const override
|
||||
{
|
||||
return detail::call_func(static_cast<Func *>(nullptr), m_f, params, t_conversions);
|
||||
}
|
||||
@ -694,7 +694,7 @@ namespace chaiscript
|
||||
assert(!m_shared_ptr_holder || m_shared_ptr_holder.get() == &m_f.get());
|
||||
}
|
||||
|
||||
bool compare_types_with_cast(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const noexcept override
|
||||
bool compare_types_with_cast(const Function_Params &vals, const Type_Conversions_State &t_conversions) const noexcept override
|
||||
{
|
||||
return detail::compare_types_cast(static_cast<Func *>(nullptr), vals, t_conversions);
|
||||
}
|
||||
@ -714,7 +714,7 @@ namespace chaiscript
|
||||
}
|
||||
|
||||
protected:
|
||||
Boxed_Value do_call(const std::vector<Boxed_Value> ¶ms, const Type_Conversions_State &t_conversions) const override
|
||||
Boxed_Value do_call(const Function_Params ¶ms, const Type_Conversions_State &t_conversions) const override
|
||||
{
|
||||
return detail::call_func(static_cast<Func *>(nullptr), m_f.get(), params, t_conversions);
|
||||
}
|
||||
@ -737,11 +737,11 @@ namespace chaiscript
|
||||
{
|
||||
}
|
||||
|
||||
bool is_attribute_function() const noexcept override { return true; }
|
||||
bool is_attribute_function() const noexcept override { return true; }
|
||||
|
||||
bool operator==(const Proxy_Function_Base &t_func) const noexcept override
|
||||
{
|
||||
const Attribute_Access<T, Class> * aa
|
||||
const Attribute_Access<T, Class> * aa
|
||||
= dynamic_cast<const Attribute_Access<T, Class> *>(&t_func);
|
||||
|
||||
if (aa) {
|
||||
@ -751,7 +751,7 @@ namespace chaiscript
|
||||
}
|
||||
}
|
||||
|
||||
bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &) const noexcept override
|
||||
bool call_match(const Function_Params &vals, const Type_Conversions_State &) const noexcept override
|
||||
{
|
||||
if (vals.size() != 1)
|
||||
{
|
||||
@ -762,7 +762,7 @@ namespace chaiscript
|
||||
}
|
||||
|
||||
protected:
|
||||
Boxed_Value do_call(const std::vector<Boxed_Value> ¶ms, const Type_Conversions_State &t_conversions) const override
|
||||
Boxed_Value do_call(const Function_Params ¶ms, const Type_Conversions_State &t_conversions) const override
|
||||
{
|
||||
const Boxed_Value &bv = params[0];
|
||||
if (bv.is_const())
|
||||
@ -811,22 +811,22 @@ namespace chaiscript
|
||||
{
|
||||
/// \brief Exception thrown in the case that a method dispatch fails
|
||||
/// because no matching function was found
|
||||
///
|
||||
///
|
||||
/// May be thrown due to an arity_error, a guard_error or a bad_boxed_cast
|
||||
/// exception
|
||||
class dispatch_error : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
dispatch_error(std::vector<Boxed_Value> t_parameters,
|
||||
dispatch_error(const Function_Params &t_parameters,
|
||||
std::vector<Const_Proxy_Function> t_functions)
|
||||
: std::runtime_error("Error with function dispatch"), parameters(std::move(t_parameters)), functions(std::move(t_functions))
|
||||
: std::runtime_error("Error with function dispatch"), parameters(t_parameters.to_vector()), functions(std::move(t_functions))
|
||||
{
|
||||
}
|
||||
|
||||
dispatch_error(std::vector<Boxed_Value> t_parameters,
|
||||
dispatch_error(const Function_Params &t_parameters,
|
||||
std::vector<Const_Proxy_Function> t_functions,
|
||||
const std::string &t_desc)
|
||||
: std::runtime_error(t_desc), parameters(std::move(t_parameters)), functions(std::move(t_functions))
|
||||
: std::runtime_error(t_desc), parameters(t_parameters.to_vector()), functions(std::move(t_functions))
|
||||
{
|
||||
}
|
||||
|
||||
@ -837,14 +837,14 @@ namespace chaiscript
|
||||
std::vector<Boxed_Value> parameters;
|
||||
std::vector<Const_Proxy_Function> functions;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
namespace dispatch
|
||||
{
|
||||
namespace detail
|
||||
namespace detail
|
||||
{
|
||||
template<typename FuncType>
|
||||
bool types_match_except_for_arithmetic(const FuncType &t_func, const std::vector<Boxed_Value> &plist,
|
||||
bool types_match_except_for_arithmetic(const FuncType &t_func, const Function_Params &plist,
|
||||
const Type_Conversions_State &t_conversions) noexcept
|
||||
{
|
||||
const std::vector<Type_Info> &types = t_func->get_param_types();
|
||||
@ -863,7 +863,7 @@ namespace chaiscript
|
||||
}
|
||||
|
||||
template<typename InItr, typename Funcs>
|
||||
Boxed_Value dispatch_with_conversions(InItr begin, const InItr &end, const std::vector<Boxed_Value> &plist,
|
||||
Boxed_Value dispatch_with_conversions(InItr begin, const InItr &end, const Function_Params &plist,
|
||||
const Type_Conversions_State &t_conversions, const Funcs &t_funcs)
|
||||
{
|
||||
InItr matching_func(end);
|
||||
@ -919,7 +919,7 @@ namespace chaiscript
|
||||
);
|
||||
|
||||
try {
|
||||
return (*(matching_func->second))(newplist, t_conversions);
|
||||
return (*(matching_func->second))(Function_Params{newplist}, t_conversions);
|
||||
} catch (const exception::bad_boxed_cast &) {
|
||||
//parameter failed to cast
|
||||
} catch (const exception::arity_error &) {
|
||||
@ -938,7 +938,7 @@ namespace chaiscript
|
||||
/// 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 Type_Conversions_State &t_conversions)
|
||||
const Function_Params &plist, const Type_Conversions_State &t_conversions)
|
||||
{
|
||||
std::vector<std::pair<size_t, const Proxy_Function_Base *>> ordered_funcs;
|
||||
ordered_funcs.reserve(funcs.size());
|
||||
|
||||
@ -21,6 +21,7 @@
|
||||
#include "boxed_value.hpp"
|
||||
#include "handle_return.hpp"
|
||||
#include "type_info.hpp"
|
||||
#include "function_params.hpp"
|
||||
|
||||
namespace chaiscript {
|
||||
class Type_Conversions_State;
|
||||
@ -77,7 +78,7 @@ namespace chaiscript
|
||||
*/
|
||||
template<typename Ret, typename ... Params>
|
||||
bool compare_types_cast(Ret (*)(Params...),
|
||||
const std::vector<Boxed_Value> ¶ms, const Type_Conversions_State &t_conversions) noexcept
|
||||
const Function_Params ¶ms, const Type_Conversions_State &t_conversions) noexcept
|
||||
{
|
||||
try {
|
||||
std::vector<Boxed_Value>::size_type i = 0;
|
||||
@ -92,7 +93,7 @@ namespace chaiscript
|
||||
template<typename Callable, typename Ret, typename ... Params, size_t ... I>
|
||||
Ret call_func(Ret (*)(Params...),
|
||||
std::index_sequence<I...>, const Callable &f,
|
||||
[[maybe_unused]] const std::vector<Boxed_Value> ¶ms,
|
||||
[[maybe_unused]] const Function_Params ¶ms,
|
||||
[[maybe_unused]] const Type_Conversions_State &t_conversions)
|
||||
{
|
||||
return f(boxed_cast<Params>(params[I], &t_conversions)...);
|
||||
@ -105,7 +106,7 @@ namespace chaiscript
|
||||
/// the bad_boxed_cast is passed up to the caller.
|
||||
template<typename Callable, typename Ret, typename ... Params>
|
||||
Boxed_Value call_func(Ret (*sig)(Params...), const Callable &f,
|
||||
const std::vector<Boxed_Value> ¶ms, const Type_Conversions_State &t_conversions)
|
||||
const Function_Params ¶ms, const Type_Conversions_State &t_conversions)
|
||||
{
|
||||
if constexpr (std::is_same_v<Ret, void>) {
|
||||
call_func(sig, std::index_sequence_for<Params...>{}, f, params, t_conversions);
|
||||
|
||||
@ -95,7 +95,7 @@ namespace chaiscript
|
||||
Logical_And, Logical_Or, Reference, Switch, Case, Default, Noop, Class, Binary, Arg, Global_Decl, Constant, Compiled
|
||||
};
|
||||
|
||||
enum class Operator_Precidence { Ternary_Cond, Logical_Or,
|
||||
enum class Operator_Precedence { Ternary_Cond, Logical_Or,
|
||||
Logical_And, Bitwise_Or, Bitwise_Xor, Bitwise_And,
|
||||
Equality, Comparison, Shift, Addition, Multiplication, Prefix };
|
||||
|
||||
@ -732,12 +732,7 @@ namespace chaiscript
|
||||
m_ds->pop_function_call(m_ds.stack_holder(), m_ds.conversion_saves());
|
||||
}
|
||||
|
||||
void save_params(const std::vector<Boxed_Value> &t_params)
|
||||
{
|
||||
m_ds->save_function_params(t_params);
|
||||
}
|
||||
|
||||
void save_params(std::initializer_list<Boxed_Value> t_params)
|
||||
void save_params(const Function_Params &t_params)
|
||||
{
|
||||
m_ds->save_function_params(t_params);
|
||||
}
|
||||
|
||||
@ -149,7 +149,7 @@ namespace chaiscript
|
||||
|
||||
m_engine.add(
|
||||
dispatch::make_dynamic_proxy_function(
|
||||
[this](const std::vector<Boxed_Value> &t_params) {
|
||||
[this](const Function_Params &t_params) {
|
||||
return m_engine.call_exists(t_params);
|
||||
})
|
||||
, "call_exists");
|
||||
@ -158,7 +158,7 @@ namespace chaiscript
|
||||
m_engine.add(fun(
|
||||
[=](const dispatch::Proxy_Function_Base &t_fun, const std::vector<Boxed_Value> &t_params) -> Boxed_Value {
|
||||
Type_Conversions_State s(this->m_engine.conversions(), this->m_engine.conversions().conversion_saves());
|
||||
return t_fun(t_params, s);
|
||||
return t_fun(Function_Params{t_params}, s);
|
||||
}), "call");
|
||||
|
||||
|
||||
@ -200,6 +200,7 @@ namespace chaiscript
|
||||
m_engine.add(fun([this](const Boxed_Value &t_bv, const std::string &t_name){ add_global(t_bv, t_name); }), "add_global");
|
||||
m_engine.add(fun([this](const Boxed_Value &t_bv, const std::string &t_name){ set_global(t_bv, t_name); }), "set_global");
|
||||
|
||||
// why this unused parameter to Namespace?
|
||||
m_engine.add(fun([this](const std::string& t_namespace_name) { register_namespace([](Namespace& /*space*/) {}, t_namespace_name); import(t_namespace_name); }), "namespace");
|
||||
m_engine.add(fun([this](const std::string& t_namespace_name) { import(t_namespace_name); }), "import");
|
||||
}
|
||||
|
||||
@ -51,7 +51,7 @@ namespace chaiscript
|
||||
{
|
||||
/// Helper function that will set up the scope around a function call, including handling the named function parameters
|
||||
template<typename T>
|
||||
static Boxed_Value eval_function(chaiscript::detail::Dispatch_Engine &t_ss, const AST_Node_Impl<T> &t_node, const std::vector<std::string> &t_param_names, const std::vector<Boxed_Value> &t_vals, const std::map<std::string, Boxed_Value> *t_locals=nullptr, bool has_this_capture = false) {
|
||||
static Boxed_Value eval_function(chaiscript::detail::Dispatch_Engine &t_ss, const AST_Node_Impl<T> &t_node, const std::vector<std::string> &t_param_names, const Function_Params &t_vals, const std::map<std::string, Boxed_Value> *t_locals=nullptr, bool has_this_capture = false) {
|
||||
chaiscript::detail::Dispatch_State state(t_ss);
|
||||
|
||||
const Boxed_Value *thisobj = [&]() -> const Boxed_Value *{
|
||||
@ -96,8 +96,11 @@ namespace chaiscript
|
||||
return Boxed_Number::clone(incoming);
|
||||
} else if (incoming.get_type_info().bare_equal_type_info(typeid(bool))) {
|
||||
return Boxed_Value(*static_cast<const bool*>(incoming.get_const_ptr()));
|
||||
} else if (incoming.get_type_info().bare_equal_type_info(typeid(std::string))) {
|
||||
return Boxed_Value(*static_cast<const std::string *>(incoming.get_const_ptr()));
|
||||
} else {
|
||||
return t_ss->call_function("clone", t_loc, {incoming}, t_ss.conversions());
|
||||
std::array<Boxed_Value, 1> params{std::move(incoming)};
|
||||
return t_ss->call_function("clone", t_loc, Function_Params{params}, t_ss.conversions());
|
||||
}
|
||||
} else {
|
||||
incoming.reset_return_value();
|
||||
@ -200,8 +203,9 @@ namespace chaiscript
|
||||
}
|
||||
} else {
|
||||
chaiscript::eval::detail::Function_Push_Pop fpp(t_ss);
|
||||
fpp.save_params({t_lhs, m_rhs});
|
||||
return t_ss->call_function(t_oper_string, m_loc, {t_lhs, m_rhs}, t_ss.conversions());
|
||||
std::array<Boxed_Value, 2> params{t_lhs, m_rhs};
|
||||
fpp.save_params(Function_Params{params});
|
||||
return t_ss->call_function(t_oper_string, m_loc, Function_Params{params}, t_ss.conversions());
|
||||
}
|
||||
}
|
||||
catch(const exception::dispatch_error &e){
|
||||
@ -246,8 +250,9 @@ namespace chaiscript
|
||||
}
|
||||
} else {
|
||||
chaiscript::eval::detail::Function_Push_Pop fpp(t_ss);
|
||||
fpp.save_params({t_lhs, t_rhs});
|
||||
return t_ss->call_function(t_oper_string, m_loc, {t_lhs, t_rhs}, t_ss.conversions());
|
||||
std::array<Boxed_Value, 2> params{t_lhs, t_rhs};
|
||||
fpp.save_params(Function_Params(params));
|
||||
return t_ss->call_function(t_oper_string, m_loc, Function_Params(params), t_ss.conversions());
|
||||
}
|
||||
}
|
||||
catch(const exception::dispatch_error &e){
|
||||
@ -321,14 +326,14 @@ namespace chaiscript
|
||||
}
|
||||
|
||||
if (Save_Params) {
|
||||
fpp.save_params(params);
|
||||
fpp.save_params(Function_Params{params});
|
||||
}
|
||||
|
||||
Boxed_Value fn(this->children[0]->eval(t_ss));
|
||||
|
||||
using ConstFunctionTypePtr = const dispatch::Proxy_Function_Base *;
|
||||
try {
|
||||
return (*t_ss->boxed_cast<ConstFunctionTypePtr>(fn))(params, t_ss.conversions());
|
||||
return (*t_ss->boxed_cast<const dispatch::Proxy_Function_Base *>(fn))(Function_Params{params}, t_ss.conversions());
|
||||
}
|
||||
catch(const exception::dispatch_error &e){
|
||||
throw exception::eval_error(std::string(e.what()) + " with function '" + this->children[0]->text + "'", e.parameters, e.functions, false, *t_ss);
|
||||
@ -338,7 +343,7 @@ namespace chaiscript
|
||||
using ConstFunctionTypeRef = const Const_Proxy_Function &;
|
||||
Const_Proxy_Function f = t_ss->boxed_cast<ConstFunctionTypeRef>(fn);
|
||||
// handle the case where there is only 1 function to try to call and dispatch fails on it
|
||||
throw exception::eval_error("Error calling function '" + this->children[0]->text + "'", params, {f}, false, *t_ss);
|
||||
throw exception::eval_error("Error calling function '" + this->children[0]->text + "'", params, make_vector(f), false, *t_ss);
|
||||
} catch (const exception::bad_boxed_cast &) {
|
||||
throw exception::eval_error("'" + this->children[0]->pretty_print() + "' does not evaluate to a function.");
|
||||
}
|
||||
@ -444,28 +449,37 @@ namespace chaiscript
|
||||
|
||||
Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override {
|
||||
chaiscript::eval::detail::Function_Push_Pop fpp(t_ss);
|
||||
Boxed_Value rhs = this->children[1]->eval(t_ss);
|
||||
Boxed_Value lhs = this->children[0]->eval(t_ss);
|
||||
|
||||
if (lhs.is_return_value()) {
|
||||
auto params = [&](){
|
||||
// The RHS *must* be evaluated before the LHS
|
||||
// consider `var range = range(x)`
|
||||
// if we declare the variable in scope first, then the name lookup fails
|
||||
// for the RHS
|
||||
auto rhs = this->children[1]->eval(t_ss);
|
||||
auto lhs = this->children[0]->eval(t_ss);
|
||||
std::array<Boxed_Value, 2> p{std::move(lhs), std::move(rhs)};
|
||||
return p;
|
||||
}();
|
||||
|
||||
if (params[0].is_return_value()) {
|
||||
throw exception::eval_error("Error, cannot assign to temporary value.");
|
||||
} else if (lhs.is_const()) {
|
||||
} else if (params[0].is_const()) {
|
||||
throw exception::eval_error("Error, cannot assign to constant value.");
|
||||
}
|
||||
|
||||
|
||||
if (m_oper != Operators::Opers::invalid && lhs.get_type_info().is_arithmetic() &&
|
||||
rhs.get_type_info().is_arithmetic())
|
||||
if (m_oper != Operators::Opers::invalid && params[0].get_type_info().is_arithmetic() &&
|
||||
params[1].get_type_info().is_arithmetic())
|
||||
{
|
||||
try {
|
||||
return Boxed_Number::do_oper(m_oper, lhs, rhs);
|
||||
return Boxed_Number::do_oper(m_oper, params[0], params[1]);
|
||||
} catch (const std::exception &) {
|
||||
throw exception::eval_error("Error with unsupported arithmetic assignment operation.");
|
||||
}
|
||||
} else if (m_oper == Operators::Opers::assign) {
|
||||
try {
|
||||
|
||||
if (lhs.is_undef()) {
|
||||
if (params[0].is_undef()) {
|
||||
if (!this->children.empty()
|
||||
&& ((this->children[0]->identifier == AST_Node_Type::Reference)
|
||||
|| (!this->children[0]->children.empty()
|
||||
@ -476,16 +490,16 @@ namespace chaiscript
|
||||
{
|
||||
/// \todo This does not handle the case of an unassigned reference variable
|
||||
/// being assigned outside of its declaration
|
||||
lhs.assign(rhs);
|
||||
lhs.reset_return_value();
|
||||
return rhs;
|
||||
params[0].assign(params[1]);
|
||||
params[0].reset_return_value();
|
||||
return params[1];
|
||||
} else {
|
||||
rhs = detail::clone_if_necessary(std::move(rhs), m_clone_loc, t_ss);
|
||||
params[1] = detail::clone_if_necessary(std::move(params[1]), m_clone_loc, t_ss);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
return t_ss->call_function(this->text, m_loc, {std::move(lhs), rhs}, t_ss.conversions());
|
||||
return t_ss->call_function(this->text, m_loc, Function_Params{params}, t_ss.conversions());
|
||||
}
|
||||
catch(const exception::dispatch_error &e){
|
||||
throw exception::eval_error("Unable to find appropriate'" + this->text + "' operator.", e.parameters, e.functions, false, *t_ss);
|
||||
@ -496,22 +510,22 @@ namespace chaiscript
|
||||
}
|
||||
}
|
||||
else if (this->text == ":=") {
|
||||
if (lhs.is_undef() || Boxed_Value::type_match(lhs, rhs)) {
|
||||
lhs.assign(rhs);
|
||||
lhs.reset_return_value();
|
||||
if (params[0].is_undef() || Boxed_Value::type_match(params[0], params[1])) {
|
||||
params[0].assign(params[1]);
|
||||
params[0].reset_return_value();
|
||||
} else {
|
||||
throw exception::eval_error("Mismatched types in equation");
|
||||
}
|
||||
}
|
||||
else {
|
||||
try {
|
||||
return t_ss->call_function(this->text, m_loc, {std::move(lhs), rhs}, t_ss.conversions());
|
||||
return t_ss->call_function(this->text, m_loc, Function_Params{params}, t_ss.conversions());
|
||||
} catch(const exception::dispatch_error &e){
|
||||
throw exception::eval_error("Unable to find appropriate'" + this->text + "' operator.", e.parameters, e.functions, false, *t_ss);
|
||||
}
|
||||
}
|
||||
|
||||
return rhs;
|
||||
return params[1];
|
||||
}
|
||||
|
||||
private:
|
||||
@ -589,11 +603,11 @@ namespace chaiscript
|
||||
Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override {
|
||||
chaiscript::eval::detail::Function_Push_Pop fpp(t_ss);
|
||||
|
||||
const std::vector<Boxed_Value> params{this->children[0]->eval(t_ss), this->children[1]->eval(t_ss)};
|
||||
std::array<Boxed_Value, 2> params{this->children[0]->eval(t_ss), this->children[1]->eval(t_ss)};
|
||||
|
||||
try {
|
||||
fpp.save_params(params);
|
||||
return t_ss->call_function("[]", m_loc, params, t_ss.conversions());
|
||||
fpp.save_params(Function_Params{params});
|
||||
return t_ss->call_function("[]", m_loc, Function_Params{params}, t_ss.conversions());
|
||||
}
|
||||
catch(const exception::dispatch_error &e){
|
||||
throw exception::eval_error("Can not find appropriate array lookup operator '[]'.", e.parameters, e.functions, false, *t_ss );
|
||||
@ -618,7 +632,7 @@ namespace chaiscript
|
||||
|
||||
|
||||
Boxed_Value retval = this->children[0]->eval(t_ss);
|
||||
std::vector<Boxed_Value> params{retval};
|
||||
auto params = make_vector(retval);
|
||||
|
||||
bool has_function_params = false;
|
||||
if (this->children[1]->children.size() > 1) {
|
||||
@ -628,10 +642,10 @@ namespace chaiscript
|
||||
}
|
||||
}
|
||||
|
||||
fpp.save_params(params);
|
||||
fpp.save_params(Function_Params{params});
|
||||
|
||||
try {
|
||||
retval = t_ss->call_member(m_fun_name, m_loc, std::move(params), has_function_params, t_ss.conversions());
|
||||
retval = t_ss->call_member(m_fun_name, m_loc, Function_Params{params}, has_function_params, t_ss.conversions());
|
||||
}
|
||||
catch(const exception::dispatch_error &e){
|
||||
if (e.functions.empty())
|
||||
@ -647,7 +661,8 @@ namespace chaiscript
|
||||
|
||||
if (this->children[1]->identifier == AST_Node_Type::Array_Call) {
|
||||
try {
|
||||
retval = t_ss->call_function("[]", m_array_loc, {retval, this->children[1]->children[1]->eval(t_ss)}, t_ss.conversions());
|
||||
std::array<Boxed_Value, 2> p{retval, this->children[1]->children[1]->eval(t_ss)};
|
||||
retval = t_ss->call_function("[]", m_array_loc, Function_Params{p}, t_ss.conversions());
|
||||
}
|
||||
catch(const exception::dispatch_error &e){
|
||||
throw exception::eval_error("Can not find appropriate array lookup operator '[]'.", e.parameters, e.functions, true, *t_ss);
|
||||
@ -696,7 +711,7 @@ namespace chaiscript
|
||||
return Boxed_Value(
|
||||
dispatch::make_dynamic_proxy_function(
|
||||
[engine, lambda_node = this->m_lambda_node, param_names = this->m_param_names, captures,
|
||||
this_capture = this->m_this_capture] (const std::vector<Boxed_Value> &t_params)
|
||||
this_capture = this->m_this_capture] (const Function_Params &t_params)
|
||||
{
|
||||
return detail::eval_function(engine, *lambda_node, param_names, t_params, &captures, this_capture);
|
||||
},
|
||||
@ -812,7 +827,7 @@ namespace chaiscript
|
||||
std::shared_ptr<dispatch::Proxy_Function_Base> guard;
|
||||
if (m_guard_node) {
|
||||
guard = dispatch::make_dynamic_proxy_function(
|
||||
[engine, guardnode = m_guard_node, t_param_names](const std::vector<Boxed_Value> &t_params)
|
||||
[engine, guardnode = m_guard_node, t_param_names](const Function_Params &t_params)
|
||||
{
|
||||
return detail::eval_function(engine, *guardnode, t_param_names, t_params);
|
||||
},
|
||||
@ -823,7 +838,7 @@ namespace chaiscript
|
||||
const std::string & l_function_name = this->children[0]->text;
|
||||
t_ss->add(
|
||||
dispatch::make_dynamic_proxy_function(
|
||||
[engine, func_node = m_body_node, t_param_names](const std::vector<Boxed_Value> &t_params)
|
||||
[engine, func_node = m_body_node, t_param_names](const Function_Params &t_params)
|
||||
{
|
||||
return detail::eval_function(engine, *func_node, t_param_names, t_params);
|
||||
},
|
||||
@ -914,7 +929,7 @@ namespace chaiscript
|
||||
};
|
||||
|
||||
const auto call_function = [&t_ss](const auto &t_funcs, const Boxed_Value &t_param) {
|
||||
return dispatch::dispatch(*t_funcs, {t_param}, t_ss.conversions());
|
||||
return dispatch::dispatch(*t_funcs, Function_Params{t_param}, t_ss.conversions());
|
||||
};
|
||||
|
||||
|
||||
@ -963,6 +978,7 @@ namespace chaiscript
|
||||
try {
|
||||
this->children[2]->eval(t_ss);
|
||||
} catch (detail::Continue_Loop &) {
|
||||
// continue statement hit
|
||||
}
|
||||
call_function(pop_front_funcs, range_obj);
|
||||
}
|
||||
@ -1034,7 +1050,8 @@ namespace chaiscript
|
||||
if (this->children[currentCase]->identifier == AST_Node_Type::Case) {
|
||||
//This is a little odd, but because want to see both the switch and the case simultaneously, I do a downcast here.
|
||||
try {
|
||||
if (hasMatched || boxed_cast<bool>(t_ss->call_function("==", m_loc, {match_value, this->children[currentCase]->children[0]->eval(t_ss)}, t_ss.conversions()))) {
|
||||
std::array<Boxed_Value, 2> p{match_value, this->children[currentCase]->children[0]->eval(t_ss)};
|
||||
if (hasMatched || boxed_cast<bool>(t_ss->call_function("==", m_loc, Function_Params{p}, t_ss.conversions()))) {
|
||||
this->children[currentCase]->eval(t_ss);
|
||||
hasMatched = true;
|
||||
}
|
||||
@ -1215,8 +1232,8 @@ namespace chaiscript
|
||||
return Boxed_Number::do_oper(m_oper, bv);
|
||||
} else {
|
||||
chaiscript::eval::detail::Function_Push_Pop fpp(t_ss);
|
||||
fpp.save_params({bv});
|
||||
return t_ss->call_function(this->text, m_loc, {std::move(bv)}, t_ss.conversions());
|
||||
fpp.save_params(Function_Params{bv});
|
||||
return t_ss->call_function(this->text, m_loc, Function_Params{bv}, t_ss.conversions());
|
||||
}
|
||||
} catch (const exception::dispatch_error &e) {
|
||||
throw exception::eval_error("Error with prefix operator evaluation: '" + this->text + "'", e.parameters, e.functions, false, *t_ss);
|
||||
@ -1281,9 +1298,12 @@ namespace chaiscript
|
||||
|
||||
Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override{
|
||||
try {
|
||||
auto oper1 = this->children[0]->children[0]->children[0]->eval(t_ss);
|
||||
auto oper2 = this->children[0]->children[0]->children[1]->eval(t_ss);
|
||||
return t_ss->call_function("generate_range", m_loc, {oper1, oper2}, t_ss.conversions());
|
||||
std::array<Boxed_Value, 2> params{
|
||||
this->children[0]->children[0]->children[0]->eval(t_ss),
|
||||
this->children[0]->children[0]->children[1]->eval(t_ss)
|
||||
};
|
||||
|
||||
return t_ss->call_function("generate_range", m_loc, Function_Params{params}, t_ss.conversions());
|
||||
}
|
||||
catch (const exception::dispatch_error &e) {
|
||||
throw exception::eval_error("Unable to generate range vector, while calling 'generate_range'", e.parameters, e.functions, false, *t_ss);
|
||||
@ -1313,7 +1333,7 @@ namespace chaiscript
|
||||
auto &catch_block = *this->children[i];
|
||||
|
||||
if (catch_block.children.size() == 1) {
|
||||
//No variable capture, no guards
|
||||
//No variable capture
|
||||
retval = catch_block.children[0]->eval(t_ss);
|
||||
break;
|
||||
} else if (catch_block.children.size() == 2 || catch_block.children.size() == 3) {
|
||||
@ -1321,32 +1341,15 @@ namespace chaiscript
|
||||
|
||||
if (dispatch::Param_Types(
|
||||
std::vector<std::pair<std::string, Type_Info>>{Arg_List_AST_Node<T>::get_arg_type(*catch_block.children[0], t_ss)}
|
||||
).match(std::vector<Boxed_Value>{t_except}, t_ss.conversions()).first)
|
||||
).match(Function_Params{t_except}, t_ss.conversions()).first)
|
||||
{
|
||||
t_ss.add_object(name, t_except);
|
||||
|
||||
if (catch_block.children.size() == 2) {
|
||||
//Variable capture, no guards
|
||||
//Variable capture
|
||||
retval = catch_block.children[1]->eval(t_ss);
|
||||
break;
|
||||
}
|
||||
else if (catch_block.children.size() == 3) {
|
||||
//Variable capture, guards
|
||||
|
||||
bool guard = false;
|
||||
try {
|
||||
guard = boxed_cast<bool>(catch_block.children[1]->eval(t_ss));
|
||||
} catch (const exception::bad_boxed_cast &) {
|
||||
if (this->children.back()->identifier == AST_Node_Type::Finally) {
|
||||
this->children.back()->children[0]->eval(t_ss);
|
||||
}
|
||||
throw exception::eval_error("Guard condition not boolean");
|
||||
}
|
||||
if (guard) {
|
||||
retval = catch_block.children[2]->eval(t_ss);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
@ -1451,7 +1454,7 @@ namespace chaiscript
|
||||
std::reference_wrapper<chaiscript::detail::Dispatch_Engine> engine(*t_ss);
|
||||
if (m_guard_node) {
|
||||
guard = dispatch::make_dynamic_proxy_function(
|
||||
[engine, t_param_names, guardnode = m_guard_node](const std::vector<Boxed_Value> &t_params) {
|
||||
[engine, t_param_names, guardnode = m_guard_node](const Function_Params &t_params) {
|
||||
return chaiscript::eval::detail::eval_function(engine, *guardnode, t_param_names, t_params);
|
||||
},
|
||||
static_cast<int>(numparams), m_guard_node);
|
||||
@ -1466,7 +1469,7 @@ namespace chaiscript
|
||||
t_ss->add(
|
||||
std::make_shared<dispatch::detail::Dynamic_Object_Constructor>(class_name,
|
||||
dispatch::make_dynamic_proxy_function(
|
||||
[engine, t_param_names, node = m_body_node](const std::vector<Boxed_Value> &t_params) {
|
||||
[engine, t_param_names, node = m_body_node](const Function_Params &t_params) {
|
||||
return chaiscript::eval::detail::eval_function(engine, *node, t_param_names, t_params);
|
||||
},
|
||||
static_cast<int>(numparams), m_body_node, param_types, guard
|
||||
@ -1483,7 +1486,7 @@ namespace chaiscript
|
||||
t_ss->add(
|
||||
std::make_shared<dispatch::detail::Dynamic_Object_Function>(class_name,
|
||||
dispatch::make_dynamic_proxy_function(
|
||||
[engine, t_param_names, node = m_body_node](const std::vector<Boxed_Value> &t_params) {
|
||||
[engine, t_param_names, node = m_body_node](const Function_Params &t_params) {
|
||||
return chaiscript::eval::detail::eval_function(engine, *node, t_param_names, t_params);
|
||||
},
|
||||
static_cast<int>(numparams), m_body_node, param_types, guard), type),
|
||||
|
||||
@ -285,20 +285,20 @@ namespace chaiscript
|
||||
|
||||
};
|
||||
|
||||
constexpr static std::array<Operator_Precidence, 12> create_operators() noexcept {
|
||||
std::array<Operator_Precidence, 12> operators = { {
|
||||
Operator_Precidence::Ternary_Cond,
|
||||
Operator_Precidence::Logical_Or,
|
||||
Operator_Precidence::Logical_And,
|
||||
Operator_Precidence::Bitwise_Or,
|
||||
Operator_Precidence::Bitwise_Xor,
|
||||
Operator_Precidence::Bitwise_And,
|
||||
Operator_Precidence::Equality,
|
||||
Operator_Precidence::Comparison,
|
||||
Operator_Precidence::Shift,
|
||||
Operator_Precidence::Addition,
|
||||
Operator_Precidence::Multiplication,
|
||||
Operator_Precidence::Prefix
|
||||
constexpr static std::array<Operator_Precedence, 12> create_operators() noexcept {
|
||||
std::array<Operator_Precedence, 12> operators = { {
|
||||
Operator_Precedence::Ternary_Cond,
|
||||
Operator_Precedence::Logical_Or,
|
||||
Operator_Precedence::Logical_And,
|
||||
Operator_Precedence::Bitwise_Or,
|
||||
Operator_Precedence::Bitwise_Xor,
|
||||
Operator_Precedence::Bitwise_And,
|
||||
Operator_Precedence::Equality,
|
||||
Operator_Precedence::Comparison,
|
||||
Operator_Precedence::Shift,
|
||||
Operator_Precedence::Addition,
|
||||
Operator_Precedence::Multiplication,
|
||||
Operator_Precedence::Prefix
|
||||
} };
|
||||
return operators;
|
||||
}
|
||||
@ -1791,11 +1791,6 @@ namespace chaiscript
|
||||
if (!(Arg() && Char(')'))) {
|
||||
throw exception::eval_error("Incomplete 'catch' expression", File_Position(m_position.line, m_position.col), *m_filename);
|
||||
}
|
||||
if (Char(':')) {
|
||||
if (!Operator()) {
|
||||
throw exception::eval_error("Missing guard expression for catch", File_Position(m_position.line, m_position.col), *m_filename);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while (Eol()) {}
|
||||
@ -2471,7 +2466,7 @@ namespace chaiscript
|
||||
bool retval = false;
|
||||
const auto prev_stack_top = m_match_stack.size();
|
||||
|
||||
if (m_operators[t_precedence] != Operator_Precidence::Prefix) {
|
||||
if (m_operators[t_precedence] != Operator_Precedence::Prefix) {
|
||||
if (Operator(t_precedence+1)) {
|
||||
retval = true;
|
||||
std::string oper;
|
||||
@ -2483,7 +2478,7 @@ namespace chaiscript
|
||||
}
|
||||
|
||||
switch (m_operators[t_precedence]) {
|
||||
case(Operator_Precidence::Ternary_Cond) :
|
||||
case(Operator_Precedence::Ternary_Cond) :
|
||||
if (Symbol(":")) {
|
||||
if (!Operator(t_precedence+1)) {
|
||||
throw exception::eval_error("Incomplete '" + oper + "' expression",
|
||||
@ -2497,24 +2492,24 @@ namespace chaiscript
|
||||
}
|
||||
break;
|
||||
|
||||
case(Operator_Precidence::Addition) :
|
||||
case(Operator_Precidence::Multiplication) :
|
||||
case(Operator_Precidence::Shift) :
|
||||
case(Operator_Precidence::Equality) :
|
||||
case(Operator_Precidence::Bitwise_And) :
|
||||
case(Operator_Precidence::Bitwise_Xor) :
|
||||
case(Operator_Precidence::Bitwise_Or) :
|
||||
case(Operator_Precidence::Comparison) :
|
||||
case(Operator_Precedence::Addition) :
|
||||
case(Operator_Precedence::Multiplication) :
|
||||
case(Operator_Precedence::Shift) :
|
||||
case(Operator_Precedence::Equality) :
|
||||
case(Operator_Precedence::Bitwise_And) :
|
||||
case(Operator_Precedence::Bitwise_Xor) :
|
||||
case(Operator_Precedence::Bitwise_Or) :
|
||||
case(Operator_Precedence::Comparison) :
|
||||
build_match<eval::Binary_Operator_AST_Node<Tracer>>(prev_stack_top, oper);
|
||||
break;
|
||||
|
||||
case(Operator_Precidence::Logical_And) :
|
||||
case(Operator_Precedence::Logical_And) :
|
||||
build_match<eval::Logical_And_AST_Node<Tracer>>(prev_stack_top, oper);
|
||||
break;
|
||||
case(Operator_Precidence::Logical_Or) :
|
||||
case(Operator_Precedence::Logical_Or) :
|
||||
build_match<eval::Logical_Or_AST_Node<Tracer>>(prev_stack_top, oper);
|
||||
break;
|
||||
case(Operator_Precidence::Prefix) :
|
||||
case(Operator_Precedence::Prefix) :
|
||||
assert(false); // cannot reach here because of if() statement at the top
|
||||
break;
|
||||
|
||||
|
||||
@ -49,19 +49,6 @@ namespace chaiscript
|
||||
}
|
||||
}
|
||||
|
||||
static T cast_symbol(void *p) noexcept
|
||||
{
|
||||
union cast_union
|
||||
{
|
||||
T func_ptr;
|
||||
void *in_ptr;
|
||||
};
|
||||
|
||||
cast_union c;
|
||||
c.in_ptr = p;
|
||||
return c.func_ptr;
|
||||
}
|
||||
|
||||
T m_symbol;
|
||||
};
|
||||
|
||||
|
||||
@ -96,7 +96,7 @@ class JSON
|
||||
template<auto ClassValue>
|
||||
auto &get_set_type() {
|
||||
set_type(ClassValue);
|
||||
return std::get<static_cast<std::size_t>(ClassValue)>(d);
|
||||
return (std::get<static_cast<std::size_t>(ClassValue)>(d));
|
||||
}
|
||||
|
||||
auto &Map() {
|
||||
|
||||
@ -3,15 +3,29 @@
|
||||
|
||||
namespace chaiscript::utility {
|
||||
|
||||
template<typename Key, typename Value>
|
||||
template<typename Key, typename Value, typename Comparator=std::equal_to<>>
|
||||
struct QuickFlatMap
|
||||
{
|
||||
auto find(const Key &s) noexcept {
|
||||
return std::find_if(std::begin(data), std::end(data), [&s](const auto &d) { return d.first == s; });
|
||||
Comparator comparator;
|
||||
|
||||
template<typename Lookup>
|
||||
auto find(const Lookup &s) noexcept {
|
||||
return std::find_if(std::begin(data), std::end(data), [&s, this](const auto &d) { return comparator(d.first, s); });
|
||||
}
|
||||
|
||||
auto find(const Key &s) const noexcept {
|
||||
return std::find_if(std::begin(data), std::end(data), [&s](const auto &d) { return d.first == s; });
|
||||
template<typename Lookup>
|
||||
auto find(const Lookup &s) const noexcept {
|
||||
return std::find_if(std::cbegin(data), std::cend(data), [&s, this](const auto &d) { return comparator(d.first, s); });
|
||||
}
|
||||
|
||||
template<typename Lookup>
|
||||
auto find(const Lookup &s, const std::size_t t_hint) const noexcept {
|
||||
if (data.size() > t_hint && comparator(data[t_hint].first, s)) {
|
||||
const auto begin = std::cbegin(data);
|
||||
return std::next(begin, static_cast<typename std::iterator_traits<std::decay_t<decltype(begin)>>::difference_type>(t_hint));
|
||||
} else {
|
||||
return find(s);
|
||||
}
|
||||
}
|
||||
|
||||
auto size() const noexcept {
|
||||
@ -35,16 +49,46 @@ namespace chaiscript::utility {
|
||||
return data.end();
|
||||
}
|
||||
|
||||
auto &back() noexcept {
|
||||
return data.back();
|
||||
}
|
||||
|
||||
const auto &back() const noexcept {
|
||||
return data.back();
|
||||
}
|
||||
|
||||
|
||||
Value &operator[](const Key &s) {
|
||||
const auto itr = find(s);
|
||||
if (itr != data.end()) {
|
||||
return itr->second;
|
||||
} else {
|
||||
grow();
|
||||
return data.emplace_back(s, Value()).second;
|
||||
}
|
||||
}
|
||||
|
||||
Value &at_index(const std::size_t idx) noexcept
|
||||
{
|
||||
return data[idx].second;
|
||||
}
|
||||
|
||||
const Value &at_index(const std::size_t idx) const noexcept
|
||||
{
|
||||
return data[idx].second;
|
||||
}
|
||||
|
||||
bool empty() const noexcept
|
||||
{
|
||||
return data.empty();
|
||||
}
|
||||
|
||||
template<typename Itr>
|
||||
void assign(Itr begin, Itr end)
|
||||
{
|
||||
data.assign(begin, end);
|
||||
}
|
||||
|
||||
Value &at(const Key &s) {
|
||||
const auto itr = find(s);
|
||||
if (itr != data.end()) {
|
||||
@ -54,6 +98,32 @@ namespace chaiscript::utility {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<typename M>
|
||||
auto insert_or_assign(Key &&key, M &&m)
|
||||
{
|
||||
if (auto itr = find(key); itr != data.end()) {
|
||||
*itr = std::forward<M>(m);
|
||||
return std::pair{itr, false};
|
||||
} else {
|
||||
grow();
|
||||
return std::pair{data.emplace(data.end(), std::move(key), std::forward<M>(m)), true};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<typename M>
|
||||
auto insert_or_assign(const Key &key, M &&m)
|
||||
{
|
||||
if (auto itr = find(key); itr != data.end()) {
|
||||
itr->second = std::forward<M>(m);
|
||||
return std::pair{itr, false};
|
||||
} else {
|
||||
grow();
|
||||
return std::pair{data.emplace(data.end(), key, std::forward<M>(m)), true};
|
||||
}
|
||||
}
|
||||
|
||||
const Value &at(const Key &s) const {
|
||||
const auto itr = find(s);
|
||||
if (itr != data.end()) {
|
||||
@ -63,15 +133,33 @@ namespace chaiscript::utility {
|
||||
}
|
||||
}
|
||||
|
||||
size_t count(const Key &s) const noexcept {
|
||||
template<typename Lookup>
|
||||
size_t count(const Lookup &s) const noexcept {
|
||||
return (find(s) != data.end())?1:0;
|
||||
}
|
||||
|
||||
std::vector<std::pair<Key, Value>> data;
|
||||
|
||||
using value_type = std::pair<Key, Value>;
|
||||
using iterator = typename decltype(data)::iterator;
|
||||
using const_iterator = typename decltype(data)::const_iterator;
|
||||
|
||||
std::pair<iterator,bool> insert( value_type&& value )
|
||||
{
|
||||
if (const auto itr = find(value.first); itr != data.end()) {
|
||||
return std::pair{itr, false};
|
||||
} else {
|
||||
grow();
|
||||
return std::pair{data.insert(data.end(), std::move(value)), true};
|
||||
}
|
||||
}
|
||||
|
||||
void grow() {
|
||||
if ((data.capacity() - data.size()) == 0) {
|
||||
data.reserve(data.size() + 2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
63
include/chaiscript/utility/stack_vector.hpp
Normal file
63
include/chaiscript/utility/stack_vector.hpp
Normal file
@ -0,0 +1,63 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
||||
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
||||
|
||||
|
||||
#ifndef CHAISCRIPT_STACK_VECTOR_HPP_
|
||||
#define CHAISCRIPT_STACK_VECTOR_HPP_
|
||||
|
||||
#include <cstdint>
|
||||
#include <type_traits>
|
||||
#include <string>
|
||||
|
||||
|
||||
|
||||
template<typename T, std::size_t MaxSize>
|
||||
struct Stack_Vector
|
||||
{
|
||||
constexpr static auto aligned_size = sizeof(T) + (sizeof(T) & std::alignment_of_v<T>) > 0 ? std::alignment_of_v<T> : 0;
|
||||
|
||||
alignas(std::alignment_of_v<T>) char data[aligned_size * MaxSize];
|
||||
|
||||
[[nodiscard]] T & operator[](const std::size_t idx) noexcept {
|
||||
return *reinterpret_cast<T*>(&data + aligned_size * idx);
|
||||
}
|
||||
|
||||
[[nodiscard]] const T & operator[](const std::size_t idx) const noexcept {
|
||||
return *reinterpret_cast<const T*>(&data + aligned_size * idx);
|
||||
}
|
||||
|
||||
template<typename ... Param>
|
||||
T& emplace_back(Param && ... param) {
|
||||
auto *p = new(&(*this)[m_size++]) T(std::forward<Param>(param)...);
|
||||
return *p;
|
||||
};
|
||||
|
||||
auto size() const noexcept {
|
||||
return m_size;
|
||||
};
|
||||
|
||||
void pop_back() noexcept(std::is_nothrow_destructible_v<T>) {
|
||||
(*this)[m_size--].~T();
|
||||
}
|
||||
|
||||
~Stack_Vector() noexcept(std::is_nothrow_destructible_v<T>)
|
||||
{
|
||||
auto loc = m_size - 1;
|
||||
for (std::size_t pos = 0; pos < m_size; ++pos) {
|
||||
(*this)[loc--].~T();
|
||||
}
|
||||
}
|
||||
|
||||
std::size_t m_size{0};
|
||||
|
||||
};
|
||||
|
||||
#endif CHAISCRIPT_STACK_VECTOR_HPP_
|
||||
|
||||
|
||||
@ -145,20 +145,20 @@ std::vector<std::string> default_search_paths()
|
||||
|
||||
void help(int n) {
|
||||
if (n >= 0) {
|
||||
std::cout << "ChaiScript evaluator. To evaluate an expression, type it and press <enter>." << std::endl;
|
||||
std::cout << "Additionally, you can inspect the runtime system using:" << std::endl;
|
||||
std::cout << " dump_system() - outputs all functions registered to the system" << std::endl;
|
||||
std::cout << " dump_object(x) - dumps information about the given symbol" << std::endl;
|
||||
std::cout << "ChaiScript evaluator. To evaluate an expression, type it and press <enter>.\n";
|
||||
std::cout << "Additionally, you can inspect the runtime system using:\n";
|
||||
std::cout << " dump_system() - outputs all functions registered to the system\n";
|
||||
std::cout << " dump_object(x) - dumps information about the given symbol\n";
|
||||
}
|
||||
else {
|
||||
std::cout << "usage : chai [option]+" << std::endl;
|
||||
std::cout << "option:" << std::endl;
|
||||
std::cout << " -h | --help" << std::endl;
|
||||
std::cout << " -i | --interactive" << std::endl;
|
||||
std::cout << " -c | --command cmd" << std::endl;
|
||||
std::cout << " -v | --version" << std::endl;
|
||||
std::cout << " - --stdin" << std::endl;
|
||||
std::cout << " filepath" << std::endl;
|
||||
std::cout << "usage : chai [option]+\n";
|
||||
std::cout << "option:\n";
|
||||
std::cout << " -h | --help\n";
|
||||
std::cout << " -i | --interactive\n";
|
||||
std::cout << " -c | --command cmd\n";
|
||||
std::cout << " -v | --version\n";
|
||||
std::cout << " - --stdin\n";
|
||||
std::cout << " filepath\n";
|
||||
}
|
||||
}
|
||||
|
||||
@ -244,7 +244,7 @@ void interactive(chaiscript::ChaiScript& chai)
|
||||
//Then, we try to print the result of the evaluation to the user
|
||||
if (!val.get_type_info().bare_equal(chaiscript::user_type<void>())) {
|
||||
try {
|
||||
std::cout << chai.eval<std::function<std::string(const chaiscript::Boxed_Value &bv)> >("to_string")(val) << std::endl;
|
||||
std::cout << chai.eval<std::function<std::string(const chaiscript::Boxed_Value &bv)> >("to_string")(val) << '\n';
|
||||
}
|
||||
catch (...) {} //If we can't, do nothing
|
||||
}
|
||||
@ -254,7 +254,7 @@ void interactive(chaiscript::ChaiScript& chai)
|
||||
if (ee.call_stack.size() > 0) {
|
||||
std::cout << "during evaluation at (" << ee.call_stack[0].start().line << ", " << ee.call_stack[0].start().column << ")";
|
||||
}
|
||||
std::cout << std::endl;
|
||||
std::cout << '\n';
|
||||
}
|
||||
catch (const std::exception &e) {
|
||||
std::cout << e.what();
|
||||
|
||||
@ -4,6 +4,11 @@
|
||||
// and Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
|
||||
// NOT TO BE USED AS A SOURCE OF BEST PRACTICES
|
||||
// FOR CHAISCRIPT
|
||||
|
||||
|
||||
#include <iostream>
|
||||
#include <ctime>
|
||||
|
||||
@ -156,7 +161,7 @@ int main(int /*argc*/, char * /*argv*/[]) {
|
||||
|
||||
//Ability to create our own container types when needed. std::vector and std::map are
|
||||
//mostly supported currently
|
||||
chai.add(bootstrap::standard_library::vector_type<std::vector<int> >("IntVector"));
|
||||
//chai.add(bootstrap::standard_library::vector_type<std::vector<int> >("IntVector"));
|
||||
|
||||
|
||||
// Test ability to register a function that excepts a shared_ptr version of a type
|
||||
@ -1,34 +0,0 @@
|
||||
var results = [];
|
||||
|
||||
for (var i = 2; i < 6; ++i) {
|
||||
try {
|
||||
throw(i)
|
||||
}
|
||||
catch(e) : e < 2 {
|
||||
results.push_back("c1: " + e.to_string());
|
||||
}
|
||||
catch(e) : e < 4 {
|
||||
results.push_back("c2: " + e.to_string());
|
||||
}
|
||||
catch(e) {
|
||||
results.push_back("c3: " + e.to_string());
|
||||
}
|
||||
catch {
|
||||
// Should never get called
|
||||
assert_equal(false, true)
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
throw(3)
|
||||
}
|
||||
catch(e) : e < 3
|
||||
{
|
||||
// Should never get called
|
||||
assert_equal(false, true);
|
||||
}
|
||||
catch {
|
||||
results.push_back("defaultcatch");
|
||||
}
|
||||
|
||||
assert_equal(["c2: 2", "c2: 3", "c3: 4", "c3: 5", "defaultcatch"], results);
|
||||
41
unittests/clone_object.chai
Normal file
41
unittests/clone_object.chai
Normal file
@ -0,0 +1,41 @@
|
||||
|
||||
/*
|
||||
global clone_count = 0;
|
||||
|
||||
class Cloneable
|
||||
{
|
||||
def Cloneable() {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
def clone(Cloneable c)
|
||||
{
|
||||
print("Clone called");
|
||||
++clone_count;
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
class MyObject
|
||||
{
|
||||
def MyObject() {
|
||||
this.data = Cloneable();
|
||||
}
|
||||
|
||||
var data;
|
||||
}
|
||||
|
||||
|
||||
assert_equal(0, clone_count);
|
||||
|
||||
var o = MyObject();
|
||||
|
||||
assert_equal(0, clone_count);
|
||||
|
||||
var p = o;
|
||||
|
||||
assert_equal(1, clone_count);
|
||||
*/
|
||||
|
||||
@ -1,34 +0,0 @@
|
||||
auto results = [];
|
||||
|
||||
for (auto i = 2; i < 6; ++i) {
|
||||
try {
|
||||
throw(i)
|
||||
}
|
||||
catch(e) : e < 2 {
|
||||
results.push_back("c1: " + e.to_string());
|
||||
}
|
||||
catch(e) : e < 4 {
|
||||
results.push_back("c2: " + e.to_string());
|
||||
}
|
||||
catch(e) {
|
||||
results.push_back("c3: " + e.to_string());
|
||||
}
|
||||
catch {
|
||||
// Should never get called
|
||||
assert_equal(false, true)
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
throw(3)
|
||||
}
|
||||
catch(e) : e < 3
|
||||
{
|
||||
// Should never get called
|
||||
assert_equal(false, true);
|
||||
}
|
||||
catch {
|
||||
results.push_back("defaultcatch");
|
||||
}
|
||||
|
||||
assert_equal(["c2: 2", "c2: 3", "c3: 4", "c3: 5", "defaultcatch"], results);
|
||||
@ -1,34 +0,0 @@
|
||||
auto results = [];
|
||||
|
||||
for (auto i = 2; i < 6; ++i) {
|
||||
try {
|
||||
throw(i)
|
||||
}
|
||||
catch(int e) : e < 2 {
|
||||
results.push_back("c1: " + e.to_string());
|
||||
}
|
||||
catch(int e) : e < 4 {
|
||||
results.push_back("c2: " + e.to_string());
|
||||
}
|
||||
catch(e) {
|
||||
results.push_back("c3: " + e.to_string());
|
||||
}
|
||||
catch {
|
||||
// Should never get called
|
||||
assert_equal(false, true)
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
throw(3)
|
||||
}
|
||||
catch(int e) : e < 3
|
||||
{
|
||||
// Should never get called
|
||||
assert_equal(false, true);
|
||||
}
|
||||
catch {
|
||||
results.push_back("defaultcatch");
|
||||
}
|
||||
|
||||
assert_equal(["c2: 2", "c2: 3", "c3: 4", "c3: 5", "defaultcatch"], results);
|
||||
Loading…
x
Reference in New Issue
Block a user