Merge remote-tracking branch 'origin/c++17' into develop

This commit is contained in:
Jason Turner 2018-05-29 12:04:34 -06:00
commit c19705da5d
40 changed files with 1479 additions and 1351 deletions

View File

@ -15,7 +15,6 @@ option(BUILD_SAMPLES "Build Samples Folder" FALSE)
option(RUN_FUZZY_TESTS "Run tests generated by AFL" FALSE)
option(USE_STD_MAKE_SHARED "Use std::make_shared instead of chaiscript::make_shared" FALSE)
option(RUN_PERFORMANCE_TESTS "Run Performance Tests" FALSE)
option(BUILD_IN_CPP17_MODE "Build with C++17 flags" FALSE)
mark_as_advanced(USE_STD_MAKE_SHARED)
@ -49,8 +48,8 @@ if(CMAKE_COMPILER_IS_GNUCC OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
option(ENABLE_MEMORY_SANITIZER "Enable memory sanitizer testing in gcc/clang" FALSE)
if(ENABLE_MEMORY_SANITIZER)
add_definitions(-fsanitize=memory -g)
set(LINKER_FLAGS "${LINKER_FLAGS} -fsanitize=memory")
add_definitions(-fsanitize=memory -fsanitize-memory-track-origins -g)
set(LINKER_FLAGS "${LINKER_FLAGS} -fsanitize=memory -fsanitize-memory-track-origins ")
endif()
option(ENABLE_UNDEFINED_SANITIZER "Enable undefined behavior sanitizer testing in gcc/clang" FALSE)
@ -98,8 +97,8 @@ set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/license.txt")
set(CPACK_RESOURCE_FILE_README "${CMAKE_CURRENT_SOURCE_DIR}/readme.md")
set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/description.txt")
set(CPACK_PACKAGE_VERSION_MAJOR 6)
set(CPACK_PACKAGE_VERSION_MINOR 1)
set(CPACK_PACKAGE_VERSION_MAJOR 7)
set(CPACK_PACKAGE_VERSION_MINOR 0)
set(CPACK_PACKAGE_VERSION_PATCH 0)
set(CPACK_PACKAGE_EXECUTABLES "chai;ChaiScript Eval")
@ -149,27 +148,16 @@ if(CMAKE_COMPILER_IS_GNUCC)
if(GCC_VERSION VERSION_LESS 4.9)
set(CPP14_FLAG "-std=c++1y")
else()
if (BUILD_IN_CPP17_MODE)
set(CPP14_FLAG "-std=c++1z")
else()
set(CPP14_FLAG "-std=c++14")
endif()
set(CPP14_FLAG "-std=c++1z")
endif()
else()
if (BUILD_IN_CPP17_MODE)
set(CPP14_FLAG "-std=c++1z")
else()
set(CPP14_FLAG "-std=c++14")
endif()
set(CPP14_FLAG "-std=c++1z")
endif()
if(MSVC)
add_definitions(/W4 /w14545 /w34242 /w34254 /w34287 /w44263 /w44265 /w44296 /w44311 /w44826 /we4289 /w14546 /w14547 /w14549 /w14555 /w14619 /w14905 /w14906 /w14928)
if (BUILD_IN_CPP17_MODE)
add_definitions(/std:c++17)
endif()
add_definitions(/std:c++latest /W4 /w14545 /w34242 /w34254 /w34287 /w44263 /w44265 /w44296 /w44311 /w44826 /we4289 /w14546 /w14547 /w14549 /w14555 /w14619 /w14905 /w14906 /w14928)
add_definitions(/std:c++17)
if (MSVC_VERSION STREQUAL "1800")
@ -190,10 +178,10 @@ 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 -pedantic ${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 ${CPP14_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)
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 )
else()
add_definitions(-Wnoexcept)
endif()

View File

@ -21,6 +21,7 @@ static_assert(_MSC_FULL_VER >= 190024210, "Visual C++ 2015 Update 3 or later req
#endif
#include <vector>
#include <string_view>
#if defined( _LIBCPP_VERSION )
#define CHAISCRIPT_LIBCPP
@ -75,13 +76,13 @@ static_assert(_MSC_FULL_VER >= 190024210, "Visual C++ 2015 Update 3 or later req
#include <cmath>
namespace chaiscript {
static const int version_major = 6;
static const int version_minor = 1;
static const int version_patch = 0;
constexpr static const int version_major = 7;
constexpr static const int version_minor = 0;
constexpr static const int version_patch = 0;
static const char *compiler_version = CHAISCRIPT_COMPILER_VERSION;
static const char *compiler_name = CHAISCRIPT_COMPILER_NAME;
static const bool debug_build = CHAISCRIPT_DEBUG;
constexpr static const char *compiler_version = CHAISCRIPT_COMPILER_VERSION;
constexpr static const char *compiler_name = CHAISCRIPT_COMPILER_NAME;
constexpr static const bool debug_build = CHAISCRIPT_DEBUG;
template<typename B, typename D, typename ...Arg>
inline std::shared_ptr<B> make_shared(Arg && ... arg)
@ -104,17 +105,17 @@ namespace chaiscript {
}
struct Build_Info {
static int version_major()
constexpr static int version_major() noexcept
{
return chaiscript::version_major;
}
static int version_minor()
constexpr static int version_minor() noexcept
{
return chaiscript::version_minor;
}
static int version_patch()
constexpr static int version_patch() noexcept
{
return chaiscript::version_patch;
}
@ -144,7 +145,7 @@ namespace chaiscript {
return chaiscript::compiler_name;
}
static bool debug_build()
constexpr static bool debug_build() noexcept
{
return chaiscript::debug_build;
}
@ -152,10 +153,10 @@ namespace chaiscript {
template<typename T>
auto parse_num(const char *t_str) -> typename std::enable_if<std::is_integral<T>::value, T>::type
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 (char c = *t_str; (c = *t_str) != 0; ++t_str) {
for (const auto c : t_str) {
if (c < '0' || c > '9') {
return t;
}
@ -167,15 +168,14 @@ namespace chaiscript {
template<typename T>
auto parse_num(const char *t_str) -> typename std::enable_if<!std::is_integral<T>::value, T>::type
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{};
T decimal_place = 0;
int exponent = 0;
for (char c;; ++t_str) {
c = *t_str;
for (const auto c : t_str) {
switch (c)
{
case '.':
@ -213,16 +213,24 @@ namespace chaiscript {
}
break;
default:
return exponent ? base * std::pow(T(10), t * static_cast<T>(exponent)) : t;
break;
}
}
return exponent ? base * std::pow(T(10), t * static_cast<T>(exponent)) : t;
}
template<typename T>
T parse_num(const std::string &t_str)
{
return parse_num<T>(t_str.c_str());
struct str_less {
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 {
return std::lexicographical_compare(t_lhs.begin(), t_lhs.end(), t_rhs.begin(), t_rhs.end());
}
struct is_transparent{};
};
enum class Options
{

View File

@ -17,6 +17,7 @@
#ifndef CHAISCRIPT_NO_THREADS
#include <thread>
#include <mutex>
#include <shared_mutex>
#else
#ifndef CHAISCRIPT_NO_THREADS_WARNING
#pragma message ("ChaiScript is compiling without thread safety.")
@ -49,13 +50,13 @@ namespace chaiscript
using unique_lock = std::unique_lock<T>;
template<typename T>
using shared_lock = std::unique_lock<T>;
using shared_lock = std::shared_lock<T>;
template<typename T>
using lock_guard = std::lock_guard<T>;
using shared_mutex = std::mutex;
using std::shared_mutex;
using std::mutex;
@ -78,22 +79,22 @@ namespace chaiscript
t().erase(this);
}
inline const T *operator->() const
inline const T *operator->() const noexcept
{
return &(t()[this]);
}
inline const T &operator*() const
inline const T &operator*() const noexcept
{
return t()[this];
}
inline T *operator->()
inline T *operator->() noexcept
{
return &(t()[this]);
}
inline T &operator*()
inline T &operator*() noexcept
{
return t()[this];
}
@ -102,7 +103,9 @@ namespace chaiscript
void *m_key;
private:
static std::unordered_map<const void*, T> &t()
/// todo: is it valid to make this noexcept? The allocation could fail, but if it
/// does there is no possible way to recover
static std::unordered_map<const void*, T> &t() noexcept
{
thread_local std::unordered_map<const void *, T> my_t;
return my_t;
@ -114,25 +117,25 @@ namespace chaiscript
class unique_lock
{
public:
explicit unique_lock(T &) {}
void lock() {}
void unlock() {}
constexpr explicit unique_lock(T &) noexcept {}
constexpr void lock() noexcept {}
constexpr void unlock() noexcept {}
};
template<typename T>
class shared_lock
{
public:
explicit shared_lock(T &) {}
void lock() {}
void unlock() {}
constexpr explicit shared_lock(T &) noexcept {}
constexpr void lock() noexcept {}
constexpr void unlock() noexcept {}
};
template<typename T>
class lock_guard
{
public:
explicit lock_guard(T &) {}
constexpr explicit lock_guard(T &) noexcept {}
};
class shared_mutex { };
@ -144,16 +147,16 @@ namespace chaiscript
class Thread_Storage
{
public:
explicit Thread_Storage()
constexpr explicit Thread_Storage() noexcept
{
}
inline T *operator->() const
constexpr inline T *operator->() const noexcept
{
return &obj;
}
inline T &operator*() const
constexpr inline T &operator*() const noexcept
{
return obj;
}

View File

@ -21,20 +21,11 @@ namespace chaiscript {
class bad_any_cast : public std::bad_cast
{
public:
bad_any_cast() = default;
bad_any_cast(const bad_any_cast &) = default;
~bad_any_cast() noexcept override = default;
/// \brief Description of what error occurred
const char * what() const noexcept override
{
return m_what.c_str();
return "bad any cast";
}
private:
std::string m_what = "bad any cast";
};
}
@ -43,18 +34,18 @@ namespace chaiscript {
private:
struct Data
{
explicit Data(const std::type_info &t_type)
constexpr explicit Data(const std::type_info &t_type) noexcept
: m_type(t_type)
{
}
Data &operator=(const Data &) = delete;
virtual ~Data() = default;
virtual ~Data() noexcept = default;
virtual void *data() = 0;
virtual void *data() noexcept = 0;
const std::type_info &type() const
const std::type_info &type() const noexcept
{
return m_type;
}
@ -72,14 +63,14 @@ namespace chaiscript {
{
}
void *data() override
void *data() noexcept override
{
return &m_data;
}
std::unique_ptr<Data> clone() const override
{
return std::unique_ptr<Data>(new Data_Impl<T>(m_data));
return std::make_unique<Data_Impl<T>>(m_data);
}
Data_Impl &operator=(const Data_Impl&) = delete;
@ -91,25 +82,19 @@ namespace chaiscript {
public:
// construct/copy/destruct
Any() = default;
constexpr Any() noexcept = default;
Any(Any &&) = default;
Any &operator=(Any &&t_any) = default;
Any(const Any &t_any)
{
if (!t_any.empty())
{
m_data = t_any.m_data->clone();
} else {
m_data.reset();
}
Any(const Any &t_any)
: m_data(t_any.empty() ? nullptr : t_any.m_data->clone())
{
}
template<typename ValueType,
typename = typename std::enable_if<!std::is_same<Any, typename std::decay<ValueType>::type>::value>::type>
typename = std::enable_if_t<!std::is_same_v<Any, std::decay_t<ValueType>>>>
explicit Any(ValueType &&t_value)
: m_data(std::unique_ptr<Data>(new Data_Impl<typename std::decay<ValueType>::type>(std::forward<ValueType>(t_value))))
: m_data(std::make_unique<Data_Impl<std::decay_t<ValueType>>>(std::forward<ValueType>(t_value)))
{
}
@ -141,12 +126,12 @@ namespace chaiscript {
}
// queries
bool empty() const
bool empty() const noexcept
{
return !bool(m_data);
}
const std::type_info & type() const
const std::type_info & type() const noexcept
{
if (m_data) {
return m_data->type();

View File

@ -15,6 +15,7 @@
#include <typeinfo>
#include "../chaiscript_defines.hpp"
#include "../utility/static_string.hpp"
#include "type_info.hpp"
namespace chaiscript {
@ -34,22 +35,22 @@ namespace chaiscript
{
public:
bad_boxed_cast(Type_Info t_from, const std::type_info &t_to,
std::string t_what) noexcept
utility::Static_String t_what) noexcept
: from(t_from), to(&t_to), m_what(std::move(t_what))
{
}
bad_boxed_cast(Type_Info t_from, const std::type_info &t_to)
: from(t_from), to(&t_to), m_what("Cannot perform boxed_cast: " + t_from.name() + " to: " + t_to.name())
bad_boxed_cast(Type_Info t_from, const std::type_info &t_to) noexcept
: from(t_from), to(&t_to), m_what("Cannot perform boxed_cast")
{
}
explicit bad_boxed_cast(std::string t_what) noexcept
explicit bad_boxed_cast(utility::Static_String t_what) noexcept
: m_what(std::move(t_what))
{
}
bad_boxed_cast(const bad_boxed_cast &) = default;
bad_boxed_cast(const bad_boxed_cast &) noexcept = default;
~bad_boxed_cast() noexcept override = default;
/// \brief Description of what error occurred
@ -62,7 +63,7 @@ namespace chaiscript
const std::type_info *to = nullptr; ///< std::type_info of the desired (but failed) result type
private:
std::string m_what;
utility::Static_String m_what;
};
}
}

View File

@ -19,37 +19,37 @@ namespace chaiscript
{
template<typename T>
T* get_pointer(T *t)
constexpr T* get_pointer(T *t) noexcept
{
return t;
}
template<typename T>
T* get_pointer(const std::reference_wrapper<T> &t)
T* get_pointer(const std::reference_wrapper<T> &t) noexcept
{
return &t.get();
}
template<typename O, typename Ret, typename P1, typename ... Param>
auto bind_first(Ret (*f)(P1, Param...), O&& o)
constexpr auto bind_first(Ret (*f)(P1, Param...), O&& o)
{
return [f, o](Param...param) -> Ret {
return f(std::forward<O>(o), std::forward<Param>(param)...);
return [f, o = std::forward<O>(o)](Param...param) -> Ret {
return f(o, std::forward<Param>(param)...);
};
}
template<typename O, typename Ret, typename Class, typename ... Param>
auto bind_first(Ret (Class::*f)(Param...), O&& o)
constexpr auto bind_first(Ret (Class::*f)(Param...), O&& o)
{
return [f, o](Param...param) -> Ret {
return [f, o = std::forward<O>(o)](Param...param) -> Ret {
return (get_pointer(o)->*f)(std::forward<Param>(param)...);
};
}
template<typename O, typename Ret, typename Class, typename ... Param>
auto bind_first(Ret (Class::*f)(Param...) const, O&& o)
constexpr auto bind_first(Ret (Class::*f)(Param...) const, O&& o)
{
return [f, o](Param...param) -> Ret {
return [f, o = std::forward<O>(o)](Param...param) -> Ret {
return (get_pointer(o)->*f)(std::forward<Param>(param)...);
};
@ -58,22 +58,22 @@ namespace chaiscript
template<typename O, typename Ret, typename P1, typename ... Param>
auto bind_first(const std::function<Ret (P1, Param...)> &f, O&& o)
{
return [f, o](Param...param) -> Ret {
return [f, o = std::forward<O>(o)](Param...param) -> Ret {
return f(o, std::forward<Param>(param)...);
};
}
template<typename F, typename O, typename Ret, typename Class, typename P1, typename ... Param>
auto bind_first(const F &fo, O&& o, Ret (Class::*f)(P1, Param...) const)
constexpr auto bind_first(const F &fo, O&& o, Ret (Class::*f)(P1, Param...) const)
{
return [fo, o, f](Param ...param) -> Ret {
return [fo, o = std::forward<O>(o), f](Param ...param) -> Ret {
return (fo.*f)(o, std::forward<Param>(param)...);
};
}
template<typename F, typename O>
auto bind_first(const F &f, O&& o)
constexpr auto bind_first(const F &f, O&& o)
{
return bind_first(f, std::forward<O>(o), &F::operator());
}

View File

@ -22,11 +22,12 @@ namespace chaiscript
template<typename T, typename = typename std::enable_if<std::is_array<T>::value>::type >
void array(const std::string &type, Module& m)
{
typedef typename std::remove_extent<T>::type ReturnType;
using ReturnType = typename std::remove_extent<T>::type;
m.add(user_type<T>(), type);
m.add(fun(
[](T& t, size_t index)->ReturnType &{
constexpr auto extent = std::extent<T>::value;
constexpr const auto extent = std::extent<T>::value;
if (extent > 0 && index >= extent) {
throw std::range_error("Array index out of range. Received: " + std::to_string(index) + " expected < " + std::to_string(extent));
} else {
@ -38,7 +39,7 @@ namespace chaiscript
m.add(fun(
[](const T &t, size_t index)->const ReturnType &{
constexpr auto extent = std::extent<T>::value;
constexpr const auto extent = std::extent<T>::value;
if (extent > 0 && index >= extent) {
throw std::range_error("Array index out of range. Received: " + std::to_string(index) + " expected < " + std::to_string(extent));
} else {
@ -50,8 +51,7 @@ namespace chaiscript
m.add(fun(
[](const T &) {
constexpr auto extent = std::extent<T>::value;
return extent;
return std::extent<T>::value;
}), "size");
}
@ -111,31 +111,20 @@ namespace chaiscript
/// Internal function for converting from a string to a value
/// uses ostream operator >> to perform the conversion
template<typename Input>
auto parse_string(const std::string &i)
-> typename std::enable_if<
!std::is_same<Input, wchar_t>::value
&& !std::is_same<Input, char16_t>::value
&& !std::is_same<Input, char32_t>::value,
Input>::type
Input parse_string(const std::string &i)
{
std::stringstream ss(i);
Input t;
ss >> t;
return t;
if constexpr (!std::is_same<Input, wchar_t>::value
&& !std::is_same<Input, char16_t>::value
&& !std::is_same<Input, char32_t>::value) {
std::stringstream ss(i);
Input t;
ss >> t;
return t;
} else {
throw std::runtime_error("Parsing of wide characters is not yet supported");
}
}
template<typename Input>
auto parse_string(const std::string &)
-> typename std::enable_if<
std::is_same<Input, wchar_t>::value
|| std::is_same<Input, char16_t>::value
|| std::is_same<Input, char32_t>::value,
Input>::type
{
throw std::runtime_error("Parsing of wide characters is not yet supported");
}
/// Add all common functions for a POD type. All operators, and
/// common conversions
template<typename T>
@ -202,12 +191,12 @@ namespace chaiscript
}
}
static void print(const std::string &s)
static void print(const std::string &s) noexcept
{
fwrite(s.c_str(), 1, s.size(), stdout);
}
static void println(const std::string &s)
static void println(const std::string &s) noexcept
{
puts(s.c_str());
}
@ -271,10 +260,10 @@ namespace chaiscript
}
static bool has_guard(const Const_Proxy_Function &t_pf)
static bool has_guard(const Const_Proxy_Function &t_pf) noexcept
{
auto pf = std::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(t_pf);
return pf && pf->get_guard();
return pf && pf->has_guard();
}
static Const_Proxy_Function get_guard(const Const_Proxy_Function &t_pf)
@ -305,7 +294,7 @@ namespace chaiscript
}
static bool has_parse_tree(const chaiscript::Const_Proxy_Function &t_pf)
static bool has_parse_tree(const chaiscript::Const_Proxy_Function &t_pf) noexcept
{
const auto pf = std::dynamic_pointer_cast<const chaiscript::dispatch::Dynamic_Proxy_Function>(t_pf);
return bool(pf);

View File

@ -44,19 +44,19 @@ namespace chaiscript
template<typename Container, typename IterType>
struct Bidir_Range
{
typedef Container container_type;
using container_type = Container;
Bidir_Range(Container &c)
constexpr Bidir_Range(Container &c)
: m_begin(c.begin()), m_end(c.end())
{
}
bool empty() const
constexpr bool empty() const noexcept
{
return m_begin == m_end;
}
void pop_front()
constexpr void pop_front()
{
if (empty())
{
@ -65,7 +65,7 @@ namespace chaiscript
++m_begin;
}
void pop_back()
constexpr void pop_back()
{
if (empty())
{
@ -74,7 +74,7 @@ namespace chaiscript
--m_end;
}
decltype(auto) front() const
constexpr decltype(auto) front() const
{
if (empty())
{
@ -83,7 +83,7 @@ namespace chaiscript
return (*m_begin);
}
decltype(auto) back() const
constexpr decltype(auto) back() const
{
if (empty())
{
@ -355,7 +355,7 @@ namespace chaiscript
, "back");
typedef void (ContainerType::*push_back)(const typename ContainerType::value_type &);
using push_back = void (ContainerType::*)(const typename ContainerType::value_type &);
m.add(fun(static_cast<push_back>(&ContainerType::push_back)),
[&]()->std::string{
if (typeid(typename ContainerType::value_type) == typeid(Boxed_Value)) {
@ -395,8 +395,8 @@ namespace chaiscript
template<typename ContainerType>
void front_insertion_sequence_type(const std::string &type, Module& m)
{
typedef void (ContainerType::*push_ptr)(typename ContainerType::const_reference);
typedef void (ContainerType::*pop_ptr)();
using push_ptr = void (ContainerType::*)(typename ContainerType::const_reference);
using pop_ptr = void (ContainerType::*)();
m.add(fun([](ContainerType &container)->decltype(auto){
if (container.empty()) {
@ -498,7 +498,7 @@ namespace chaiscript
{
m.add(fun(detail::count<ContainerType>), "count");
typedef size_t (ContainerType::*erase_ptr)(const typename ContainerType::key_type &);
using erase_ptr = size_t (ContainerType::*)(const typename ContainerType::key_type &);
m.add(fun(static_cast<erase_ptr>(&ContainerType::erase)), "erase");
@ -529,8 +529,8 @@ namespace chaiscript
{
m.add(user_type<MapType>(), type);
typedef typename MapType::mapped_type &(MapType::*elem_access)(const typename MapType::key_type &);
typedef const typename MapType::mapped_type &(MapType::*const_elem_access)(const typename MapType::key_type &) const;
using elem_access = typename MapType::mapped_type &(MapType::*)(const typename MapType::key_type &);
using const_elem_access = const typename MapType::mapped_type &(MapType::*)(const typename MapType::key_type &) const;
m.add(fun(static_cast<elem_access>(&MapType::operator[])), "[]");

View File

@ -27,7 +27,7 @@ namespace chaiscript
// Cast_Helper_Inner helper classes
template<typename T>
T* throw_if_null(T *t)
constexpr T* throw_if_null(T *t)
{
if (t) { return t; }
throw std::runtime_error("Attempted to dereference null Boxed_Value");

View File

@ -59,6 +59,7 @@ namespace chaiscript
#pragma GCC diagnostic ignored "-Wconversion"
#pragma GCC diagnostic ignored "-Wsign-conversion"
#pragma GCC diagnostic ignored "-Wfloat-conversion"
#pragma GCC diagnostic ignored "-Wswitch"
#endif
/// \brief Represents any numeric type, generically. Used internally for generic operations between POD values
@ -80,21 +81,18 @@ namespace chaiscript
};
template<typename T>
static inline void check_divide_by_zero(T t, typename std::enable_if<std::is_integral<T>::value>::type* = nullptr)
constexpr static inline void check_divide_by_zero([[maybe_unused]] T t)
{
#ifndef CHAISCRIPT_NO_PROTECT_DIVIDEBYZERO
if (t == 0) {
throw chaiscript::exception::arithmetic_error("divide by zero");
if constexpr (!std::is_floating_point<T>::value) {
if (t == 0) {
throw chaiscript::exception::arithmetic_error("divide by zero");
}
}
#endif
}
template<typename T>
static inline void check_divide_by_zero(T, typename std::enable_if<std::is_floating_point<T>::value>::type* = nullptr)
{
}
static constexpr Common_Types get_common_type(size_t t_size, bool t_signed)
constexpr static Common_Types get_common_type(size_t t_size, bool t_signed) noexcept
{
return (t_size == 1 && t_signed)?(Common_Types::t_int8)
:(t_size == 1)?(Common_Types::t_uint8)
@ -111,378 +109,234 @@ namespace chaiscript
{
const Type_Info &inp_ = t_bv.get_type_info();
if (inp_ == typeid(int)) {
if (inp_ == user_type<int>()) {
return get_common_type(sizeof(int), true);
} else if (inp_ == typeid(double)) {
} else if (inp_ == user_type<double>()) {
return Common_Types::t_double;
} else if (inp_ == typeid(long double)) {
} else if (inp_ == user_type<long double>()) {
return Common_Types::t_long_double;
} else if (inp_ == typeid(float)) {
} else if (inp_ == user_type<float>()) {
return Common_Types::t_float;
} else if (inp_ == typeid(char)) {
} else if (inp_ == user_type<char>()) {
return get_common_type(sizeof(char), std::is_signed<char>::value);
} else if (inp_ == typeid(unsigned char)) {
} else if (inp_ == user_type<unsigned char>()) {
return get_common_type(sizeof(unsigned char), false);
} else if (inp_ == typeid(unsigned int)) {
} else if (inp_ == user_type<unsigned int>()) {
return get_common_type(sizeof(unsigned int), false);
} else if (inp_ == typeid(long)) {
} else if (inp_ == user_type<long>()) {
return get_common_type(sizeof(long), true);
} else if (inp_ == typeid(long long)) {
} else if (inp_ == user_type<long long>()) {
return get_common_type(sizeof(long long), true);
} else if (inp_ == typeid(unsigned long)) {
} else if (inp_ == user_type<unsigned long>()) {
return get_common_type(sizeof(unsigned long), false);
} else if (inp_ == typeid(unsigned long long)) {
} else if (inp_ == user_type<unsigned long long>()) {
return get_common_type(sizeof(unsigned long long), false);
} else if (inp_ == typeid(std::int8_t)) {
} else if (inp_ == user_type<std::int8_t>()) {
return Common_Types::t_int8;
} else if (inp_ == typeid(std::int16_t)) {
} else if (inp_ == user_type<std::int16_t>()) {
return Common_Types::t_int16;
} else if (inp_ == typeid(std::int32_t)) {
} else if (inp_ == user_type<std::int32_t>()) {
return Common_Types::t_int32;
} else if (inp_ == typeid(std::int64_t)) {
} else if (inp_ == user_type<std::int64_t>()) {
return Common_Types::t_int64;
} else if (inp_ == typeid(std::uint8_t)) {
} else if (inp_ == user_type<std::uint8_t>()) {
return Common_Types::t_uint8;
} else if (inp_ == typeid(std::uint16_t)) {
} else if (inp_ == user_type<std::uint16_t>()) {
return Common_Types::t_uint16;
} else if (inp_ == typeid(std::uint32_t)) {
} else if (inp_ == user_type<std::uint32_t>()) {
return Common_Types::t_uint32;
} else if (inp_ == typeid(std::uint64_t)) {
} else if (inp_ == user_type<std::uint64_t>()) {
return Common_Types::t_uint64;
} else if (inp_ == typeid(wchar_t)) {
} else if (inp_ == user_type<wchar_t>()) {
return get_common_type(sizeof(wchar_t), std::is_signed<wchar_t>::value);
} else if (inp_ == typeid(char16_t)) {
} else if (inp_ == user_type<char16_t>()) {
return get_common_type(sizeof(char16_t), std::is_signed<char16_t>::value);
} else if (inp_ == typeid(char32_t)) {
} else if (inp_ == user_type<char32_t>()) {
return get_common_type(sizeof(char32_t), std::is_signed<char32_t>::value);
} else {
throw chaiscript::detail::exception::bad_any_cast();
}
}
template<typename T>
static Boxed_Value boolean_go(Operators::Opers t_oper, const T &t, const T &u)
template<typename LHS, typename RHS>
static auto go(Operators::Opers t_oper, const Boxed_Value &t_bv, LHS *t_lhs, const LHS &c_lhs, const RHS &c_rhs)
{
switch (t_oper)
{
switch (t_oper) {
case Operators::Opers::equals:
return const_var(t == u);
return const_var(c_lhs == c_rhs);
case Operators::Opers::less_than:
return const_var(t < u);
return const_var(c_lhs < c_rhs);
case Operators::Opers::greater_than:
return const_var(t > u);
return const_var(c_lhs > c_rhs);
case Operators::Opers::less_than_equal:
return const_var(t <= u);
return const_var(c_lhs <= c_rhs);
case Operators::Opers::greater_than_equal:
return const_var(t >= u);
return const_var(c_lhs >= c_rhs);
case Operators::Opers::not_equal:
return const_var(t != u);
default:
throw chaiscript::detail::exception::bad_any_cast();
}
}
template<typename T>
static Boxed_Value unary_go(Operators::Opers t_oper, T &t, const Boxed_Value &t_lhs)
{
switch (t_oper)
{
case Operators::Opers::pre_increment:
++t;
break;
case Operators::Opers::pre_decrement:
--t;
break;
default:
throw chaiscript::detail::exception::bad_any_cast();
}
return t_lhs;
}
template<typename T, typename U>
static Boxed_Value binary_go(Operators::Opers t_oper, T &t, const U &u, const Boxed_Value &t_lhs)
{
switch (t_oper)
{
case Operators::Opers::assign:
t = u;
break;
case Operators::Opers::assign_product:
t *= u;
break;
case Operators::Opers::assign_sum:
t += u;
break;
case Operators::Opers::assign_quotient:
check_divide_by_zero(u);
t /= u;
break;
case Operators::Opers::assign_difference:
t -= u;
break;
default:
throw chaiscript::detail::exception::bad_any_cast();
}
return t_lhs;
}
template<typename T, typename U>
static Boxed_Value binary_int_go(Operators::Opers t_oper, T &t, const U &u, const Boxed_Value &t_lhs)
{
switch (t_oper)
{
case Operators::Opers::assign_bitwise_and:
t &= u;
break;
case Operators::Opers::assign_bitwise_or:
t |= u;
break;
case Operators::Opers::assign_shift_left:
t <<= u;
break;
case Operators::Opers::assign_shift_right:
t >>= u;
break;
case Operators::Opers::assign_remainder:
check_divide_by_zero(u);
t %= u;
break;
case Operators::Opers::assign_bitwise_xor:
t ^= u;
break;
default:
throw chaiscript::detail::exception::bad_any_cast();
}
return t_lhs;
}
template<typename T>
static Boxed_Value const_unary_int_go(Operators::Opers t_oper, const T &t)
{
switch (t_oper)
{
case Operators::Opers::bitwise_complement:
return const_var(~t);
default:
throw chaiscript::detail::exception::bad_any_cast();
}
}
template<typename T>
static Boxed_Value const_binary_int_go(Operators::Opers t_oper, const T &t, const T &u)
{
switch (t_oper)
{
case Operators::Opers::shift_left:
return const_var(t << u);
case Operators::Opers::shift_right:
return const_var(t >> u);
case Operators::Opers::remainder:
check_divide_by_zero(u);
return const_var(t % u);
case Operators::Opers::bitwise_and:
return const_var(t & u);
case Operators::Opers::bitwise_or:
return const_var(t | u);
case Operators::Opers::bitwise_xor:
return const_var(t ^ u);
default:
throw chaiscript::detail::exception::bad_any_cast();
}
}
template<typename T>
static Boxed_Value const_unary_go(Operators::Opers t_oper, const T &t)
{
switch (t_oper)
{
case Operators::Opers::unary_minus:
return const_var(-t);
case Operators::Opers::unary_plus:
return const_var(+t);
default:
throw chaiscript::detail::exception::bad_any_cast();
}
}
template<typename T>
static Boxed_Value const_binary_go(Operators::Opers t_oper, const T &t, const T &u)
{
switch (t_oper)
{
return const_var(c_lhs != c_rhs);
case Operators::Opers::sum:
return const_var(t + u);
return const_var(c_lhs + c_rhs);
case Operators::Opers::quotient:
check_divide_by_zero(u);
return const_var(t / u);
check_divide_by_zero(c_rhs);
return const_var(c_lhs / c_rhs);
case Operators::Opers::product:
return const_var(t * u);
return const_var(c_lhs * c_rhs);
case Operators::Opers::difference:
return const_var(t - u);
default:
throw chaiscript::detail::exception::bad_any_cast();
return const_var(c_lhs - c_rhs);
}
}
template<typename LHS, typename RHS>
static auto go(Operators::Opers t_oper, const Boxed_Value &t_lhs, const Boxed_Value &t_rhs)
-> typename std::enable_if<!std::is_floating_point<LHS>::value && !std::is_floating_point<RHS>::value, Boxed_Value>::type
{
typedef typename std::common_type<LHS, RHS>::type common_type;
if (t_oper > Operators::Opers::boolean_flag && t_oper < Operators::Opers::non_const_flag)
{
return boolean_go(t_oper, get_as_aux<common_type, LHS>(t_lhs), get_as_aux<common_type, RHS>(t_rhs));
} else if (t_oper > Operators::Opers::non_const_flag && t_oper < Operators::Opers::non_const_int_flag && !t_lhs.is_const() && !t_lhs.is_return_value()) {
return binary_go(t_oper, *static_cast<LHS *>(t_lhs.get_ptr()), get_as_aux<common_type, RHS>(t_rhs), t_lhs);
} else if (t_oper > Operators::Opers::non_const_int_flag && t_oper < Operators::Opers::const_int_flag && !t_lhs.is_const() && !t_lhs.is_return_value()) {
return binary_int_go(t_oper, *static_cast<LHS *>(t_lhs.get_ptr()), get_as_aux<common_type, RHS>(t_rhs), t_lhs);
} else if (t_oper > Operators::Opers::const_int_flag && t_oper < Operators::Opers::const_flag) {
return const_binary_int_go(t_oper, get_as_aux<common_type, LHS>(t_lhs), get_as_aux<common_type, RHS>(t_rhs));
} else if (t_oper > Operators::Opers::const_flag) {
return const_binary_go(t_oper, get_as_aux<common_type, LHS>(t_lhs), get_as_aux<common_type, RHS>(t_rhs));
} else {
throw chaiscript::detail::exception::bad_any_cast();
if constexpr (!std::is_floating_point<LHS>::value && !std::is_floating_point<RHS>::value) {
switch (t_oper) {
case Operators::Opers::shift_left:
return const_var(c_lhs << c_rhs);
case Operators::Opers::shift_right:
return const_var(c_lhs >> c_rhs);
case Operators::Opers::remainder:
check_divide_by_zero(c_rhs);
return const_var(c_lhs % c_rhs);
case Operators::Opers::bitwise_and:
return const_var(c_lhs & c_rhs);
case Operators::Opers::bitwise_or:
return const_var(c_lhs | c_rhs);
case Operators::Opers::bitwise_xor:
return const_var(c_lhs ^ c_rhs);
}
}
}
template<typename LHS, typename RHS>
static auto go(Operators::Opers t_oper, const Boxed_Value &t_lhs, const Boxed_Value &t_rhs)
-> typename std::enable_if<std::is_floating_point<LHS>::value || std::is_floating_point<RHS>::value, Boxed_Value>::type
{
typedef typename std::common_type<LHS, RHS>::type common_type;
if (t_oper > Operators::Opers::boolean_flag && t_oper < Operators::Opers::non_const_flag)
{
return boolean_go(t_oper, get_as_aux<common_type, LHS>(t_lhs), get_as_aux<common_type, RHS>(t_rhs));
} else if (t_oper > Operators::Opers::non_const_flag && t_oper < Operators::Opers::non_const_int_flag && !t_lhs.is_const() && !t_lhs.is_return_value()) {
return binary_go(t_oper, *static_cast<LHS *>(t_lhs.get_ptr()), get_as_aux<common_type, RHS>(t_rhs), t_lhs);
} else if (t_oper > Operators::Opers::const_flag) {
return const_binary_go(t_oper, get_as_aux<common_type, LHS>(t_lhs), get_as_aux<common_type, RHS>(t_rhs));
} else {
throw chaiscript::detail::exception::bad_any_cast();
}
}
// Unary
template<typename LHS>
static auto go(Operators::Opers t_oper, const Boxed_Value &t_lhs)
-> typename std::enable_if<!std::is_floating_point<LHS>::value, Boxed_Value>::type
{
if (t_oper > Operators::Opers::non_const_flag && t_oper < Operators::Opers::non_const_int_flag && !t_lhs.is_const() && !t_lhs.is_return_value()) {
return unary_go(t_oper, *static_cast<LHS *>(t_lhs.get_ptr()), t_lhs);
} else if (t_oper > Operators::Opers::const_int_flag && t_oper < Operators::Opers::const_flag) {
return const_unary_int_go(t_oper, *static_cast<const LHS *>(t_lhs.get_const_ptr()));
} else if (t_oper > Operators::Opers::const_flag) {
return const_unary_go(t_oper, *static_cast<const LHS *>(t_lhs.get_const_ptr()));
} else {
throw chaiscript::detail::exception::bad_any_cast();
}
}
template<typename LHS>
static auto go(Operators::Opers t_oper, const Boxed_Value &t_lhs)
-> typename std::enable_if<std::is_floating_point<LHS>::value, Boxed_Value>::type
{
if (t_oper > Operators::Opers::non_const_flag && t_oper < Operators::Opers::non_const_int_flag && !t_lhs.is_const() && !t_lhs.is_return_value()) {
return unary_go(t_oper, *static_cast<LHS *>(t_lhs.get_ptr()), t_lhs);
} else if (t_oper > Operators::Opers::const_flag) {
return const_unary_go(t_oper, *static_cast<const LHS *>(t_lhs.get_const_ptr()));
} else {
throw chaiscript::detail::exception::bad_any_cast();
}
}
template<typename LHS>
inline static Boxed_Value oper_rhs(Operators::Opers t_oper, const Boxed_Value &t_lhs, const Boxed_Value &t_rhs)
{
switch (get_common_type(t_rhs)) {
case Common_Types::t_int32:
return go<LHS, int32_t>(t_oper, t_lhs, t_rhs);
case Common_Types::t_uint8:
return go<LHS, uint8_t>(t_oper, t_lhs, t_rhs);
case Common_Types::t_int8:
return go<LHS, int8_t>(t_oper, t_lhs, t_rhs);
case Common_Types::t_uint16:
return go<LHS, uint16_t>(t_oper, t_lhs, t_rhs);
case Common_Types::t_int16:
return go<LHS, int16_t>(t_oper, t_lhs, t_rhs);
case Common_Types::t_uint32:
return go<LHS, uint32_t>(t_oper, t_lhs, t_rhs);
case Common_Types::t_uint64:
return go<LHS, uint64_t>(t_oper, t_lhs, t_rhs);
case Common_Types::t_int64:
return go<LHS, int64_t>(t_oper, t_lhs, t_rhs);
case Common_Types::t_double:
return go<LHS, double>(t_oper, t_lhs, t_rhs);
case Common_Types::t_float:
return go<LHS, float>(t_oper, t_lhs, t_rhs);
case Common_Types::t_long_double:
return go<LHS, long double>(t_oper, t_lhs, t_rhs);
if (t_lhs) {
switch (t_oper) {
case Operators::Opers::assign:
*t_lhs = c_rhs;
return t_bv;
case Operators::Opers::assign_product:
*t_lhs *= c_rhs;
return t_bv;
case Operators::Opers::assign_sum:
*t_lhs += c_rhs;
return t_bv;
case Operators::Opers::assign_quotient:
check_divide_by_zero(c_rhs);
*t_lhs /= c_rhs;
return t_bv;
case Operators::Opers::assign_difference:
*t_lhs -= c_rhs;
return t_bv;
}
throw chaiscript::detail::exception::bad_any_cast();
if constexpr (!std::is_floating_point<LHS>::value && !std::is_floating_point<RHS>::value) {
switch (t_oper) {
case Operators::Opers::assign_bitwise_and:
check_divide_by_zero(c_rhs);
*t_lhs &= c_rhs;
return t_bv;
case Operators::Opers::assign_bitwise_or:
*t_lhs |= c_rhs;
return t_bv;
case Operators::Opers::assign_shift_left:
*t_lhs <<= c_rhs;
return t_bv;
case Operators::Opers::assign_shift_right:
*t_lhs >>= c_rhs;
return t_bv;
case Operators::Opers::assign_remainder:
*t_lhs %= c_rhs;
return t_bv;
case Operators::Opers::assign_bitwise_xor:
*t_lhs ^= c_rhs;
return t_bv;
}
}
}
throw chaiscript::detail::exception::bad_any_cast();
}
template<typename Callable>
inline static auto visit(const Boxed_Value &bv, Callable &&callable)
{
switch (get_common_type(bv)) {
case Common_Types::t_int32:
return callable(*static_cast<const std::int32_t *>(bv.get_const_ptr()));
case Common_Types::t_uint8:
return callable(*static_cast<const std::uint8_t *>(bv.get_const_ptr()));
case Common_Types::t_int8:
return callable(*static_cast<const std::int8_t *>(bv.get_const_ptr()));
case Common_Types::t_uint16:
return callable(*static_cast<const std::uint16_t *>(bv.get_const_ptr()));
case Common_Types::t_int16:
return callable(*static_cast<const std::int16_t *>(bv.get_const_ptr()));
case Common_Types::t_uint32:
return callable(*static_cast<const std::uint32_t *>(bv.get_const_ptr()));
case Common_Types::t_uint64:
return callable(*static_cast<const std::uint64_t *>(bv.get_const_ptr()));
case Common_Types::t_int64:
return callable(*static_cast<const std::int64_t *>(bv.get_const_ptr()));
case Common_Types::t_double:
return callable(*static_cast<const double *>(bv.get_const_ptr()));
case Common_Types::t_float:
return callable(*static_cast<const float *>(bv.get_const_ptr()));
case Common_Types::t_long_double:
return callable(*static_cast<const long double *>(bv.get_const_ptr()));
default:
throw chaiscript::detail::exception::bad_any_cast();
}
}
inline static Boxed_Value oper(Operators::Opers t_oper, const Boxed_Value &t_lhs)
{
switch (get_common_type(t_lhs)) {
case Common_Types::t_int32:
return go<int32_t>(t_oper, t_lhs);
case Common_Types::t_uint8:
return go<uint8_t>(t_oper, t_lhs);
case Common_Types::t_int8:
return go<int8_t>(t_oper, t_lhs);
case Common_Types::t_uint16:
return go<uint16_t>(t_oper, t_lhs);
case Common_Types::t_int16:
return go<int16_t>(t_oper, t_lhs);
case Common_Types::t_uint32:
return go<uint32_t>(t_oper, t_lhs);
case Common_Types::t_uint64:
return go<uint64_t>(t_oper, t_lhs);
case Common_Types::t_int64:
return go<int64_t>(t_oper, t_lhs);
case Common_Types::t_double:
return go<double>(t_oper, t_lhs);
case Common_Types::t_float:
return go<float>(t_oper, t_lhs);
case Common_Types::t_long_double:
return go<long double>(t_oper, t_lhs);
}
auto unary_operator = [t_oper, &t_lhs](const auto &c_lhs){
auto *lhs = static_cast<std::decay_t<decltype(c_lhs)> *>(t_lhs.get_ptr());
throw chaiscript::detail::exception::bad_any_cast();
if (lhs) {
switch (t_oper) {
case Operators::Opers::pre_increment:
++(*lhs);
return t_lhs;
case Operators::Opers::pre_decrement:
--(*lhs);
return t_lhs;
}
}
switch (t_oper) {
case Operators::Opers::unary_minus:
return const_var(-c_lhs);
case Operators::Opers::unary_plus:
return const_var(+c_lhs);
}
if constexpr (!std::is_floating_point_v<std::decay_t<decltype(c_lhs)>>) {
switch (t_oper) {
case Operators::Opers::bitwise_complement:
return const_var(~c_lhs);
}
}
throw chaiscript::detail::exception::bad_any_cast();
};
return visit(t_lhs, unary_operator);
}
inline static Boxed_Value oper(Operators::Opers t_oper, const Boxed_Value &t_lhs, const Boxed_Value &t_rhs)
{
switch (get_common_type(t_lhs)) {
case Common_Types::t_int32:
return oper_rhs<int32_t>(t_oper, t_lhs, t_rhs);
case Common_Types::t_uint8:
return oper_rhs<uint8_t>(t_oper, t_lhs, t_rhs);
case Common_Types::t_int8:
return oper_rhs<int8_t>(t_oper, t_lhs, t_rhs);
case Common_Types::t_uint16:
return oper_rhs<uint16_t>(t_oper, t_lhs, t_rhs);
case Common_Types::t_int16:
return oper_rhs<int16_t>(t_oper, t_lhs, t_rhs);
case Common_Types::t_uint32:
return oper_rhs<uint32_t>(t_oper, t_lhs, t_rhs);
case Common_Types::t_uint64:
return oper_rhs<uint64_t>(t_oper, t_lhs, t_rhs);
case Common_Types::t_int64:
return oper_rhs<int64_t>(t_oper, t_lhs, t_rhs);
case Common_Types::t_double:
return oper_rhs<double>(t_oper, t_lhs, t_rhs);
case Common_Types::t_float:
return oper_rhs<float>(t_oper, t_lhs, t_rhs);
case Common_Types::t_long_double:
return oper_rhs<long double>(t_oper, t_lhs, t_rhs);
}
throw chaiscript::detail::exception::bad_any_cast();
auto lhs_visit = [t_oper, &t_lhs, &t_rhs](const auto &c_lhs){
auto *lhs = t_lhs.is_return_value()?nullptr:static_cast<std::decay_t<decltype(c_lhs)> *>(t_lhs.get_ptr());
auto rhs_visit = [t_oper, &t_lhs, lhs, &c_lhs](const auto &c_rhs) {
return go(t_oper, t_lhs, lhs, c_lhs, c_rhs);
};
return visit(t_rhs, rhs_visit);
};
return visit(t_lhs, lhs_visit);
}
template<typename Target, typename Source>
@ -529,11 +383,11 @@ namespace chaiscript
{
const Type_Info &inp_ = t_bv.get_type_info();
if (inp_ == typeid(double)) {
if (inp_ == user_type<double>()) {
return true;
} else if (inp_ == typeid(long double)) {
} else if (inp_ == user_type<long double>()) {
return true;
} else if (inp_ == typeid(float)) {
} else if (inp_ == user_type<float>()) {
return true;
} else {
return false;
@ -542,49 +396,49 @@ namespace chaiscript
Boxed_Number get_as(const Type_Info &inp_) const
{
if (inp_.bare_equal_type_info(typeid(int))) {
if (inp_.bare_equal(user_type<int>())) {
return Boxed_Number(get_as<int>());
} else if (inp_.bare_equal_type_info(typeid(double))) {
} else if (inp_.bare_equal(user_type<double>())) {
return Boxed_Number(get_as<double>());
} else if (inp_.bare_equal_type_info(typeid(float))) {
} else if (inp_.bare_equal(user_type<float>())) {
return Boxed_Number(get_as<float>());
} else if (inp_.bare_equal_type_info(typeid(long double))) {
} else if (inp_.bare_equal(user_type<long double>())) {
return Boxed_Number(get_as<long double>());
} else if (inp_.bare_equal_type_info(typeid(char))) {
} else if (inp_.bare_equal(user_type<char>())) {
return Boxed_Number(get_as<char>());
} else if (inp_.bare_equal_type_info(typeid(unsigned char))) {
} else if (inp_.bare_equal(user_type<unsigned char>())) {
return Boxed_Number(get_as<unsigned char>());
} else if (inp_.bare_equal_type_info(typeid(wchar_t))) {
} else if (inp_.bare_equal(user_type<wchar_t>())) {
return Boxed_Number(get_as<wchar_t>());
} else if (inp_.bare_equal_type_info(typeid(char16_t))) {
} else if (inp_.bare_equal(user_type<char16_t>())) {
return Boxed_Number(get_as<char16_t>());
} else if (inp_.bare_equal_type_info(typeid(char32_t))) {
} else if (inp_.bare_equal(user_type<char32_t>())) {
return Boxed_Number(get_as<char32_t>());
} else if (inp_.bare_equal_type_info(typeid(unsigned int))) {
} else if (inp_.bare_equal(user_type<unsigned int>())) {
return Boxed_Number(get_as<unsigned int>());
} else if (inp_.bare_equal_type_info(typeid(long))) {
} else if (inp_.bare_equal(user_type<long>())) {
return Boxed_Number(get_as<long>());
} else if (inp_.bare_equal_type_info(typeid(long long))) {
} else if (inp_.bare_equal(user_type<long long>())) {
return Boxed_Number(get_as<long long>());
} else if (inp_.bare_equal_type_info(typeid(unsigned long))) {
} else if (inp_.bare_equal(user_type<unsigned long>())) {
return Boxed_Number(get_as<unsigned long>());
} else if (inp_.bare_equal_type_info(typeid(unsigned long long))) {
} else if (inp_.bare_equal(user_type<unsigned long long>())) {
return Boxed_Number(get_as<unsigned long long>());
} else if (inp_.bare_equal_type_info(typeid(int8_t))) {
} else if (inp_.bare_equal(user_type<int8_t>())) {
return Boxed_Number(get_as<int8_t>());
} else if (inp_.bare_equal_type_info(typeid(int16_t))) {
} else if (inp_.bare_equal(user_type<int16_t>())) {
return Boxed_Number(get_as<int16_t>());
} else if (inp_.bare_equal_type_info(typeid(int32_t))) {
} else if (inp_.bare_equal(user_type<int32_t>())) {
return Boxed_Number(get_as<int32_t>());
} else if (inp_.bare_equal_type_info(typeid(int64_t))) {
} else if (inp_.bare_equal(user_type<int64_t>())) {
return Boxed_Number(get_as<int64_t>());
} else if (inp_.bare_equal_type_info(typeid(uint8_t))) {
} else if (inp_.bare_equal(user_type<uint8_t>())) {
return Boxed_Number(get_as<uint8_t>());
} else if (inp_.bare_equal_type_info(typeid(uint16_t))) {
} else if (inp_.bare_equal(user_type<uint16_t>())) {
return Boxed_Number(get_as<uint16_t>());
} else if (inp_.bare_equal_type_info(typeid(uint32_t))) {
} else if (inp_.bare_equal(user_type<uint32_t>())) {
return Boxed_Number(get_as<uint32_t>());
} else if (inp_.bare_equal_type_info(typeid(uint64_t))) {
} else if (inp_.bare_equal(user_type<uint64_t>())) {
return Boxed_Number(get_as<uint64_t>());
} else {
throw chaiscript::detail::exception::bad_any_cast();
@ -716,7 +570,7 @@ namespace chaiscript
static void validate_boxed_number(const Boxed_Value &v)
{
const Type_Info &inp_ = v.get_type_info();
if (inp_ == typeid(bool))
if (inp_ == user_type<bool>())
{
throw chaiscript::detail::exception::bad_any_cast();
}

View File

@ -208,14 +208,14 @@ namespace chaiscript
Boxed_Value(const Boxed_Value&) = default;
Boxed_Value& operator=(const Boxed_Value&) = default;
void swap(Boxed_Value &rhs)
void swap(Boxed_Value &rhs) noexcept
{
std::swap(m_data, rhs.m_data);
}
/// Copy the values stored in rhs.m_data to m_data.
/// m_data pointers are not shared in this case
Boxed_Value assign(const Boxed_Value &rhs)
Boxed_Value assign(const Boxed_Value &rhs) noexcept
{
(*m_data) = (*rhs.m_data);
return *this;
@ -244,7 +244,7 @@ namespace chaiscript
template<typename T>
auto pointer_sentinel(std::shared_ptr<T> &ptr) const
auto pointer_sentinel(std::shared_ptr<T> &ptr) const noexcept
{
struct Sentinel {
Sentinel(std::shared_ptr<T> &t_ptr, Data &data)
@ -263,7 +263,7 @@ namespace chaiscript
Sentinel& operator=(Sentinel&&s) = default;
Sentinel(Sentinel &&s) = default;
operator std::shared_ptr<T>&() const
operator std::shared_ptr<T>&() const noexcept
{
return m_ptr.get();
}
@ -308,7 +308,7 @@ namespace chaiscript
return !is_ref();
}
void *get_ptr() const noexcept
void *get_ptr() const noexcept
{
return m_data->m_data_ptr;
}

View File

@ -19,6 +19,7 @@
#include <set>
#include <stdexcept>
#include <string>
#include <string_view>
#include <typeinfo>
#include <utility>
#include <vector>
@ -180,9 +181,9 @@ namespace chaiscript
//Add a bit of ChaiScript to eval during module implementation
Module &eval(const std::string &str)
Module &eval(std::string str)
{
m_evals.push_back(str);
m_evals.push_back(std::move(str));
return *this;
}
@ -196,15 +197,15 @@ namespace chaiscript
apply_globals(m_globals.begin(), m_globals.end(), t_engine);
}
bool has_function(const Proxy_Function &new_f, const std::string &name)
bool has_function(const Proxy_Function &new_f, const std::string_view &name) noexcept
{
return std::any_of(m_funcs.begin(), m_funcs.end(),
return std::any_of(m_funcs.begin(), m_funcs.end(),
[&](const std::pair<Proxy_Function, std::string> &existing_f) {
return existing_f.second == name && *(existing_f.first) == *(new_f);
}
);
}
private:
std::vector<std::pair<Type_Info, std::string>> m_typeinfos;
@ -214,14 +215,14 @@ namespace chaiscript
std::vector<Type_Conversion> m_conversions;
template<typename T, typename InItr>
static void apply(InItr begin, const InItr end, T &t)
static void apply(InItr begin, const InItr end, T &t)
{
for_each(begin, end,
for_each(begin, end,
[&t](const auto &obj) {
try {
t.add(obj.first, obj.second);
} catch (const chaiscript::exception::name_conflict_error &) {
/// \todo Should we throw an error if there's a name conflict
/// \todo Should we throw an error if there's a name conflict
/// while applying a module?
}
}
@ -260,12 +261,12 @@ namespace chaiscript
};
/// Convenience typedef for Module objects to be added to the ChaiScript runtime
typedef std::shared_ptr<Module> ModulePtr;
using ModulePtr = std::shared_ptr<Module>;
namespace detail
{
/// A Proxy_Function implementation that is able to take
/// a vector of Proxy_Functions and perform a dispatch on them. It is
/// a vector of Proxy_Functions and perform a dispatch on them. It is
/// used specifically in the case of dealing with Function object variables
class Dispatch_Function final : public dispatch::Proxy_Function_Base
{
@ -276,7 +277,7 @@ namespace chaiscript
{
}
bool operator==(const dispatch::Proxy_Function_Base &rhs) const override
bool operator==(const dispatch::Proxy_Function_Base &rhs) const noexcept override
{
try {
const auto &dispatch_fun = dynamic_cast<const Dispatch_Function &>(rhs);
@ -292,7 +293,7 @@ namespace chaiscript
}
static int calculate_arity(const std::vector<Proxy_Function> &t_funcs)
static int calculate_arity(const std::vector<Proxy_Function> &t_funcs) noexcept
{
if (t_funcs.empty()) {
return -1;
@ -312,7 +313,7 @@ namespace chaiscript
return arity;
}
bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const override
bool call_match(const std::vector<Boxed_Value> &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); });
@ -385,13 +386,13 @@ namespace chaiscript
template <class T>
using SmallVector = std::vector<T>;
typedef SmallVector<std::pair<std::string, Boxed_Value>> Scope;
typedef SmallVector<Scope> StackData;
typedef SmallVector<StackData> Stacks;
typedef SmallVector<Boxed_Value> Call_Param_List;
typedef SmallVector<Call_Param_List> Call_Params;
using Scope = SmallVector<std::pair<std::string, Boxed_Value>>;
using StackData = SmallVector<Scope>;
using Stacks = SmallVector<StackData>;
using Call_Param_List = SmallVector<Boxed_Value>;
using Call_Params = SmallVector<Call_Param_List>;
Stack_Holder()
{
@ -438,16 +439,16 @@ namespace chaiscript
{
public:
typedef std::map<std::string, chaiscript::Type_Info> Type_Name_Map;
typedef std::vector<std::pair<std::string, Boxed_Value>> Scope;
typedef Stack_Holder::StackData StackData;
using Type_Name_Map = std::map<std::string, chaiscript::Type_Info, str_less>;
using Scope = std::vector<std::pair<std::string, Boxed_Value>>;
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;
std::map<std::string, Boxed_Value> m_global_objects;
std::map<std::string, Boxed_Value, str_less> m_global_objects;
Type_Name_Map m_types;
};
@ -515,8 +516,7 @@ namespace chaiscript
throw chaiscript::exception::name_conflict_error(t_name);
}
stack_elem.emplace_back(t_name, std::move(obj));
return stack_elem.back().second;
return stack_elem.emplace_back(t_name, std::move(obj)).second;
}
@ -654,7 +654,7 @@ namespace chaiscript
/// Searches the current stack for an object of the given name
/// includes a special overload for the _ place holder object to
/// ensure that it is always in scope.
Boxed_Value get_object(const std::string &name, std::atomic_uint_fast32_t &t_loc, Stack_Holder &t_holder) const
Boxed_Value get_object(const std::string_view &name, std::atomic_uint_fast32_t &t_loc, Stack_Holder &t_holder) const
{
enum class Loc : uint_fast32_t {
located = 0x80000000,
@ -719,7 +719,7 @@ namespace chaiscript
}
/// Returns the type info for a named type
Type_Info get_type(const std::string &name, bool t_throw = true) const
Type_Info get_type(std::string_view name, bool t_throw = true) const
{
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
@ -731,7 +731,7 @@ namespace chaiscript
}
if (t_throw) {
throw std::range_error("Type Not Known: " + name);
throw std::range_error("Type Not Known: " + std::string(name));
} else {
return Type_Info();
}
@ -776,7 +776,7 @@ namespace chaiscript
/// Return a function by name
std::pair<size_t, std::shared_ptr<std::vector< Proxy_Function>>> get_function(const std::string &t_name, const size_t t_hint) const
std::pair<size_t, std::shared_ptr<std::vector< Proxy_Function>>> get_function(const std::string_view &t_name, const size_t t_hint) const
{
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
@ -804,7 +804,7 @@ namespace chaiscript
/// \returns a function object (Boxed_Value wrapper) if it exists
/// \throws std::range_error if it does not
/// \warn does not obtain a mutex lock. \sa get_function_object for public version
std::pair<size_t, Boxed_Value> get_function_object_int(const std::string &t_name, const size_t t_hint) const
std::pair<size_t, Boxed_Value> get_function_object_int(const std::string_view &t_name, const size_t t_hint) const
{
const auto &funs = get_boxed_functions_int();
@ -814,13 +814,13 @@ namespace chaiscript
{
return std::make_pair(std::distance(funs.begin(), itr), itr->second);
} else {
throw std::range_error("Object not found: " + t_name);
throw std::range_error("Object not found: " + std::string(t_name));
}
}
/// Return true if a function exists
bool function_exists(const std::string &name) const
bool function_exists(const std::string_view &name) const
{
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
@ -930,13 +930,13 @@ namespace chaiscript
}
const Type_Conversions &conversions() const
const Type_Conversions &conversions() const noexcept
{
return m_conversions;
}
static bool is_attribute_call(const std::vector<Proxy_Function> &t_funs, const std::vector<Boxed_Value> &t_params,
bool t_has_params, const Type_Conversions_State &t_conversions)
bool t_has_params, const Type_Conversions_State &t_conversions) noexcept
{
if (!t_has_params || t_params.empty()) {
return false;
@ -1049,7 +1049,7 @@ namespace chaiscript
if (!functions.empty()) {
try {
if (is_no_param) {
std::vector<Boxed_Value> tmp_params(params);
auto tmp_params(params);
tmp_params.insert(tmp_params.begin() + 1, var(t_name));
return do_attribute_call(2, tmp_params, functions, t_conversions);
} else {
@ -1076,14 +1076,13 @@ namespace chaiscript
Boxed_Value call_function(const std::string &t_name, std::atomic_uint_fast32_t &t_loc, const std::vector<Boxed_Value> &params,
Boxed_Value call_function(const std::string_view &t_name, std::atomic_uint_fast32_t &t_loc, const std::vector<Boxed_Value> &params,
const Type_Conversions_State &t_conversions) const
{
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);
}
return dispatch::dispatch(*funs.second, params, t_conversions);
const auto [func_loc, func] = get_function(t_name, loc);
if (func_loc != loc) { t_loc = uint_fast32_t(func_loc); }
return dispatch::dispatch(*func, params, t_conversions);
}
@ -1102,12 +1101,12 @@ namespace chaiscript
/// Dump function to stdout
void dump_function(const std::pair<const std::string, Proxy_Function > &f) const
{
std::vector<Type_Info> params = f.second->get_param_types();
const auto params = f.second->get_param_types();
dump_type(params.front());
std::cout << " " << f.first << "(";
for (std::vector<Type_Info>::const_iterator itr = params.begin() + 1;
for (auto itr = params.begin() + 1;
itr != params.end();
)
{
@ -1132,7 +1131,7 @@ namespace chaiscript
throw chaiscript::exception::arity_error(static_cast<int>(params.size()), 1);
}
const Const_Proxy_Function &f = this->boxed_cast<Const_Proxy_Function>(params[0]);
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));
@ -1142,15 +1141,15 @@ namespace chaiscript
void dump_system() const
{
std::cout << "Registered Types: \n";
for (auto const &type: get_types())
for (const auto &[type_name, type] : get_types() )
{
std::cout << type.first << ": " << type.second.bare_name() << '\n';
std::cout << type_name << ": " << type.bare_name() << '\n';
}
std::cout << '\n';
std::cout << '\n';
std::cout << "Functions: \n";
for (auto const &func: get_functions())
for (const auto &func : get_functions())
{
dump_function(func);
}
@ -1158,7 +1157,7 @@ namespace chaiscript
}
/// return true if the Boxed_Value matches the registered type by name
bool is_type(const Boxed_Value &r, const std::string &user_typename) const
bool is_type(const Boxed_Value &r, const std::string_view &user_typename) const noexcept
{
try {
if (get_type(user_typename).bare_equal(r.get_type_info()))
@ -1264,66 +1263,66 @@ namespace chaiscript
pop_function_call(*m_stack_holder, m_conversions.conversion_saves());
}
Stack_Holder &get_stack_holder()
Stack_Holder &get_stack_holder() noexcept
{
return *m_stack_holder;
}
/// Returns the current stack
/// make const/non const versions
const StackData &get_stack_data() const
const StackData &get_stack_data() const noexcept
{
return m_stack_holder->stacks.back();
}
static StackData &get_stack_data(Stack_Holder &t_holder)
static StackData &get_stack_data(Stack_Holder &t_holder) noexcept
{
return t_holder.stacks.back();
}
StackData &get_stack_data()
StackData &get_stack_data() noexcept
{
return m_stack_holder->stacks.back();
}
parser::ChaiScript_Parser_Base &get_parser()
parser::ChaiScript_Parser_Base &get_parser() noexcept
{
return m_parser.get();
}
private:
const std::vector<std::pair<std::string, Boxed_Value>> &get_boxed_functions_int() const
const std::vector<std::pair<std::string, Boxed_Value>> &get_boxed_functions_int() const noexcept
{
return m_state.m_boxed_functions;
}
std::vector<std::pair<std::string, Boxed_Value>> &get_boxed_functions_int()
std::vector<std::pair<std::string, Boxed_Value>> &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
const std::vector<std::pair<std::string, Proxy_Function>> &get_function_objects_int() const noexcept
{
return m_state.m_function_objects;
}
std::vector<std::pair<std::string, Proxy_Function>> &get_function_objects_int()
std::vector<std::pair<std::string, Proxy_Function>> &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
const std::vector<std::pair<std::string, std::shared_ptr<std::vector<Proxy_Function>>>> &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()
std::vector<std::pair<std::string, std::shared_ptr<std::vector<Proxy_Function>>>> &get_functions_int() noexcept
{
return m_state.m_functions;
}
static bool function_less_than(const Proxy_Function &lhs, const Proxy_Function &rhs)
static bool function_less_than(const Proxy_Function &lhs, const Proxy_Function &rhs) noexcept
{
auto dynamic_lhs(std::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(lhs));
@ -1355,8 +1354,8 @@ namespace chaiscript
const auto lhssize = lhsparamtypes.size();
const auto rhssize = rhsparamtypes.size();
static const auto boxed_type = user_type<Boxed_Value>();
static const auto boxed_pod_type = user_type<Boxed_Number>();
constexpr const auto boxed_type = user_type<Boxed_Value>();
constexpr const auto boxed_pod_type = user_type<Boxed_Number>();
for (size_t i = 1; i < lhssize && i < rhssize; ++i)
{
@ -1418,13 +1417,13 @@ namespace chaiscript
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 {
typedef typename Container::value_type value_type;
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)
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) {
@ -1433,16 +1432,16 @@ namespace chaiscript
}
template<typename Container, typename Key>
static typename Container::const_iterator find_keyed_value(const Container &t_c, const Key &t_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 o.first == t_key;
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)
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));
@ -1519,23 +1518,23 @@ namespace chaiscript
{
}
Dispatch_Engine *operator->() const {
Dispatch_Engine *operator->() const noexcept {
return &m_engine.get();
}
Dispatch_Engine &operator*() const {
Dispatch_Engine &operator*() const noexcept {
return m_engine.get();
}
Stack_Holder &stack_holder() const {
Stack_Holder &stack_holder() const noexcept {
return m_stack_holder.get();
}
const Type_Conversions_State &conversions() const {
const Type_Conversions_State &conversions() const noexcept {
return m_conversions;
}
Type_Conversions::Conversion_Saves &conversion_saves() const {
Type_Conversions::Conversion_Saves &conversion_saves() const noexcept {
return m_conversions.saves();
}
@ -1547,7 +1546,7 @@ namespace chaiscript
return m_engine.get().add_object(t_name, std::move(obj), m_stack_holder.get());
}
Boxed_Value get_object(const std::string &t_name, std::atomic_uint_fast32_t &t_loc) const {
Boxed_Value get_object(const std::string_view &t_name, std::atomic_uint_fast32_t &t_loc) const {
return m_engine.get().get_object(t_name, t_loc, m_stack_holder.get());
}

View File

@ -50,17 +50,17 @@ namespace chaiscript
Dynamic_Object() = default;
bool is_explicit() const
bool is_explicit() const noexcept
{
return m_option_explicit;
}
void set_explicit(const bool t_explicit)
void set_explicit(const bool t_explicit) noexcept
{
m_option_explicit = t_explicit;
}
std::string get_type_name() const
const std::string &get_type_name() const noexcept
{
return m_type_name;
}

View File

@ -71,7 +71,7 @@ namespace chaiscript
Dynamic_Object_Function &operator=(const Dynamic_Object_Function) = delete;
Dynamic_Object_Function(Dynamic_Object_Function &) = delete;
bool operator==(const Proxy_Function_Base &f) const override
bool operator==(const Proxy_Function_Base &f) const noexcept override
{
if (const auto *df = dynamic_cast<const Dynamic_Object_Function *>(&f))
{
@ -81,9 +81,9 @@ namespace chaiscript
}
}
bool is_attribute_function() const override { return m_is_attribute; }
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 override
bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const noexcept override
{
if (dynamic_object_typename_match(vals, m_type_name, m_ti, t_conversions))
{
@ -109,7 +109,7 @@ namespace chaiscript
}
}
bool compare_first_type(const Boxed_Value &bv, const Type_Conversions_State &t_conversions) const override
bool compare_first_type(const Boxed_Value &bv, const Type_Conversions_State &t_conversions) const noexcept override
{
return dynamic_object_typename_match(bv, m_type_name, m_ti, t_conversions);
}
@ -127,7 +127,7 @@ namespace chaiscript
}
bool dynamic_object_typename_match(const Boxed_Value &bv, const std::string &name,
const std::unique_ptr<Type_Info> &ti, const Type_Conversions_State &t_conversions) const
const std::unique_ptr<Type_Info> &ti, const Type_Conversions_State &t_conversions) const noexcept
{
if (bv.get_type_info().bare_equal(m_doti))
{
@ -149,7 +149,7 @@ namespace chaiscript
}
bool dynamic_object_typename_match(const std::vector<Boxed_Value> &bvs, const std::string &name,
const std::unique_ptr<Type_Info> &ti, const Type_Conversions_State &t_conversions) const
const std::unique_ptr<Type_Info> &ti, const Type_Conversions_State &t_conversions) const noexcept
{
if (!bvs.empty())
{
@ -199,7 +199,7 @@ namespace chaiscript
return std::vector<Type_Info>(begin, end);
}
bool operator==(const Proxy_Function_Base &f) const override
bool operator==(const Proxy_Function_Base &f) const noexcept override
{
const Dynamic_Object_Constructor *dc = dynamic_cast<const Dynamic_Object_Constructor*>(&f);
return (dc != nullptr) && dc->m_type_name == m_type_name && (*dc->m_func) == (*m_func);

View File

@ -46,7 +46,7 @@ namespace chaiscript
{
void handle(const Boxed_Value &bv, const Dispatch_Engine &t_engine) override
{
(void)std::initializer_list<int>{(throw_type<T>(bv, t_engine), 0)...};
(throw_type<T>(bv, t_engine), ...);
}
};
}
@ -101,7 +101,7 @@ namespace chaiscript
///
/// \sa chaiscript::exception_specification for creation of chaiscript::Exception_Handler objects
/// \sa \ref exceptions
typedef std::shared_ptr<detail::Exception_Handler_Base> Exception_Handler;
using Exception_Handler = std::shared_ptr<detail::Exception_Handler_Base>;
/// \brief creates a chaiscript::Exception_Handler which handles one type of exception unboxing
/// \sa \ref exceptions

View File

@ -18,7 +18,6 @@
#include "boxed_cast.hpp"
#include "function_call_detail.hpp"
#include "proxy_functions.hpp"
#include "callable_traits.hpp"
namespace chaiscript {
class Boxed_Value;
@ -32,6 +31,15 @@ namespace chaiscript
{
namespace dispatch
{
namespace detail
{
template<typename Ret, typename ... Param>
constexpr auto arity(Ret (*)(Param...)) noexcept
{
return sizeof...(Param);
}
}
/// Build a function caller that knows how to dispatch on a set of functions
/// example:
/// std::function<void (int)> f =
@ -43,7 +51,7 @@ namespace chaiscript
{
const bool has_arity_match = std::any_of(funcs.begin(), funcs.end(),
[](const Const_Proxy_Function &f) {
return f->get_arity() == -1 || size_t(f->get_arity()) == chaiscript::dispatch::detail::Arity<FunctionType>::arity;
return f->get_arity() == -1 || size_t(f->get_arity()) == detail::arity(static_cast<FunctionType *>(nullptr));
});
if (!has_arity_match) {

View File

@ -129,7 +129,7 @@ namespace chaiscript
}
template<typename P>
static Boxed_Value box(Boxed_Value bv)
static Boxed_Value box(Boxed_Value bv) noexcept
{
return bv;
}

View File

@ -0,0 +1,124 @@
#ifndef CHAISCRIPT_FUNCTION_SIGNATURE_HPP
#define CHAISCRIPT_FUNCTION_SIGNATURE_HPP
#include <type_traits>
namespace chaiscript::dispatch::detail {
template<typename ... Param>
struct Function_Params
{
};
template<typename Ret, typename Params, bool IsNoExcept = false, bool IsMember = false, bool IsMemberObject = false, bool IsObject = false>
struct Function_Signature {
using Param_Types = Params;
using Return_Type = Ret;
constexpr static const bool is_object = IsObject;
constexpr static const bool is_member_object = IsMemberObject;
constexpr static const bool is_noexcept = IsNoExcept;
template<typename T>
constexpr Function_Signature(T &&) noexcept {}
constexpr Function_Signature() noexcept = default;
};
// Free functions
template<typename Ret, typename ... Param>
Function_Signature(Ret (*f)(Param...)) -> Function_Signature<Ret, Function_Params<Param...>>;
template<typename Ret, typename ... Param>
Function_Signature(Ret (*f)(Param...) noexcept) -> Function_Signature<Ret, Function_Params<Param...>, true>;
// no reference specifier
template<typename Ret, typename Class, typename ... Param>
Function_Signature(Ret (Class::*f)(Param ...) volatile) -> Function_Signature<Ret, Function_Params<volatile Class &, Param...>, false, true>;
template<typename Ret, typename Class, typename ... Param>
Function_Signature(Ret (Class::*f)(Param ...) volatile noexcept) -> Function_Signature<Ret, Function_Params<volatile Class &, Param...>, true, true>;
template<typename Ret, typename Class, typename ... Param>
Function_Signature(Ret (Class::*f)(Param ...) volatile const) -> Function_Signature<Ret, Function_Params<volatile const Class &, Param...>, false, true>;
template<typename Ret, typename Class, typename ... Param>
Function_Signature(Ret (Class::*f)(Param ...) volatile const noexcept) -> Function_Signature<Ret, Function_Params<volatile const Class &, Param...>, true, true>;
template<typename Ret, typename Class, typename ... Param>
Function_Signature(Ret (Class::*f)(Param ...) ) -> Function_Signature<Ret, Function_Params<Class &, Param...>, false, true>;
template<typename Ret, typename Class, typename ... Param>
Function_Signature(Ret (Class::*f)(Param ...) noexcept) -> Function_Signature<Ret, Function_Params<Class &, Param...>, true, true>;
template<typename Ret, typename Class, typename ... Param>
Function_Signature(Ret (Class::*f)(Param ...) const) -> Function_Signature<Ret, Function_Params<const Class &, Param...>, false, true>;
template<typename Ret, typename Class, typename ... Param>
Function_Signature(Ret (Class::*f)(Param ...) const noexcept) -> Function_Signature<Ret, Function_Params<const Class &, Param...>, true, true>;
// & reference specifier
template<typename Ret, typename Class, typename ... Param>
Function_Signature(Ret (Class::*f)(Param ...) volatile &) -> Function_Signature<Ret, Function_Params<volatile Class &, Param...>, false, true>;
template<typename Ret, typename Class, typename ... Param>
Function_Signature(Ret (Class::*f)(Param ...) volatile & noexcept) -> Function_Signature<Ret, Function_Params<volatile Class &, Param...>, true, true>;
template<typename Ret, typename Class, typename ... Param>
Function_Signature(Ret (Class::*f)(Param ...) volatile const &) -> Function_Signature<Ret, Function_Params<volatile const Class &, Param...>, false, true>;
template<typename Ret, typename Class, typename ... Param>
Function_Signature(Ret (Class::*f)(Param ...) volatile const & noexcept) -> Function_Signature<Ret, Function_Params<volatile const Class &, Param...>, true, true>;
template<typename Ret, typename Class, typename ... Param>
Function_Signature(Ret (Class::*f)(Param ...) & ) -> Function_Signature<Ret, Function_Params<Class &, Param...>, false, true>;
template<typename Ret, typename Class, typename ... Param>
Function_Signature(Ret (Class::*f)(Param ...) & noexcept) -> Function_Signature<Ret, Function_Params<Class &, Param...>, true, true>;
template<typename Ret, typename Class, typename ... Param>
Function_Signature(Ret (Class::*f)(Param ...) const &) -> Function_Signature<Ret, Function_Params<const Class &, Param...>, false, true>;
template<typename Ret, typename Class, typename ... Param>
Function_Signature(Ret (Class::*f)(Param ...) const & noexcept) -> Function_Signature<Ret, Function_Params<const Class &, Param...>, true, true>;
// && reference specifier
template<typename Ret, typename Class, typename ... Param>
Function_Signature(Ret (Class::*f)(Param ...) volatile &&) -> Function_Signature<Ret, Function_Params<volatile Class &&, Param...>, false, true>;
template<typename Ret, typename Class, typename ... Param>
Function_Signature(Ret (Class::*f)(Param ...) volatile && noexcept) -> Function_Signature<Ret, Function_Params<volatile Class &&, Param...>, true, true>;
template<typename Ret, typename Class, typename ... Param>
Function_Signature(Ret (Class::*f)(Param ...) volatile const &&) -> Function_Signature<Ret, Function_Params<volatile const Class &&, Param...>, false, true>;
template<typename Ret, typename Class, typename ... Param>
Function_Signature(Ret (Class::*f)(Param ...) volatile const && noexcept) -> Function_Signature<Ret, Function_Params<volatile const Class &&, Param...>, true, true>;
template<typename Ret, typename Class, typename ... Param>
Function_Signature(Ret (Class::*f)(Param ...) &&) -> Function_Signature<Ret, Function_Params<Class &&, Param...>, false, true>;
template<typename Ret, typename Class, typename ... Param>
Function_Signature(Ret (Class::*f)(Param ...) && noexcept) -> Function_Signature<Ret, Function_Params<Class &&, Param...>, true, true>;
template<typename Ret, typename Class, typename ... Param>
Function_Signature(Ret (Class::*f)(Param ...) const &&) -> Function_Signature<Ret, Function_Params<const Class &&, Param...>, false, true>;
template<typename Ret, typename Class, typename ... Param>
Function_Signature(Ret (Class::*f)(Param ...) const && noexcept) -> Function_Signature<Ret, Function_Params<const Class &&, Param...>, true, true>;
template<typename Ret, typename Class>
Function_Signature(Ret (Class::*f)) -> Function_Signature<Ret, Function_Params<Class &>, true, true, true>;
template<typename Func>
Function_Signature(Func &&) -> Function_Signature<
typename decltype(Function_Signature{&std::decay_t<Func>::operator()})::Return_Type,
typename decltype(Function_Signature{&std::decay_t<Func>::operator()})::Param_Types,
decltype(Function_Signature{&std::decay_t<Func>::operator()})::is_noexcept,
false,
false,
true
>;
}
#endif

View File

@ -199,7 +199,7 @@ namespace chaiscript
template<>
struct Handle_Return<Boxed_Value>
{
static Boxed_Value handle(const Boxed_Value &r)
static Boxed_Value handle(const Boxed_Value &r) noexcept
{
return r;
}
@ -226,7 +226,7 @@ namespace chaiscript
template<>
struct Handle_Return<Boxed_Number>
{
static Boxed_Value handle(const Boxed_Number &r)
static Boxed_Value handle(const Boxed_Number &r) noexcept
{
return r.bv;
}

View File

@ -19,14 +19,15 @@ namespace chaiscript
{
namespace detail
{
template<typename Class, typename ... Params >
Proxy_Function build_constructor_(Class (*)(Params...))
{
auto call = dispatch::detail::Constructor<Class, Params...>();
auto call = [](auto && ... param){
return Class(std::forward<decltype(param)>(param)...);
};
return Proxy_Function(
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<std::shared_ptr<Class> (Params...), decltype(call)>>(call));
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Class (Params...), decltype(call)>>(call));
}
}
}

View File

@ -41,7 +41,7 @@ namespace chaiscript
class Boxed_Number;
struct AST_Node;
typedef std::unique_ptr<AST_Node> AST_NodePtr;
using AST_NodePtr = std::unique_ptr<AST_Node>;
namespace dispatch
{
@ -52,14 +52,12 @@ namespace chaiscript
{
public:
Param_Types()
: m_has_types(false),
m_doti(user_type<Dynamic_Object>())
: m_has_types(false)
{}
explicit Param_Types(std::vector<std::pair<std::string, Type_Info>> t_types)
: m_types(std::move(t_types)),
m_has_types(false),
m_doti(user_type<Dynamic_Object>())
m_has_types(false)
{
update_has_types();
}
@ -70,20 +68,21 @@ namespace chaiscript
update_has_types();
}
bool operator==(const Param_Types &t_rhs) const
bool operator==(const Param_Types &t_rhs) const noexcept
{
return m_types == t_rhs.m_types;
}
std::vector<Boxed_Value> convert(std::vector<Boxed_Value> vals, const Type_Conversions_State &t_conversions) const
{
constexpr auto dynamic_object_type_info = user_type<Dynamic_Object>();
for (size_t i = 0; i < vals.size(); ++i)
{
const auto &name = m_types[i].first;
if (!name.empty()) {
const auto &bv = vals[i];
if (!bv.get_type_info().bare_equal(m_doti))
if (!bv.get_type_info().bare_equal(dynamic_object_type_info))
{
const auto &ti = m_types[i].second;
if (!ti.is_undef())
@ -114,8 +113,9 @@ 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
std::pair<bool, bool> match(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const noexcept
{
constexpr auto dynamic_object_type_info = user_type<Dynamic_Object>();
bool needs_conversion = false;
if (!m_has_types) { return std::make_pair(true, needs_conversion); }
@ -127,7 +127,7 @@ namespace chaiscript
if (!name.empty()) {
const auto &bv = vals[i];
if (bv.get_type_info().bare_equal(m_doti))
if (bv.get_type_info().bare_equal(dynamic_object_type_info))
{
try {
const Dynamic_Object &d = boxed_cast<const Dynamic_Object &>(bv, &t_conversions);
@ -158,7 +158,7 @@ namespace chaiscript
return std::make_pair(true, needs_conversion);
}
const std::vector<std::pair<std::string, Type_Info>> &types() const
const std::vector<std::pair<std::string, Type_Info>> &types() const noexcept
{
return m_types;
}
@ -180,7 +180,6 @@ namespace chaiscript
std::vector<std::pair<std::string, Type_Info>> m_types;
bool m_has_types;
Type_Info m_doti;
};
@ -210,14 +209,14 @@ namespace chaiscript
/// 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.
const std::vector<Type_Info> &get_param_types() const { return m_types; }
const std::vector<Type_Info> &get_param_types() const noexcept { return m_types; }
virtual bool operator==(const Proxy_Function_Base &) const = 0;
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 is_attribute_function() const { return false; }
virtual bool is_attribute_function() const noexcept { return false; }
bool has_arithmetic_param() const
bool has_arithmetic_param() const noexcept
{
return m_has_arithmetic_param;
}
@ -229,7 +228,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
bool filter(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const noexcept
{
assert(m_arity == -1 || (m_arity > 0 && static_cast<int>(vals.size()) == m_arity));
@ -244,19 +243,23 @@ namespace chaiscript
}
/// \returns the number of arguments the function takes or -1 if it is variadic
int get_arity() const
int get_arity() const noexcept
{
return m_arity;
}
static bool compare_type_to_param(const Type_Info &ti, const Boxed_Value &bv, const Type_Conversions_State &t_conversions)
static bool compare_type_to_param(const Type_Info &ti, const Boxed_Value &bv, const Type_Conversions_State &t_conversions) noexcept
{
constexpr auto boxed_value_ti = user_type<Boxed_Value>();
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()
|| ti.bare_equal(user_type<Boxed_Value>())
|| ti.bare_equal(boxed_value_ti)
|| (!bv.get_type_info().is_undef()
&& ( (ti.bare_equal(user_type<Boxed_Number>()) && bv.get_type_info().is_arithmetic())
&& ( (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(user_type<std::shared_ptr<const Proxy_Function_Base> >())
|| bv.get_type_info().bare_equal(function_ti)
|| t_conversions->converts(ti, bv.get_type_info())
)
)
@ -268,8 +271,9 @@ namespace chaiscript
}
}
virtual bool compare_first_type(const Boxed_Value &bv, const Type_Conversions_State &t_conversions) const
virtual bool compare_first_type(const Boxed_Value &bv, const Type_Conversions_State &t_conversions) const noexcept
{
/// TODO is m_types guaranteed to be at least 2??
return compare_type_to_param(m_types[1], bv, t_conversions);
}
@ -292,7 +296,7 @@ namespace chaiscript
static bool compare_types(const std::vector<Type_Info> &tis, const std::vector<Boxed_Value> &bvs,
const Type_Conversions_State &t_conversions)
const Type_Conversions_State &t_conversions) noexcept
{
if (tis.size() - 1 != bvs.size())
{
@ -314,11 +318,11 @@ namespace chaiscript
}
/// \brief Common typedef used for passing of any registered function in ChaiScript
typedef std::shared_ptr<dispatch::Proxy_Function_Base> Proxy_Function;
using Proxy_Function = std::shared_ptr<dispatch::Proxy_Function_Base>;
/// \brief Const version of Proxy_Function. Points to a const Proxy_Function. This is how most registered functions
/// are handled internally.
typedef std::shared_ptr<const dispatch::Proxy_Function_Base> Const_Proxy_Function;
using Const_Proxy_Function = std::shared_ptr<const dispatch::Proxy_Function_Base>;
namespace exception
{
@ -358,7 +362,7 @@ namespace chaiscript
}
bool operator==(const Proxy_Function_Base &rhs) const override
bool operator==(const Proxy_Function_Base &rhs) const noexcept override
{
const Dynamic_Proxy_Function *prhs = dynamic_cast<const Dynamic_Proxy_Function *>(&rhs);
@ -374,13 +378,17 @@ namespace chaiscript
return call_match_internal(vals, t_conversions).first;
}
bool has_guard() const noexcept
{
return bool(m_guard);
}
Proxy_Function get_guard() const
Proxy_Function get_guard() const noexcept
{
return m_guard;
}
bool has_parse_tree() const {
bool has_parse_tree() const noexcept {
return static_cast<bool>(m_parsenode);
}
@ -528,7 +536,7 @@ namespace chaiscript
assert(m_f->get_arity() < 0 || m_f->get_arity() == static_cast<int>(m_args.size()));
}
bool operator==(const Proxy_Function_Base &t_f) const override
bool operator==(const Proxy_Function_Base &t_f) const noexcept override
{
return &t_f == this;
}
@ -620,13 +628,13 @@ namespace chaiscript
{
}
bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const override
bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const noexcept override
{
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 = 0;
virtual bool compare_types_with_cast(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const noexcept = 0;
};
@ -642,12 +650,12 @@ namespace chaiscript
{
}
bool compare_types_with_cast(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const override
bool compare_types_with_cast(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const noexcept override
{
return detail::compare_types_cast(static_cast<Func *>(nullptr), vals, t_conversions);
}
bool operator==(const Proxy_Function_Base &t_func) const override
bool operator==(const Proxy_Function_Base &t_func) const noexcept override
{
return dynamic_cast<const Proxy_Function_Callable_Impl<Func, Callable> *>(&t_func) != nullptr;
}
@ -656,7 +664,7 @@ namespace chaiscript
protected:
Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions_State &t_conversions) const override
{
return detail::call_func(detail::Function_Signature<Func>(), m_f, params, t_conversions);
return detail::call_func(static_cast<Func *>(nullptr), m_f, params, t_conversions);
}
private:
@ -686,12 +694,12 @@ 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 override
bool compare_types_with_cast(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const noexcept override
{
return detail::compare_types_cast(static_cast<Func *>(nullptr), vals, t_conversions);
}
bool operator==(const Proxy_Function_Base &t_func) const override
bool operator==(const Proxy_Function_Base &t_func) const noexcept override
{
return dynamic_cast<const Assignable_Proxy_Function_Impl<Func> *>(&t_func) != nullptr;
}
@ -708,7 +716,7 @@ namespace chaiscript
protected:
Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions_State &t_conversions) const override
{
return detail::call_func(detail::Function_Signature<Func>(), m_f.get(), params, t_conversions);
return detail::call_func(static_cast<Func *>(nullptr), m_f.get(), params, t_conversions);
}
@ -729,9 +737,9 @@ namespace chaiscript
{
}
bool is_attribute_function() const override { return true; }
bool is_attribute_function() const noexcept override { return true; }
bool operator==(const Proxy_Function_Base &t_func) const override
bool operator==(const Proxy_Function_Base &t_func) const noexcept override
{
const Attribute_Access<T, Class> * aa
= dynamic_cast<const Attribute_Access<T, Class> *>(&t_func);
@ -743,14 +751,14 @@ namespace chaiscript
}
}
bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &) const override
bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &) const noexcept override
{
if (vals.size() != 1)
{
return false;
}
return vals[0].get_type_info().bare_equal(user_type<Class>());
constexpr auto class_type_info = user_type<Class>();
return vals[0].get_type_info().bare_equal(class_type_info);
}
protected:
@ -769,36 +777,32 @@ namespace chaiscript
private:
template<typename Type>
auto do_call_impl(Class *o) const -> std::enable_if_t<std::is_pointer<Type>::value, Boxed_Value>
auto do_call_impl(Class *o) const
{
return detail::Handle_Return<Type>::handle(o->*m_attr);
if constexpr(std::is_pointer<Type>::value) {
return detail::Handle_Return<Type>::handle(o->*m_attr);
} else {
return detail::Handle_Return<typename std::add_lvalue_reference<Type>::type>::handle(o->*m_attr);
}
}
template<typename Type>
auto do_call_impl(const Class *o) const -> std::enable_if_t<std::is_pointer<Type>::value, Boxed_Value>
auto do_call_impl(const Class *o) const
{
return detail::Handle_Return<const Type>::handle(o->*m_attr);
if constexpr(std::is_pointer<Type>::value) {
return detail::Handle_Return<const Type>::handle(o->*m_attr);
} else {
return detail::Handle_Return<typename std::add_lvalue_reference<typename std::add_const<Type>::type>::type>::handle(o->*m_attr);
}
}
template<typename Type>
auto do_call_impl(Class *o) const -> std::enable_if_t<!std::is_pointer<Type>::value, Boxed_Value>
{
return detail::Handle_Return<typename std::add_lvalue_reference<Type>::type>::handle(o->*m_attr);
}
template<typename Type>
auto do_call_impl(const Class *o) const -> std::enable_if_t<!std::is_pointer<Type>::value, Boxed_Value>
{
return detail::Handle_Return<typename std::add_lvalue_reference<typename std::add_const<Type>::type>::type>::handle(o->*m_attr);
}
static std::vector<Type_Info> param_types()
{
return {user_type<T>(), user_type<Class>()};
}
std::vector<Type_Info> m_param_types{user_type<T>(), user_type<Class>()};
T Class::* m_attr;
};
}
@ -841,7 +845,7 @@ namespace chaiscript
{
template<typename FuncType>
bool types_match_except_for_arithmetic(const FuncType &t_func, const std::vector<Boxed_Value> &plist,
const Type_Conversions_State &t_conversions)
const Type_Conversions_State &t_conversions) noexcept
{
const std::vector<Type_Info> &types = t_func->get_param_types();

View File

@ -21,7 +21,6 @@
#include "boxed_value.hpp"
#include "handle_return.hpp"
#include "type_info.hpp"
#include "callable_traits.hpp"
namespace chaiscript {
class Type_Conversions_State;
@ -78,14 +77,11 @@ namespace chaiscript
*/
template<typename Ret, typename ... Params>
bool compare_types_cast(Ret (*)(Params...),
const std::vector<Boxed_Value> &params, const Type_Conversions_State &t_conversions)
const std::vector<Boxed_Value> &params, const Type_Conversions_State &t_conversions) noexcept
{
try {
std::vector<Boxed_Value>::size_type i = 0;
(void)i;
(void)params; (void)t_conversions;
// this is ok because the order of evaluation of initializer lists is well defined
(void)std::initializer_list<int>{(boxed_cast<Params>(params[i++], &t_conversions), 0)...};
( boxed_cast<Params>(params[i++], &t_conversions), ... );
return true;
} catch (const exception::bad_boxed_cast &) {
return false;
@ -94,11 +90,11 @@ namespace chaiscript
template<typename Callable, typename Ret, typename ... Params, size_t ... I>
Ret call_func(const chaiscript::dispatch::detail::Function_Signature<Ret (Params...)> &,
Ret call_func(Ret (*)(Params...),
std::index_sequence<I...>, const Callable &f,
const std::vector<Boxed_Value> &params, const Type_Conversions_State &t_conversions)
[[maybe_unused]] const std::vector<Boxed_Value> &params,
[[maybe_unused]] const Type_Conversions_State &t_conversions)
{
(void)params; (void)t_conversions;
return f(boxed_cast<Params>(params[I], &t_conversions)...);
}
@ -108,26 +104,15 @@ namespace chaiscript
/// if any unboxing fails the execution of the function fails and
/// the bad_boxed_cast is passed up to the caller.
template<typename Callable, typename Ret, typename ... Params>
Boxed_Value call_func(const chaiscript::dispatch::detail::Function_Signature<Ret (Params...)> &sig, const Callable &f,
Boxed_Value call_func(Ret (*sig)(Params...), const Callable &f,
const std::vector<Boxed_Value> &params, const Type_Conversions_State &t_conversions)
{
return Handle_Return<Ret>::handle(call_func(sig, std::index_sequence_for<Params...>{}, f, params, t_conversions));
}
template<typename Callable, typename ... Params>
Boxed_Value call_func(const chaiscript::dispatch::detail::Function_Signature<void (Params...)> &sig, const Callable &f,
const std::vector<Boxed_Value> &params, const Type_Conversions_State &t_conversions)
{
call_func(sig, std::index_sequence_for<Params...>{}, f, params, t_conversions);
#ifdef CHAISCRIPT_MSVC
#pragma warning(push)
#pragma warning(disable : 4702)
#endif
// MSVC is reporting that this is unreachable code - and it's wrong.
return Handle_Return<void>::handle();
#ifdef CHAISCRIPT_MSVC
#pragma warning(pop)
#endif
if constexpr (std::is_same_v<Ret, void>) {
call_func(sig, std::index_sequence_for<Params...>{}, f, params, t_conversions);
return Handle_Return<void>::handle();
} else {
return Handle_Return<Ret>::handle(call_func(sig, std::index_sequence_for<Params...>{}, f, params, t_conversions));
}
}
}

View File

@ -15,9 +15,54 @@
#include "bind_first.hpp"
#include "proxy_functions.hpp"
#include "function_signature.hpp"
namespace chaiscript
{
namespace dispatch::detail
{
template<typename Obj, typename Param1, typename ... Rest>
Param1 get_first_param(Function_Params<Param1, Rest...>, Obj &&obj)
{
return static_cast<Param1>(std::forward<Obj>(obj));
}
template<typename Func, bool Is_Noexcept, bool Is_Member, bool Is_MemberObject, bool Is_Object, typename Ret, typename ... Param>
auto make_callable_impl(Func &&func, Function_Signature<Ret, Function_Params<Param...>, Is_Noexcept, Is_Member, Is_MemberObject, Is_Object>)
{
if constexpr (Is_MemberObject) {
// we now that the Param pack will have only one element, so we are safe expanding it here
return Proxy_Function(chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Attribute_Access<Ret, std::decay_t<Param>...>>(std::forward<Func>(func)));
} else if constexpr (Is_Member) {
auto call = [func = std::forward<Func>(func)](auto && obj, auto && ... param) noexcept(Is_Noexcept) -> decltype(auto) {
return (( get_first_param(Function_Params<Param...>{}, obj).*func )(std::forward<decltype(param)>(param)...));
};
return Proxy_Function(
chaiscript::make_shared<dispatch::Proxy_Function_Base,
dispatch::Proxy_Function_Callable_Impl<Ret (Param...), decltype(call)>>(std::move(call))
);
} else {
return Proxy_Function(
chaiscript::make_shared<dispatch::Proxy_Function_Base,
dispatch::Proxy_Function_Callable_Impl<Ret (Param...), std::decay_t<Func>>>(std::forward<Func>(func))
);
}
}
// this version peels off the function object itself from the function signature, when used
// on a callable object
template<typename Func, typename Ret, typename Object, typename ... Param, bool Is_Noexcept>
auto make_callable(Func &&func, Function_Signature<Ret, Function_Params<Object, Param...>, Is_Noexcept, false, false, true>)
{
return make_callable_impl(std::forward<Func>(func), Function_Signature<Ret, Function_Params<Param...>, Is_Noexcept, false, false, true>{});
}
template<typename Func, typename Ret, typename ... Param, bool Is_Noexcept, bool Is_Member, bool Is_MemberObject>
auto make_callable(Func &&func, Function_Signature<Ret, Function_Params<Param...>, Is_Noexcept, Is_Member, Is_MemberObject, false> fs)
{
return make_callable_impl(std::forward<Func>(func), fs);
}
}
/// \brief Creates a new Proxy_Function object from a free function, member function or data member
/// \param[in] t Function / member to expose
@ -40,85 +85,12 @@ namespace chaiscript
///
/// \sa \ref adding_functions
template<typename T>
Proxy_Function fun(const T &t)
Proxy_Function fun(T &&t)
{
typedef typename dispatch::detail::Callable_Traits<T>::Signature Signature;
return Proxy_Function(
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Signature, T>>(t));
return dispatch::detail::make_callable(std::forward<T>(t), dispatch::detail::Function_Signature{t});
}
template<typename Ret, typename ... Param>
Proxy_Function fun(Ret (*func)(Param...))
{
auto fun_call = dispatch::detail::Fun_Caller<Ret, Param...>(func);
return Proxy_Function(
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Ret (Param...), decltype(fun_call)>>(fun_call));
}
template<typename Ret, typename Class, typename ... Param>
Proxy_Function fun(Ret (Class::*t_func)(Param...) const)
{
auto call = dispatch::detail::Const_Caller<Ret, Class, Param...>(t_func);
return Proxy_Function(
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Ret (const Class &, Param...), decltype(call)>>(call));
}
template<typename Ret, typename Class, typename ... Param>
Proxy_Function fun(Ret (Class::*t_func)(Param...))
{
auto call = dispatch::detail::Caller<Ret, Class, Param...>(t_func);
return Proxy_Function(
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Ret (Class &, Param...), decltype(call)>>(call));
}
template<typename T, typename Class /*, typename = typename std::enable_if<std::is_member_object_pointer<T>::value>::type*/>
Proxy_Function fun(T Class::* m /*, typename std::enable_if<std::is_member_object_pointer<T>::value>::type* = 0*/ )
{
return Proxy_Function(chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Attribute_Access<T, Class>>(m));
}
// only compile this bit if noexcept is part of the type system
//
#if (defined(__cpp_noexcept_function_type) && __cpp_noexcept_function_type >= 201510) || (defined(_NOEXCEPT_TYPES_SUPPORTED) && _MSC_VER >= 1912)
template<typename Ret, typename ... Param>
Proxy_Function fun(Ret (*func)(Param...) noexcept)
{
auto fun_call = dispatch::detail::Fun_Caller<Ret, Param...>(func);
return Proxy_Function(
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Ret (Param...), decltype(fun_call)>>(fun_call));
}
template<typename Ret, typename Class, typename ... Param>
Proxy_Function fun(Ret (Class::*t_func)(Param...) const noexcept)
{
auto call = dispatch::detail::Const_Caller<Ret, Class, Param...>(t_func);
return Proxy_Function(
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Ret (const Class &, Param...), decltype(call)>>(call));
}
template<typename Ret, typename Class, typename ... Param>
Proxy_Function fun(Ret (Class::*t_func)(Param...) noexcept)
{
auto call = dispatch::detail::Caller<Ret, Class, Param...>(t_func);
return Proxy_Function(
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Ret (Class &, Param...), decltype(call)>>(call));
}
#endif
/// \brief Creates a new Proxy_Function object from a free function, member function or data member and binds the first parameter of it
/// \param[in] t Function / member to expose
@ -145,6 +117,7 @@ namespace chaiscript
}
}

View File

@ -20,6 +20,7 @@
#include <typeinfo>
#include "../chaiscript_threading.hpp"
#include "../utility/static_string.hpp"
#include "bad_boxed_cast.hpp"
#include "boxed_cast_helper.hpp"
#include "boxed_value.hpp"
@ -33,7 +34,7 @@ namespace chaiscript
{
public:
bad_boxed_dynamic_cast(const Type_Info &t_from, const std::type_info &t_to,
const std::string &t_what) noexcept
const utility::Static_String &t_what) noexcept
: bad_boxed_cast(t_from, t_to, t_what)
{
}
@ -43,7 +44,7 @@ namespace chaiscript
{
}
explicit bad_boxed_dynamic_cast(const std::string &w) noexcept
explicit bad_boxed_dynamic_cast(const utility::Static_String &w) noexcept
: bad_boxed_cast(w)
{
}
@ -57,7 +58,7 @@ namespace chaiscript
{
public:
bad_boxed_type_cast(const Type_Info &t_from, const std::type_info &t_to,
const std::string &t_what) noexcept
const utility::Static_String &t_what) noexcept
: bad_boxed_cast(t_from, t_to, t_what)
{
}
@ -67,7 +68,7 @@ namespace chaiscript
{
}
explicit bad_boxed_type_cast(const std::string &w) noexcept
explicit bad_boxed_type_cast(const utility::Static_String &w) noexcept
: bad_boxed_cast(w)
{
}
@ -87,16 +88,16 @@ namespace chaiscript
virtual Boxed_Value convert(const Boxed_Value &from) const = 0;
virtual Boxed_Value convert_down(const Boxed_Value &to) const = 0;
const Type_Info &to() const
const Type_Info &to() const noexcept
{
return m_to;
}
const Type_Info &from() const
const Type_Info &from() const noexcept
{
return m_from;
}
virtual bool bidir() const
virtual bool bidir() const noexcept
{
return true;
}
@ -122,6 +123,7 @@ namespace chaiscript
public:
static Boxed_Value cast(const Boxed_Value &t_from)
{
if (t_from.get_type_info().bare_equal(chaiscript::user_type<From>()))
{
if (t_from.is_pointer())
@ -272,7 +274,7 @@ namespace chaiscript
"Unable to cast down inheritance hierarchy with non-polymorphic types");
}
bool bidir() const override
bool bidir() const noexcept override
{
return false;
}
@ -306,7 +308,7 @@ namespace chaiscript
return m_func(t_from);
}
bool bidir() const override
bool bidir() const noexcept override
{
return false;
}
@ -328,7 +330,7 @@ namespace chaiscript
struct Less_Than
{
bool operator()(const std::type_info *t_lhs, const std::type_info *t_rhs) const
bool operator()(const std::type_info *t_lhs, const std::type_info *t_rhs) const noexcept
{
return *t_lhs != *t_rhs && t_lhs->before(*t_rhs);
}
@ -370,18 +372,19 @@ namespace chaiscript
}
template<typename T>
bool convertable_type() const
bool convertable_type() const noexcept
{
return thread_cache().count(user_type<T>().bare_type_info()) != 0;
constexpr auto type = user_type<T>().bare_type_info();
return thread_cache().count(type) != 0;
}
template<typename To, typename From>
bool converts() const
bool converts() const noexcept
{
return converts(user_type<To>(), user_type<From>());
}
bool converts(const Type_Info &to, const Type_Info &from) const
bool converts(const Type_Info &to, const Type_Info &from) const noexcept
{
const auto &types = thread_cache();
if (types.count(to.bare_type_info()) != 0 && types.count(from.bare_type_info()) != 0)
@ -459,11 +462,11 @@ namespace chaiscript
{
return *itr;
} else {
throw std::out_of_range("No such conversion exists from " + from.bare_name() + " to " + to.bare_name());
throw std::out_of_range(std::string("No such conversion exists from ") + from.bare_name() + " to " + to.bare_name());
}
}
Conversion_Saves &conversion_saves() const {
Conversion_Saves &conversion_saves() const noexcept {
return *m_conversion_saves;
}
@ -518,15 +521,15 @@ namespace chaiscript
{
}
const Type_Conversions *operator->() const {
const Type_Conversions *operator->() const noexcept {
return &m_conversions.get();
}
const Type_Conversions *get() const {
const Type_Conversions *get() const noexcept {
return &m_conversions.get();
}
Type_Conversions::Conversion_Saves &saves() const {
Type_Conversions::Conversion_Saves &saves() const noexcept {
return m_saves;
}
@ -535,7 +538,7 @@ namespace chaiscript
std::reference_wrapper<Type_Conversions::Conversion_Saves> m_saves;
};
typedef std::shared_ptr<chaiscript::detail::Type_Conversion_Base> Type_Conversion;
using Type_Conversion = std::shared_ptr<chaiscript::detail::Type_Conversion_Base>;
/// \brief Used to register a to / parent class relationship with ChaiScript. Necessary if you
/// want automatic conversions up your inheritance hierarchy.
@ -559,23 +562,17 @@ namespace chaiscript
/// \endcode
///
template<typename Base, typename Derived>
Type_Conversion base_class(typename std::enable_if<std::is_polymorphic<Base>::value && std::is_polymorphic<Derived>::value>::type* = nullptr)
Type_Conversion base_class()
{
//Can only be used with related polymorphic types
//may be expanded some day to support conversions other than child -> parent
static_assert(std::is_base_of<Base,Derived>::value, "Classes are not related by inheritance");
return chaiscript::make_shared<detail::Type_Conversion_Base, detail::Dynamic_Conversion_Impl<Base, Derived>>();
}
template<typename Base, typename Derived>
Type_Conversion base_class(typename std::enable_if<!std::is_polymorphic<Base>::value || !std::is_polymorphic<Derived>::value>::type* = nullptr)
{
//Can only be used with related polymorphic types
//may be expanded some day to support conversions other than child -> parent
static_assert(std::is_base_of<Base,Derived>::value, "Classes are not related by inheritance");
return chaiscript::make_shared<detail::Type_Conversion_Base, detail::Static_Conversion_Impl<Base, Derived>>();
if constexpr(std::is_polymorphic<Base>::value && std::is_polymorphic<Derived>::value) {
return chaiscript::make_shared<detail::Type_Conversion_Base, detail::Dynamic_Conversion_Impl<Base, Derived>>();
} else {
return chaiscript::make_shared<detail::Type_Conversion_Base, detail::Static_Conversion_Impl<Base, Derived>>();
}
}

View File

@ -24,7 +24,7 @@ namespace chaiscript
template<typename T>
struct Bare_Type
{
typedef typename std::remove_cv<typename std::remove_pointer<typename std::remove_reference<T>::type>::type>::type type;
using type = typename std::remove_cv<typename std::remove_pointer<typename std::remove_reference<T>::type>::type>::type;
};
}
@ -34,7 +34,7 @@ namespace chaiscript
{
public:
constexpr Type_Info(const bool t_is_const, const bool t_is_reference, const bool t_is_pointer, const bool t_is_void,
const bool t_is_arithmetic, const std::type_info *t_ti, const std::type_info *t_bare_ti)
const bool t_is_arithmetic, const std::type_info *t_ti, const std::type_info *t_bare_ti) noexcept
: m_type_info(t_ti), m_bare_type_info(t_bare_ti),
m_flags((static_cast<unsigned int>(t_is_const) << is_const_flag)
+ (static_cast<unsigned int>(t_is_reference) << is_reference_flag)
@ -44,7 +44,7 @@ namespace chaiscript
{
}
constexpr Type_Info() = default;
constexpr Type_Info() noexcept = default;
bool operator<(const Type_Info &ti) const noexcept
{
@ -90,7 +90,7 @@ namespace chaiscript
constexpr bool is_undef() const noexcept { return (m_flags & (1 << is_undef_flag)) != 0; }
constexpr bool is_pointer() const noexcept { return (m_flags & (1 << is_pointer_flag)) != 0; }
std::string name() const
const char * name() const noexcept
{
if (!is_undef())
{
@ -100,7 +100,7 @@ namespace chaiscript
}
}
std::string bare_name() const
const char * bare_name() const noexcept
{
if (!is_undef())
{
@ -110,7 +110,7 @@ namespace chaiscript
}
}
constexpr const std::type_info *bare_type_info() const
constexpr const std::type_info *bare_type_info() const noexcept
{
return m_bare_type_info;
}
@ -135,7 +135,7 @@ namespace chaiscript
template<typename T>
struct Get_Type_Info
{
static constexpr Type_Info get()
constexpr static Type_Info get() noexcept
{
return Type_Info(std::is_const<typename std::remove_pointer<typename std::remove_reference<T>::type>::type>::value,
std::is_reference<T>::value, std::is_pointer<T>::value,
@ -152,7 +152,7 @@ namespace chaiscript
{
// typedef T type;
static constexpr Type_Info get()
constexpr static Type_Info get() noexcept
{
return Type_Info(std::is_const<T>::value, std::is_reference<T>::value, std::is_pointer<T>::value,
std::is_void<T>::value,
@ -170,7 +170,7 @@ namespace chaiscript
template<typename T>
struct Get_Type_Info<const std::shared_ptr<T> &>
{
static constexpr Type_Info get()
constexpr static Type_Info get() noexcept
{
return Type_Info(std::is_const<T>::value, std::is_reference<T>::value, std::is_pointer<T>::value,
std::is_void<T>::value,
@ -183,7 +183,7 @@ namespace chaiscript
template<typename T>
struct Get_Type_Info<std::reference_wrapper<T> >
{
static constexpr Type_Info get()
constexpr static Type_Info get() noexcept
{
return Type_Info(std::is_const<T>::value, std::is_reference<T>::value, std::is_pointer<T>::value,
std::is_void<T>::value,
@ -196,7 +196,7 @@ namespace chaiscript
template<typename T>
struct Get_Type_Info<const std::reference_wrapper<T> &>
{
static constexpr Type_Info get()
constexpr static Type_Info get() noexcept
{
return Type_Info(std::is_const<T>::value, std::is_reference<T>::value, std::is_pointer<T>::value,
std::is_void<T>::value,
@ -218,7 +218,7 @@ namespace chaiscript
/// chaiscript::Type_Info ti = chaiscript::user_type(i);
/// \endcode
template<typename T>
constexpr Type_Info user_type(const T &/*t*/)
constexpr Type_Info user_type(const T &/*t*/) noexcept
{
return detail::Get_Type_Info<T>::get();
}
@ -233,7 +233,7 @@ namespace chaiscript
/// chaiscript::Type_Info ti = chaiscript::user_type<int>();
/// \endcode
template<typename T>
constexpr Type_Info user_type()
constexpr Type_Info user_type() noexcept
{
return detail::Get_Type_Info<T>::get();
}

View File

@ -11,7 +11,7 @@
#ifndef CHAISCRIPT_ALGEBRAIC_HPP_
#define CHAISCRIPT_ALGEBRAIC_HPP_
#include "../utility/fnv1a.hpp"
#include "../utility/hash.hpp"
#include <string>
@ -21,23 +21,18 @@ namespace chaiscript
struct Operators {
enum class Opers
{
boolean_flag,
equals, less_than, greater_than, less_than_equal, greater_than_equal, not_equal,
non_const_flag,
assign, pre_increment, pre_decrement, assign_product, assign_sum,
assign_quotient, assign_difference,
non_const_int_flag,
assign_bitwise_and, assign_bitwise_or, assign_shift_left, assign_shift_right,
assign_remainder, assign_bitwise_xor,
const_int_flag,
shift_left, shift_right, remainder, bitwise_and, bitwise_or, bitwise_xor, bitwise_complement,
const_flag,
sum, quotient, product, difference, unary_plus, unary_minus,
invalid
};
static const char *to_string(Opers t_oper) {
static const char *opers[] = {
constexpr static const char *to_string(Opers t_oper) noexcept {
constexpr const char *opers[] = {
"",
"==", "<", ">", "<=", ">=", "!=",
"",
@ -55,44 +50,44 @@ namespace chaiscript
return opers[static_cast<int>(t_oper)];
}
static Opers to_operator(const std::string &t_str, bool t_is_unary = false)
constexpr static Opers to_operator(const std::string_view &t_str, bool t_is_unary = false) noexcept
{
#ifdef CHAISCRIPT_MSVC
#pragma warning(push)
#pragma warning(disable : 4307)
#endif
const auto op_hash = utility::fnv1a_32(t_str.c_str());
const auto op_hash = utility::hash(t_str);
switch (op_hash) {
case utility::fnv1a_32("=="): { return Opers::equals; }
case utility::fnv1a_32("<"): { return Opers::less_than; }
case utility::fnv1a_32(">"): { return Opers::greater_than; }
case utility::fnv1a_32("<="): { return Opers::less_than_equal; }
case utility::fnv1a_32(">="): { return Opers::greater_than_equal; }
case utility::fnv1a_32("!="): { return Opers::not_equal; }
case utility::fnv1a_32("="): { return Opers::assign; }
case utility::fnv1a_32("++"): { return Opers::pre_increment; }
case utility::fnv1a_32("--"): { return Opers::pre_decrement; }
case utility::fnv1a_32("*="): { return Opers::assign_product; }
case utility::fnv1a_32("+="): { return Opers::assign_sum; }
case utility::fnv1a_32("-="): { return Opers::assign_difference; }
case utility::fnv1a_32("&="): { return Opers::assign_bitwise_and; }
case utility::fnv1a_32("|="): { return Opers::assign_bitwise_or; }
case utility::fnv1a_32("<<="): { return Opers::assign_shift_left; }
case utility::fnv1a_32(">>="): { return Opers::assign_shift_right; }
case utility::fnv1a_32("%="): { return Opers::assign_remainder; }
case utility::fnv1a_32("^="): { return Opers::assign_bitwise_xor; }
case utility::fnv1a_32("<<"): { return Opers::shift_left; }
case utility::fnv1a_32(">>"): { return Opers::shift_right; }
case utility::fnv1a_32("%"): { return Opers::remainder; }
case utility::fnv1a_32("&"): { return Opers::bitwise_and; }
case utility::fnv1a_32("|"): { return Opers::bitwise_or; }
case utility::fnv1a_32("^"): { return Opers::bitwise_xor; }
case utility::fnv1a_32("~"): { return Opers::bitwise_complement; }
case utility::fnv1a_32("+"): { return t_is_unary ? Opers::unary_plus : Opers::sum; }
case utility::fnv1a_32("-"): { return t_is_unary ? Opers::unary_minus : Opers::difference; }
case utility::fnv1a_32("/"): { return Opers::quotient; }
case utility::fnv1a_32("*"): { return Opers::product; }
case utility::hash("=="): { return Opers::equals; }
case utility::hash("<"): { return Opers::less_than; }
case utility::hash(">"): { return Opers::greater_than; }
case utility::hash("<="): { return Opers::less_than_equal; }
case utility::hash(">="): { return Opers::greater_than_equal; }
case utility::hash("!="): { return Opers::not_equal; }
case utility::hash("="): { return Opers::assign; }
case utility::hash("++"): { return Opers::pre_increment; }
case utility::hash("--"): { return Opers::pre_decrement; }
case utility::hash("*="): { return Opers::assign_product; }
case utility::hash("+="): { return Opers::assign_sum; }
case utility::hash("-="): { return Opers::assign_difference; }
case utility::hash("&="): { return Opers::assign_bitwise_and; }
case utility::hash("|="): { return Opers::assign_bitwise_or; }
case utility::hash("<<="): { return Opers::assign_shift_left; }
case utility::hash(">>="): { return Opers::assign_shift_right; }
case utility::hash("%="): { return Opers::assign_remainder; }
case utility::hash("^="): { return Opers::assign_bitwise_xor; }
case utility::hash("<<"): { return Opers::shift_left; }
case utility::hash(">>"): { return Opers::shift_right; }
case utility::hash("%"): { return Opers::remainder; }
case utility::hash("&"): { return Opers::bitwise_and; }
case utility::hash("|"): { return Opers::bitwise_or; }
case utility::hash("^"): { return Opers::bitwise_xor; }
case utility::hash("~"): { return Opers::bitwise_complement; }
case utility::hash("+"): { return t_is_unary ? Opers::unary_plus : Opers::sum; }
case utility::hash("-"): { return t_is_unary ? Opers::unary_minus : Opers::difference; }
case utility::hash("/"): { return Opers::quotient; }
case utility::hash("*"): { return Opers::product; }
default: { return Opers::invalid; }
}
#ifdef CHAISCRIPT_MSVC

View File

@ -23,6 +23,7 @@
#include "../dispatchkit/dispatchkit.hpp"
#include "../dispatchkit/proxy_functions.hpp"
#include "../dispatchkit/type_info.hpp"
#include <unordered_set>
namespace chaiscript {
struct AST_Node;
@ -31,34 +32,59 @@ struct AST_Node;
namespace chaiscript
{
struct Name_Validator {
static bool is_reserved_word(const std::string &name)
template<typename T>
static bool is_reserved_word(const T &s) noexcept
{
static const std::set<std::string> m_reserved_words
= {"def", "fun", "while", "for", "if", "else", "&&", "||", ",", "auto",
"return", "break", "true", "false", "class", "attr", "var", "global", "GLOBAL", "_",
"__LINE__", "__FILE__", "__FUNC__", "__CLASS__"};
return m_reserved_words.count(name) > 0;
const static std::unordered_set<std::uint32_t> words{
utility::hash("def"),
utility::hash("fun"),
utility::hash("while"),
utility::hash("for"),
utility::hash("if"),
utility::hash("else"),
utility::hash("&&"),
utility::hash("||"),
utility::hash(","),
utility::hash("auto"),
utility::hash("return"),
utility::hash("break"),
utility::hash("true"),
utility::hash("false"),
utility::hash("class"),
utility::hash("attr"),
utility::hash("var"),
utility::hash("global"),
utility::hash("GLOBAL"),
utility::hash("_"),
utility::hash("__LINE__"),
utility::hash("__FILE__"),
utility::hash("__FUNC__"),
utility::hash("__CLASS__")};
return words.count(utility::hash(s)) == 1;
}
static bool valid_object_name(const std::string &name)
template<typename T>
static bool valid_object_name(const T &name) noexcept
{
return name.find("::") == std::string::npos && !is_reserved_word(name);
}
static void validate_object_name(const std::string &name)
template<typename T>
static void validate_object_name(const T &name)
{
if (is_reserved_word(name)) {
throw exception::reserved_word_error(name);
throw exception::reserved_word_error(std::string(name));
}
if (name.find("::") != std::string::npos) {
throw exception::illegal_name_error(name);
throw exception::illegal_name_error(std::string(name));
}
}
};
/// Signature of module entry point that all binary loadable modules must implement.
typedef ModulePtr (*Create_Module_Func)();
using Create_Module_Func = ModulePtr (*)();
/// Types of AST nodes available to the parser and eval
@ -76,8 +102,8 @@ namespace chaiscript
namespace
{
/// Helper lookup to get the name of each node type
inline const char *ast_node_type_to_string(AST_Node_Type ast_node_type) {
static const char * const ast_node_types[] = { "Id", "Fun_Call", "Unused_Return_Fun_Call", "Arg_List", "Equation", "Var_Decl", "Assign_Decl",
constexpr const char *ast_node_type_to_string(AST_Node_Type ast_node_type) noexcept {
constexpr const char * const ast_node_types[] = { "Id", "Fun_Call", "Unused_Return_Fun_Call", "Arg_List", "Equation", "Var_Decl", "Assign_Decl",
"Array_Call", "Dot_Access",
"Lambda", "Block", "Scopeless_Block", "Def", "While", "If", "For", "Ranged_For", "Inline_Array", "Inline_Map", "Return", "File", "Prefix", "Break", "Continue", "Map_Pair", "Value_Range",
"Inline_Range", "Try", "Catch", "Finally", "Method", "Attr_Decl",
@ -89,13 +115,13 @@ namespace chaiscript
/// \brief Convenience type for file positions
struct File_Position {
int line;
int column;
int line = 0;
int column = 0;
File_Position(int t_file_line, int t_file_column)
constexpr File_Position(int t_file_line, int t_file_column) noexcept
: line(t_file_line), column(t_file_column) { }
File_Position() : line(0), column(0) { }
constexpr File_Position() noexcept = default;
};
struct Parse_Location {
@ -124,8 +150,8 @@ namespace chaiscript
/// \brief Typedef for pointers to AST_Node objects. Used in building of the AST_Node tree
typedef std::unique_ptr<AST_Node> AST_NodePtr;
typedef std::unique_ptr<const AST_Node> AST_NodePtr_Const;
using AST_NodePtr = std::unique_ptr<AST_Node>;
using AST_NodePtr_Const = std::unique_ptr<const AST_Node>;
struct AST_Node_Trace;
@ -136,7 +162,7 @@ namespace chaiscript
/// \brief Thrown if an error occurs while attempting to load a binary module
struct load_module_error : std::runtime_error
{
explicit load_module_error(const std::string &t_reason) noexcept
explicit load_module_error(const std::string &t_reason)
: std::runtime_error(t_reason)
{
}
@ -228,7 +254,7 @@ namespace chaiscript
private:
template<typename T>
static AST_Node_Type id(const T& t)
static AST_Node_Type id(const T& t) noexcept
{
return t.identifier;
}
@ -240,7 +266,7 @@ namespace chaiscript
}
template<typename T>
static const std::string &fname(const T& t)
static const std::string &fname(const T& t) noexcept
{
return t.filename();
}
@ -479,7 +505,7 @@ namespace chaiscript
/// Errors generated when loading a file
struct file_not_found_error : std::runtime_error {
explicit file_not_found_error(const std::string &t_filename) noexcept
explicit file_not_found_error(const std::string &t_filename)
: std::runtime_error("File Not Found: " + t_filename),
filename(t_filename)
{ }
@ -500,15 +526,15 @@ namespace chaiscript
const std::string text;
Parse_Location location;
const std::string &filename() const {
const std::string &filename() const noexcept {
return *location.filename;
}
const File_Position &start() const {
const File_Position &start() const noexcept {
return location.start;
}
const File_Position &end() const {
const File_Position &end() const noexcept {
return location.end;
}
@ -553,7 +579,7 @@ namespace chaiscript
}
virtual ~AST_Node() = default;
virtual ~AST_Node() noexcept = default;
AST_Node(AST_Node &&) = default;
AST_Node &operator=(AST_Node &&) = default;
AST_Node(const AST_Node &) = delete;
@ -576,15 +602,15 @@ namespace chaiscript
const std::string text;
Parse_Location location;
const std::string &filename() const {
const std::string &filename() const noexcept {
return *location.filename;
}
const File_Position &start() const {
const File_Position &start() const noexcept {
return location.start;
}
const File_Position &end() const {
const File_Position &end() const noexcept {
return location.end;
}
@ -632,7 +658,7 @@ namespace chaiscript
ChaiScript_Parser_Base &operator=(const ChaiScript_Parser_Base &&) = delete;
template<typename T>
T &get_tracer()
T &get_tracer() noexcept
{
// to do type check this somehow?
return *static_cast<T*>(get_tracer_ptr());
@ -655,13 +681,11 @@ namespace chaiscript
/// Special type indicating a call to 'break'
struct Break_Loop {
Break_Loop() = default;
};
/// Special type indicating a call to 'continue'
struct Continue_Loop {
Continue_Loop() = default;
};

View File

@ -98,7 +98,7 @@ namespace chaiscript
/// Evaluates the given file and looks in the 'use' paths
const Boxed_Value internal_eval_file(const std::string &t_filename) {
Boxed_Value internal_eval_file(const std::string &t_filename) {
for (const auto &path : m_use_paths)
{
try {
@ -119,7 +119,7 @@ namespace chaiscript
/// Evaluates the given string, used during eval() inside of a script
const Boxed_Value internal_eval(const std::string &t_e) {
Boxed_Value internal_eval(const std::string &t_e) {
try {
return do_eval(t_e, "__EVAL__", true);
} catch (const exception::eval_error &t_ee) {
@ -128,7 +128,7 @@ namespace chaiscript
}
/// Returns the current evaluation m_engine
chaiscript::detail::Dispatch_Engine &get_eval_engine() {
chaiscript::detail::Dispatch_Engine &get_eval_engine() noexcept {
return m_engine;
}
@ -343,13 +343,13 @@ namespace chaiscript
}
}
#else // CHAISCRIPT_NO_DYNLOAD
explicit ChaiScript_Basic(std::unique_ptr<parser::ChaiScript_Parser_Base> &&parser,
std::vector<std::string> t_module_paths = {},
std::vector<std::string> t_use_paths = {},
const std::vector<chaiscript::Options> &t_opts = chaiscript::default_options()) = delete;
explicit ChaiScript_Basic(std::unique_ptr<parser::ChaiScript_Parser_Base> &&parser,
std::vector<std::string> t_module_paths = {},
std::vector<std::string> t_use_paths = {},
const std::vector<chaiscript::Options> &t_opts = chaiscript::default_options()) = delete;
#endif
parser::ChaiScript_Parser_Base &get_parser()
parser::ChaiScript_Parser_Base &get_parser() noexcept
{
return *m_parser;
}
@ -594,7 +594,6 @@ explicit ChaiScript_Basic(std::unique_ptr<parser::ChaiScript_Parser_Base> &&pars
std::string load_module(const std::string &t_module_name)
{
#ifdef CHAISCRIPT_NO_DYNLOAD
(void)t_module_name; // -Wunused-parameter
throw chaiscript::exception::load_module_error("Loadable module support was disabled (CHAISCRIPT_NO_DYNLOAD)");
#else
std::vector<exception::load_module_error> errors;

View File

@ -34,11 +34,9 @@
#include "chaiscript_algebraic.hpp"
#include "chaiscript_common.hpp"
namespace chaiscript {
namespace exception {
namespace chaiscript::exception {
class bad_boxed_cast;
} // namespace exception
} // namespace chaiscript
} // namespace chaiscript::exception
namespace chaiscript
{
@ -57,8 +55,9 @@ namespace chaiscript
chaiscript::detail::Dispatch_State state(t_ss);
const Boxed_Value *thisobj = [&]() -> const Boxed_Value *{
auto &stack = t_ss.get_stack_data(state.stack_holder()).back();
if (!stack.empty() && stack.back().first == "__this") {
if (auto &stack = t_ss.get_stack_data(state.stack_holder()).back();
!stack.empty() && stack.back().first == "__this")
{
return &stack.back().second;
} else if (!t_vals.empty()) {
return &t_vals[0];
@ -71,8 +70,8 @@ namespace chaiscript
if (thisobj && !has_this_capture) { state.add_object("this", *thisobj); }
if (t_locals) {
for (const auto &local : *t_locals) {
state.add_object(local.first, local.second);
for (const auto &[name, value] : *t_locals) {
state.add_object(name, value);
}
}
@ -126,7 +125,7 @@ namespace chaiscript
std::vector<std::reference_wrapper<AST_Node>> get_children() const final {
std::vector<std::reference_wrapper<AST_Node>> retval;
retval.reserve(children.size());
for (auto &&child : children) {
for (auto &child : children) {
retval.emplace_back(*child);
}
@ -706,7 +705,7 @@ namespace chaiscript
);
}
static bool has_this_capture(const std::vector<AST_Node_Impl_Ptr<T>> &children) {
static bool has_this_capture(const std::vector<AST_Node_Impl_Ptr<T>> &children) noexcept {
return std::any_of(std::begin(children), std::end(children),
[](const auto &child){
return child->children[0]->text == "this";
@ -782,7 +781,7 @@ namespace chaiscript
return std::move(vec.back());
}
static bool has_guard(const std::vector<AST_Node_Impl_Ptr<T>> &t_children, const std::size_t offset)
static bool has_guard(const std::vector<AST_Node_Impl_Ptr<T>> &t_children, const std::size_t offset) noexcept
{
if ((t_children.size() > 2 + offset) && (t_children[1+offset]->identifier == AST_Node_Type::Arg_List)) {
if (t_children.size() > 3 + offset) {
@ -909,9 +908,9 @@ namespace chaiscript
Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override{
const auto get_function = [&t_ss](const std::string &t_name, auto &t_hint){
uint_fast32_t hint = t_hint;
auto funs = t_ss->get_function(t_name, hint);
if (funs.first != hint) { t_hint = uint_fast32_t(funs.first); }
return std::move(funs.second);
auto [funs_loc, funs] = t_ss->get_function(t_name, hint);
if (funs_loc != hint) { t_hint = uint_fast32_t(funs_loc); }
return std::move(funs);
};
const auto call_function = [&t_ss](const auto &t_funcs, const Boxed_Value &t_param) {

View File

@ -24,13 +24,13 @@ namespace chaiscript {
template<typename Tracer>
auto optimize(eval::AST_Node_Impl_Ptr<Tracer> p) {
(void)std::initializer_list<int>{ (p = static_cast<T&>(*this).optimize(std::move(p)), 0)... };
( (p = static_cast<T&>(*this).optimize(std::move(p))), ... );
return p;
}
};
template<typename T>
eval::AST_Node_Impl<T> &child_at(eval::AST_Node_Impl<T> &node, const size_t offset) {
eval::AST_Node_Impl<T> &child_at(eval::AST_Node_Impl<T> &node, const size_t offset) noexcept {
if (node.children[offset]->identifier == AST_Node_Type::Compiled) {
return *(dynamic_cast<eval::Compiled_AST_Node<T> &>(*node.children[offset]).m_original_node);
} else {
@ -39,7 +39,7 @@ namespace chaiscript {
}
template<typename T>
const eval::AST_Node_Impl<T> &child_at(const eval::AST_Node_Impl<T> &node, const size_t offset) {
const eval::AST_Node_Impl<T> &child_at(const eval::AST_Node_Impl<T> &node, const size_t offset) noexcept {
if (node.children[offset]->identifier == AST_Node_Type::Compiled) {
return *(dynamic_cast<const eval::Compiled_AST_Node<T> &>(*node.children[offset]).m_original_node);
} else {
@ -57,7 +57,7 @@ namespace chaiscript {
}
template<typename T>
auto child_count(const eval::AST_Node_Impl<T> &node) {
auto child_count(const eval::AST_Node_Impl<T> &node) noexcept {
if (node.identifier == AST_Node_Type::Compiled) {
return dynamic_cast<const eval::Compiled_AST_Node<T>&>(node).m_original_node->children.size();
} else {
@ -95,7 +95,7 @@ namespace chaiscript {
};
template<typename T>
bool contains_var_decl_in_scope(const eval::AST_Node_Impl<T> &node)
bool contains_var_decl_in_scope(const eval::AST_Node_Impl<T> &node) noexcept
{
if (node.identifier == AST_Node_Type::Var_Decl || node.identifier == AST_Node_Type::Assign_Decl || node.identifier == AST_Node_Type::Reference) {
return true;
@ -469,3 +469,4 @@ namespace chaiscript {
#endif

View File

@ -27,7 +27,7 @@
#include "chaiscript_common.hpp"
#include "chaiscript_optimizer.hpp"
#include "chaiscript_tracer.hpp"
#include "../utility/fnv1a.hpp"
#include "../utility/hash.hpp"
#include "../utility/static_string.hpp"
#if defined(CHAISCRIPT_UTF16_UTF32)
@ -76,7 +76,7 @@ namespace chaiscript
// common for all implementations
static std::string u8str_from_ll(long long val)
{
typedef std::string::value_type char_type;
using char_type = std::string::value_type;
char_type c[2];
c[1] = char_type(val);
@ -92,7 +92,7 @@ namespace chaiscript
static string_type str_from_ll(long long val)
{
typedef typename string_type::value_type target_char_type;
using target_char_type = typename string_type::value_type;
#if defined (CHAISCRIPT_UTF16_UTF32)
// prepare converter
std::wstring_convert<std::codecvt_utf8<target_char_type>, target_char_type> converter;
@ -120,7 +120,7 @@ namespace chaiscript
template<typename Tracer, typename Optimizer, std::size_t Parse_Depth=512>
class ChaiScript_Parser final : public ChaiScript_Parser_Base {
void *get_tracer_ptr() override {
void *get_tracer_ptr() noexcept override {
return &m_tracer;
}
@ -146,97 +146,147 @@ namespace chaiscript
ChaiScript_Parser *parser;
};
static std::array<std::array<bool, detail::lengthof_alphabet>, detail::max_alphabet> build_alphabet()
template<typename Array2D, typename First, typename Second>
constexpr static void set_alphabet(Array2D &array, const First first, const Second second) noexcept
{
std::array<std::array<bool, detail::lengthof_alphabet>, detail::max_alphabet> alphabet;
auto *first_ptr = &std::get<0>(array) + static_cast<std::size_t>(first);
auto *second_ptr = &std::get<0>(*first_ptr) + static_cast<std::size_t>(second);
*second_ptr = true;
}
for (auto &alpha : alphabet) {
alpha.fill(false);
}
constexpr static std::array<std::array<bool, detail::lengthof_alphabet>, detail::max_alphabet> build_alphabet() noexcept
{
std::array<std::array<bool, detail::lengthof_alphabet>, detail::max_alphabet> alphabet{};
alphabet[detail::symbol_alphabet][static_cast<size_t>('?')]=true;
alphabet[detail::symbol_alphabet][static_cast<size_t>('+')]=true;
alphabet[detail::symbol_alphabet][static_cast<size_t>('-')]=true;
alphabet[detail::symbol_alphabet][static_cast<size_t>('*')]=true;
alphabet[detail::symbol_alphabet][static_cast<size_t>('/')]=true;
alphabet[detail::symbol_alphabet][static_cast<size_t>('|')]=true;
alphabet[detail::symbol_alphabet][static_cast<size_t>('&')]=true;
alphabet[detail::symbol_alphabet][static_cast<size_t>('^')]=true;
alphabet[detail::symbol_alphabet][static_cast<size_t>('=')]=true;
alphabet[detail::symbol_alphabet][static_cast<size_t>('.')]=true;
alphabet[detail::symbol_alphabet][static_cast<size_t>('<')]=true;
alphabet[detail::symbol_alphabet][static_cast<size_t>('>')]=true;
set_alphabet(alphabet, detail::symbol_alphabet, '?');
for ( size_t c = 'a' ; c <= 'z' ; ++c ) { alphabet[detail::keyword_alphabet][c]=true; }
for ( size_t c = 'A' ; c <= 'Z' ; ++c ) { alphabet[detail::keyword_alphabet][c]=true; }
for ( size_t c = '0' ; c <= '9' ; ++c ) { alphabet[detail::keyword_alphabet][c]=true; }
alphabet[detail::keyword_alphabet][static_cast<size_t>('_')]=true;
set_alphabet(alphabet, detail::symbol_alphabet, '?');
set_alphabet(alphabet, detail::symbol_alphabet, '+');
set_alphabet(alphabet, detail::symbol_alphabet, '-');
set_alphabet(alphabet, detail::symbol_alphabet, '*');
set_alphabet(alphabet, detail::symbol_alphabet, '/');
set_alphabet(alphabet, detail::symbol_alphabet, '|');
set_alphabet(alphabet, detail::symbol_alphabet, '&');
set_alphabet(alphabet, detail::symbol_alphabet, '^');
set_alphabet(alphabet, detail::symbol_alphabet, '=');
set_alphabet(alphabet, detail::symbol_alphabet, '.');
set_alphabet(alphabet, detail::symbol_alphabet, '<');
set_alphabet(alphabet, detail::symbol_alphabet, '>');
for ( size_t c = '0' ; c <= '9' ; ++c ) { alphabet[detail::int_alphabet][c]=true; }
for ( size_t c = '0' ; c <= '9' ; ++c ) { alphabet[detail::float_alphabet][c]=true; }
alphabet[detail::float_alphabet][static_cast<size_t>('.')]=true;
for ( size_t c = 'a' ; c <= 'z' ; ++c ) { set_alphabet(alphabet, detail::keyword_alphabet, c); }
for ( size_t c = 'A' ; c <= 'Z' ; ++c ) { set_alphabet(alphabet, detail::keyword_alphabet, c); }
for ( size_t c = '0' ; c <= '9' ; ++c ) { set_alphabet(alphabet, detail::keyword_alphabet, c); }
set_alphabet(alphabet, detail::keyword_alphabet, '_');
for ( size_t c = '0' ; c <= '9' ; ++c ) { alphabet[detail::hex_alphabet][c]=true; }
for ( size_t c = 'a' ; c <= 'f' ; ++c ) { alphabet[detail::hex_alphabet][c]=true; }
for ( size_t c = 'A' ; c <= 'F' ; ++c ) { alphabet[detail::hex_alphabet][c]=true; }
for ( size_t c = '0' ; c <= '9' ; ++c ) { set_alphabet(alphabet, detail::int_alphabet, c); }
for ( size_t c = '0' ; c <= '9' ; ++c ) { set_alphabet(alphabet, detail::float_alphabet, c); }
set_alphabet(alphabet, detail::float_alphabet, '.');
alphabet[detail::x_alphabet][static_cast<size_t>('x')]=true;
alphabet[detail::x_alphabet][static_cast<size_t>('X')]=true;
for ( size_t c = '0' ; c <= '9' ; ++c ) { set_alphabet(alphabet, detail::hex_alphabet, c); }
for ( size_t c = 'a' ; c <= 'f' ; ++c ) { set_alphabet(alphabet, detail::hex_alphabet, c); }
for ( size_t c = 'A' ; c <= 'F' ; ++c ) { set_alphabet(alphabet, detail::hex_alphabet, c); }
for ( size_t c = '0' ; c <= '1' ; ++c ) { alphabet[detail::bin_alphabet][c]=true; }
alphabet[detail::b_alphabet][static_cast<size_t>('b')]=true;
alphabet[detail::b_alphabet][static_cast<size_t>('B')]=true;
set_alphabet(alphabet, detail::x_alphabet, 'x');
set_alphabet(alphabet, detail::x_alphabet, 'X');
for ( size_t c = 'a' ; c <= 'z' ; ++c ) { alphabet[detail::id_alphabet][c]=true; }
for ( size_t c = 'A' ; c <= 'Z' ; ++c ) { alphabet[detail::id_alphabet][c]=true; }
alphabet[detail::id_alphabet][static_cast<size_t>('_')] = true;
for ( size_t c = '0' ; c <= '1' ; ++c ) { set_alphabet(alphabet, detail::bin_alphabet, c); }
set_alphabet(alphabet, detail::b_alphabet, 'b');
set_alphabet(alphabet, detail::b_alphabet, 'B');
alphabet[detail::white_alphabet][static_cast<size_t>(' ')]=true;
alphabet[detail::white_alphabet][static_cast<size_t>('\t')]=true;
for ( size_t c = 'a' ; c <= 'z' ; ++c ) { set_alphabet(alphabet, detail::id_alphabet, c); }
for ( size_t c = 'A' ; c <= 'Z' ; ++c ) { set_alphabet(alphabet, detail::id_alphabet, c); }
set_alphabet(alphabet, detail::id_alphabet, '_');
alphabet[detail::int_suffix_alphabet][static_cast<size_t>('l')] = true;
alphabet[detail::int_suffix_alphabet][static_cast<size_t>('L')] = true;
alphabet[detail::int_suffix_alphabet][static_cast<size_t>('u')] = true;
alphabet[detail::int_suffix_alphabet][static_cast<size_t>('U')] = true;
set_alphabet(alphabet, detail::white_alphabet, ' ');
set_alphabet(alphabet, detail::white_alphabet, '\t');
alphabet[detail::float_suffix_alphabet][static_cast<size_t>('l')] = true;
alphabet[detail::float_suffix_alphabet][static_cast<size_t>('L')] = true;
alphabet[detail::float_suffix_alphabet][static_cast<size_t>('f')] = true;
alphabet[detail::float_suffix_alphabet][static_cast<size_t>('F')] = true;
set_alphabet(alphabet, detail::int_suffix_alphabet, 'l');
set_alphabet(alphabet, detail::int_suffix_alphabet, 'L');
set_alphabet(alphabet, detail::int_suffix_alphabet, 'u');
set_alphabet(alphabet, detail::int_suffix_alphabet, 'U');
set_alphabet(alphabet, detail::float_suffix_alphabet, 'l');
set_alphabet(alphabet, detail::float_suffix_alphabet, 'L');
set_alphabet(alphabet, detail::float_suffix_alphabet, 'f');
set_alphabet(alphabet, detail::float_suffix_alphabet, 'F');
return alphabet;
}
static const std::array<std::array<bool, detail::lengthof_alphabet>, detail::max_alphabet> &create_alphabet()
struct Operator_Matches
{
static const auto alpha = build_alphabet();
return alpha;
}
using SS = utility::Static_String;
static const std::vector<std::vector<utility::Static_String>> &create_operator_matches() {
static const std::vector<std::vector<utility::Static_String>> operator_matches {
{"?"},
{"||"},
{"&&"},
{"|"},
{"^"},
{"&"},
{"==", "!="},
{"<", "<=", ">", ">="},
{"<<", ">>"},
std::array<utility::Static_String, 1> m_0 {{SS("?")}};
std::array<utility::Static_String, 1> m_1 {{SS("||")}};
std::array<utility::Static_String, 1> m_2 {{SS("&&")}};
std::array<utility::Static_String, 1> m_3 {{SS("|")}};
std::array<utility::Static_String, 1> m_4 {{SS("^")}};
std::array<utility::Static_String, 1> m_5 {{SS("&")}};
std::array<utility::Static_String, 2> m_6 {{SS("=="), SS("!=")}};
std::array<utility::Static_String, 4> m_7 {{SS("<"), SS("<="), SS(">"), SS(">=")}};
std::array<utility::Static_String, 2> m_8 {{SS("<<"), SS(">>")}};
//We share precedence here but then separate them later
{"+", "-"},
{"*", "/", "%"},
{"++", "--", "-", "+", "!", "~"}
};
std::array<utility::Static_String, 2> m_9 {{SS("+"), SS("-")}};
std::array<utility::Static_String, 3> m_10 {{SS("*"), SS("/"), SS("%")}};
std::array<utility::Static_String, 6> m_11 {{SS("++"), SS("--"), SS("-"), SS("+"), SS("!"), SS("~")}};
return operator_matches;
}
bool is_match(const std::string_view &t_str) const noexcept {
constexpr std::array<std::size_t, 12> groups{{0,1,2,3,4,5,6,7,8,9,10,11}};
return std::any_of(groups.begin(), groups.end(), [&t_str, this](const std::size_t group){ return is_match(group, t_str); });
}
template<typename Predicate>
bool any_of(const std::size_t t_group, Predicate &&predicate) const
{
auto match = [&predicate](const auto &array) {
return std::any_of(array.begin(), array.end(), predicate);
};
static const std::array<Operator_Precidence, 12> &create_operators() {
static const std::array<Operator_Precidence, 12> operators = { {
switch (t_group) {
case 0: return match(m_0);
case 1: return match(m_1);
case 2: return match(m_2);
case 3: return match(m_3);
case 4: return match(m_4);
case 5: return match(m_5);
case 6: return match(m_6);
case 7: return match(m_7);
case 8: return match(m_8);
case 9: return match(m_9);
case 10: return match(m_10);
case 11: return match(m_11);
default: return false;
}
}
constexpr bool is_match(const std::size_t t_group, const std::string_view &t_str) const noexcept {
auto match = [&t_str](const auto &array) {
return std::any_of(array.begin(), array.end(), [&t_str](const auto &v){ return v == t_str; });
};
switch (t_group) {
case 0: return match(m_0);
case 1: return match(m_1);
case 2: return match(m_2);
case 3: return match(m_3);
case 4: return match(m_4);
case 5: return match(m_5);
case 6: return match(m_6);
case 7: return match(m_7);
case 8: return match(m_8);
case 9: return match(m_9);
case 10: return match(m_10);
case 11: return match(m_11);
default: return false;
}
}
};
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,
@ -253,39 +303,12 @@ namespace chaiscript
return operators;
}
static const utility::Static_String &multiline_comment_end()
{
static const utility::Static_String s("*/");
return s;
}
static const utility::Static_String &multiline_comment_begin()
{
static const utility::Static_String s("/*");
return s;
}
static const utility::Static_String &singleline_comment()
{
static const utility::Static_String s("//");
return s;
}
static const utility::Static_String &annotation()
{
static const utility::Static_String s("#");
return s;
}
static const utility::Static_String &cr_lf()
{
static const utility::Static_String s("\r\n");
return s;
}
const std::array<std::array<bool, detail::lengthof_alphabet>, detail::max_alphabet> &m_alphabet = create_alphabet();
const std::vector<std::vector<utility::Static_String>> &m_operator_matches = create_operator_matches();
const std::array<Operator_Precidence, 12> &m_operators = create_operators();
constexpr static utility::Static_String m_multiline_comment_end{"*/"};
constexpr static utility::Static_String m_multiline_comment_begin{"/*"};
constexpr static utility::Static_String m_singleline_comment{"//"};
constexpr static utility::Static_String m_annotation{"#"};
constexpr static utility::Static_String m_cr_lf{"\r\n"};
constexpr static auto m_operators = create_operators();
std::shared_ptr<std::string> m_filename;
std::vector<eval::AST_Node_Impl_Ptr<Tracer>> m_match_stack;
@ -293,22 +316,27 @@ namespace chaiscript
struct Position
{
Position() = default;
constexpr Position() = default;
Position(std::string::const_iterator t_pos, std::string::const_iterator t_end)
constexpr Position(const char * t_pos, const char * t_end) noexcept
: line(1), col(1), m_pos(t_pos), m_end(t_end), m_last_col(1)
{
}
static std::string str(const Position &t_begin, const Position &t_end) {
return std::string(t_begin.m_pos, t_end.m_pos);
static std::string_view str(const Position &t_begin, const Position &t_end) noexcept {
if (t_begin.m_pos != nullptr && t_end.m_pos != nullptr) {
return std::string_view(t_begin.m_pos, std::distance(t_begin.m_pos, t_end.m_pos));
} else {
return {};
}
}
Position &operator++() {
constexpr Position &operator++() noexcept {
if (m_pos != m_end) {
if (*m_pos == '\n') {
++line;
m_last_col = std::exchange(col, 1);
m_last_col = col;
col = 1;
} else {
++col;
}
@ -318,7 +346,7 @@ namespace chaiscript
return *this;
}
Position &operator--() {
constexpr Position &operator--() noexcept {
--m_pos;
if (*m_pos == '\n') {
--line;
@ -329,12 +357,12 @@ namespace chaiscript
return *this;
}
Position &operator+=(size_t t_distance) {
constexpr Position &operator+=(size_t t_distance) noexcept {
*this = (*this) + t_distance;
return *this;
}
Position operator+(size_t t_distance) const {
constexpr Position operator+(size_t t_distance) const noexcept {
Position ret(*this);
for (size_t i = 0; i < t_distance; ++i) {
++ret;
@ -342,12 +370,12 @@ namespace chaiscript
return ret;
}
Position &operator-=(size_t t_distance) {
constexpr Position &operator-=(size_t t_distance) noexcept {
*this = (*this) - t_distance;
return *this;
}
Position operator-(size_t t_distance) const {
constexpr Position operator-(size_t t_distance) const noexcept {
Position ret(*this);
for (size_t i = 0; i < t_distance; ++i) {
--ret;
@ -355,26 +383,25 @@ namespace chaiscript
return ret;
}
bool operator==(const Position &t_rhs) const {
constexpr bool operator==(const Position &t_rhs) const noexcept {
return m_pos == t_rhs.m_pos;
}
bool operator!=(const Position &t_rhs) const {
constexpr bool operator!=(const Position &t_rhs) const noexcept {
return m_pos != t_rhs.m_pos;
}
bool has_more() const {
constexpr bool has_more() const noexcept {
return m_pos != m_end;
}
size_t remaining() const {
return static_cast<size_t>(std::distance(m_pos, m_end));
constexpr size_t remaining() const noexcept {
return static_cast<size_t>(m_end - m_pos);
}
const char& operator*() const {
constexpr const char& operator*() const noexcept {
if (m_pos == m_end) {
static const char ktmp ='\0';
return ktmp;
return ""[0];
} else {
return *m_pos;
}
@ -384,8 +411,8 @@ namespace chaiscript
int col = -1;
private:
std::string::const_iterator m_pos;
std::string::const_iterator m_end;
const char *m_pos = nullptr;
const char *m_end = nullptr;
int m_last_col = -1;
};
@ -394,14 +421,14 @@ namespace chaiscript
Tracer m_tracer;
Optimizer m_optimizer;
void validate_object_name(const std::string &name) const
void validate_object_name(const std::string_view &name) const
{
if (!Name_Validator::valid_object_name(name)) {
throw exception::eval_error("Invalid Object Name: " + name, File_Position(m_position.line, m_position.col), *m_filename);
throw exception::eval_error("Invalid Object Name: " + std::string(name), File_Position(m_position.line, m_position.col), *m_filename);
}
}
public:
public:
explicit ChaiScript_Parser(Tracer tracer = Tracer(), Optimizer optimizer=Optimizer())
: m_tracer(std::move(tracer)),
m_optimizer(std::move(optimizer))
@ -409,12 +436,12 @@ namespace chaiscript
m_match_stack.reserve(2);
}
Tracer &get_tracer()
Tracer &get_tracer() noexcept
{
return m_tracer;
}
Optimizer &get_optimizer()
Optimizer &get_optimizer() noexcept
{
return m_optimizer;
}
@ -424,8 +451,13 @@ namespace chaiscript
ChaiScript_Parser(ChaiScript_Parser &&) = default;
ChaiScript_Parser &operator=(ChaiScript_Parser &&) = delete;
constexpr static auto m_alphabet = build_alphabet();
constexpr static Operator_Matches m_operator_matches{};
/// test a char in an m_alphabet
bool char_in_alphabet(char c, detail::Alphabet a) const { return m_alphabet[a][static_cast<uint8_t>(c)]; }
constexpr bool char_in_alphabet(char c, detail::Alphabet a) const noexcept {
return m_alphabet[a][static_cast<uint8_t>(c)];
}
/// Prints the parsed ast_nodes as a tree
void debug_print(const AST_Node &t, std::string prepend = "") const override {
@ -483,7 +515,7 @@ namespace chaiscript
/// Reads a symbol group from input if it matches the parameter, without skipping initial whitespace
inline auto Symbol_(const utility::Static_String &sym)
inline auto Symbol_(const utility::Static_String &sym) noexcept
{
const auto len = sym.size();
if (m_position.remaining() >= len) {
@ -500,18 +532,18 @@ namespace chaiscript
/// Skips any multi-line or single-line comment
bool SkipComment() {
if (Symbol_(multiline_comment_begin())) {
if (Symbol_(m_multiline_comment_begin)) {
while (m_position.has_more()) {
if (Symbol_(multiline_comment_end())) {
if (Symbol_(m_multiline_comment_end)) {
break;
} else if (!Eol_()) {
++m_position;
}
}
return true;
} else if (Symbol_(singleline_comment())) {
} else if (Symbol_(m_singleline_comment)) {
while (m_position.has_more()) {
if (Symbol_(cr_lf())) {
if (Symbol_(m_cr_lf)) {
m_position -= 2;
break;
} else if (Char_('\n')) {
@ -522,9 +554,9 @@ namespace chaiscript
}
}
return true;
} else if (Symbol_(annotation())) {
} else if (Symbol_(m_annotation)) {
while (m_position.has_more()) {
if (Symbol_(cr_lf())) {
if (Symbol_(m_cr_lf)) {
m_position -= 2;
break;
} else if (Char_('\n')) {
@ -575,7 +607,7 @@ namespace chaiscript
}
/// Reads the optional exponent (scientific notation) and suffix for a Float
bool read_exponent_and_suffix() {
bool read_exponent_and_suffix() noexcept {
// Support a form of scientific notation: 1e-5, 35.5E+8, 0.01e19
if (m_position.has_more() && (std::tolower(*m_position) == 'e')) {
++m_position;
@ -603,7 +635,7 @@ namespace chaiscript
/// Reads a floating point value from input, without skipping initial whitespace
bool Float_() {
bool Float_() noexcept {
if (m_position.has_more() && char_in_alphabet(*m_position,detail::float_alphabet) ) {
while (m_position.has_more() && char_in_alphabet(*m_position,detail::int_alphabet) ) {
++m_position;
@ -631,7 +663,7 @@ namespace chaiscript
}
/// Reads a hex value from input, without skipping initial whitespace
bool Hex_() {
bool Hex_() noexcept {
if (m_position.has_more() && (*m_position == '0')) {
++m_position;
@ -692,7 +724,7 @@ namespace chaiscript
}
/// Parses a floating point value and returns a Boxed_Value representation of it
static Boxed_Value buildFloat(const std::string &t_val)
static Boxed_Value buildFloat(const std::string_view &t_val)
{
bool float_ = false;
bool long_ = false;
@ -725,7 +757,7 @@ namespace chaiscript
static Boxed_Value buildInt(const int base, const std::string &t_val, const bool prefixed)
static Boxed_Value buildInt(const int base, std::string_view t_val, const bool prefixed)
{
bool unsigned_ = false;
bool long_ = false;
@ -752,7 +784,7 @@ namespace chaiscript
}
}
const auto val = prefixed?std::string(t_val.begin()+2,t_val.end()):t_val;
if (prefixed) { t_val.remove_prefix(2); };
#ifdef __GNUC__
#pragma GCC diagnostic push
@ -766,7 +798,8 @@ namespace chaiscript
#endif
try {
auto u = std::stoll(val,nullptr,base);
/// TODO fix this to use from_chars
auto u = std::stoll(std::string(t_val),nullptr,base);
if (!unsigned_ && !long_ && u >= std::numeric_limits<int>::min() && u <= std::numeric_limits<int>::max()) {
@ -789,7 +822,8 @@ namespace chaiscript
} catch (const std::out_of_range &) {
// too big to be signed
try {
auto u = std::stoull(val,nullptr,base);
/// TODO fix this to use from_chars
auto u = std::stoull(std::string(t_val),nullptr,base);
if (!longlong_ && u >= std::numeric_limits<unsigned long>::min() && u <= std::numeric_limits<unsigned long>::max()) {
return const_var(static_cast<unsigned long>(u));
@ -809,9 +843,9 @@ namespace chaiscript
}
template<typename T, typename ... Param>
std::unique_ptr<eval::AST_Node_Impl<Tracer>> make_node(std::string t_match, const int t_prev_line, const int t_prev_col, Param && ...param)
std::unique_ptr<eval::AST_Node_Impl<Tracer>> make_node(std::string_view t_match, const int t_prev_line, const int t_prev_col, Param && ...param)
{
return chaiscript::make_unique<eval::AST_Node_Impl<Tracer>, T>(std::move(t_match), Parse_Location(m_filename, t_prev_line, t_prev_col, m_position.line, m_position.col), std::forward<Param>(param)...);
return chaiscript::make_unique<eval::AST_Node_Impl<Tracer>, T>(std::string(t_match), Parse_Location(m_filename, t_prev_line, t_prev_col, m_position.line, m_position.col), std::forward<Param>(param)...);
}
/// Reads a number from the input, detecting if it's an integer or floating point
@ -824,20 +858,20 @@ namespace chaiscript
if (Hex_()) {
auto match = Position::str(start, m_position);
auto bv = buildInt(16, match, true);
m_match_stack.emplace_back(make_node<eval::Constant_AST_Node<Tracer>>(std::move(match), start.line, start.col, std::move(bv)));
m_match_stack.emplace_back(make_node<eval::Constant_AST_Node<Tracer>>(match, start.line, start.col, std::move(bv)));
return true;
}
if (Binary_()) {
auto match = Position::str(start, m_position);
auto bv = buildInt(2, match, true);
m_match_stack.push_back(make_node<eval::Constant_AST_Node<Tracer>>(std::move(match), start.line, start.col, std::move(bv)));
m_match_stack.push_back(make_node<eval::Constant_AST_Node<Tracer>>(match, start.line, start.col, std::move(bv)));
return true;
}
if (Float_()) {
auto match = Position::str(start, m_position);
auto bv = buildFloat(match);
m_match_stack.push_back(make_node<eval::Constant_AST_Node<Tracer>>(std::move(match), start.line, start.col, std::move(bv)));
m_match_stack.push_back(make_node<eval::Constant_AST_Node<Tracer>>(match, start.line, start.col, std::move(bv)));
return true;
}
else {
@ -845,11 +879,11 @@ namespace chaiscript
auto match = Position::str(start, m_position);
if (!match.empty() && (match[0] == '0')) {
auto bv = buildInt(8, match, false);
m_match_stack.push_back(make_node<eval::Constant_AST_Node<Tracer>>(std::move(match), start.line, start.col, std::move(bv)));
m_match_stack.push_back(make_node<eval::Constant_AST_Node<Tracer>>(match, start.line, start.col, std::move(bv)));
}
else if (!match.empty()) {
auto bv = buildInt(10, match, false);
m_match_stack.push_back(make_node<eval::Constant_AST_Node<Tracer>>(std::move(match), start.line, start.col, std::move(bv)));
m_match_stack.push_back(make_node<eval::Constant_AST_Node<Tracer>>(match, start.line, start.col, std::move(bv)));
} else {
return false;
}
@ -908,7 +942,7 @@ namespace chaiscript
if (Id_()) {
auto text = Position::str(start, m_position);
const auto text_hash = utility::fnv1a_32(text.c_str());
const auto text_hash = utility::hash(text);
if (validate) {
validate_object_name(text);
@ -920,29 +954,29 @@ namespace chaiscript
#endif
switch (text_hash) {
case utility::fnv1a_32("true"): {
m_match_stack.push_back(make_node<eval::Constant_AST_Node<Tracer>>(std::move(text), start.line, start.col, const_var(true)));
case utility::hash("true"): {
m_match_stack.push_back(make_node<eval::Constant_AST_Node<Tracer>>(text, start.line, start.col, const_var(true)));
} break;
case utility::fnv1a_32("false"): {
m_match_stack.push_back(make_node<eval::Constant_AST_Node<Tracer>>(std::move(text), start.line, start.col, const_var(false)));
case utility::hash("false"): {
m_match_stack.push_back(make_node<eval::Constant_AST_Node<Tracer>>(text, start.line, start.col, const_var(false)));
} break;
case utility::fnv1a_32("Infinity"): {
m_match_stack.push_back(make_node<eval::Constant_AST_Node<Tracer>>(std::move(text), start.line, start.col,
case utility::hash("Infinity"): {
m_match_stack.push_back(make_node<eval::Constant_AST_Node<Tracer>>(text, start.line, start.col,
const_var(std::numeric_limits<double>::infinity())));
} break;
case utility::fnv1a_32("NaN"): {
m_match_stack.push_back(make_node<eval::Constant_AST_Node<Tracer>>(std::move(text), start.line, start.col,
case utility::hash("NaN"): {
m_match_stack.push_back(make_node<eval::Constant_AST_Node<Tracer>>(text, start.line, start.col,
const_var(std::numeric_limits<double>::quiet_NaN())));
} break;
case utility::fnv1a_32("__LINE__"): {
m_match_stack.push_back(make_node<eval::Constant_AST_Node<Tracer>>(std::move(text), start.line, start.col,
case utility::hash("__LINE__"): {
m_match_stack.push_back(make_node<eval::Constant_AST_Node<Tracer>>(text, start.line, start.col,
const_var(start.line)));
} break;
case utility::fnv1a_32("__FILE__"): {
m_match_stack.push_back(make_node<eval::Constant_AST_Node<Tracer>>(std::move(text), start.line, start.col,
case utility::hash("__FILE__"): {
m_match_stack.push_back(make_node<eval::Constant_AST_Node<Tracer>>(text, start.line, start.col,
const_var(m_filename)));
} break;
case utility::fnv1a_32("__FUNC__"): {
case utility::hash("__FUNC__"): {
std::string fun_name = "NOT_IN_FUNCTION";
for (size_t idx = m_match_stack.empty() ? 0 : m_match_stack.size() - 1; idx > 0; --idx)
{
@ -952,10 +986,10 @@ namespace chaiscript
}
}
m_match_stack.push_back(make_node<eval::Constant_AST_Node<Tracer>>(std::move(text), start.line, start.col,
m_match_stack.push_back(make_node<eval::Constant_AST_Node<Tracer>>(text, start.line, start.col,
const_var(fun_name)));
} break;
case utility::fnv1a_32("__CLASS__"): {
case utility::hash("__CLASS__"): {
std::string fun_name = "NOT_IN_CLASS";
for (size_t idx = m_match_stack.empty() ? 0 : m_match_stack.size() - 1; idx > 1; --idx)
{
@ -969,15 +1003,16 @@ namespace chaiscript
m_match_stack.push_back(make_node<eval::Constant_AST_Node<Tracer>>(std::move(text), start.line, start.col,
const_var(fun_name)));
} break;
case utility::fnv1a_32("_"): {
case utility::hash("_"): {
m_match_stack.push_back(make_node<eval::Constant_AST_Node<Tracer>>(std::move(text), start.line, start.col,
Boxed_Value(std::make_shared<dispatch::Placeholder_Object>())));
} break;
default: {
std::string val = std::move(text);
auto val = text;
if (*start == '`') {
// 'escaped' literal, like an operator name
val = Position::str(start+1, m_position-1);
// val.remove_prefix(1); val.remove_suffix(1);
}
m_match_stack.push_back(make_node<eval::Id_AST_Node<Tracer>>(val, start.line, start.col));
} break;
@ -1060,7 +1095,7 @@ namespace chaiscript
struct Char_Parser
{
string_type &match;
typedef typename string_type::value_type char_type;
using char_type = typename string_type::value_type;
bool is_escaped = false;
bool is_interpolated = false;
bool saw_interpolation_marker = false;
@ -1456,14 +1491,8 @@ namespace chaiscript
return retval;
}
bool is_operator(const std::string &t_s) const {
return std::any_of(m_operator_matches.begin(), m_operator_matches.end(),
[t_s](const std::vector<utility::Static_String> &opers) {
return std::any_of(opers.begin(), opers.end(),
[t_s](const utility::Static_String &s) {
return t_s == s.c_str();
});
});
bool is_operator(const std::string_view &t_s) const noexcept {
return m_operator_matches.is_match(t_s);
}
/// Reads (and potentially captures) a symbol group from input if it matches the parameter
@ -1490,7 +1519,7 @@ namespace chaiscript
bool Eol_(const bool t_eos = false) {
bool retval = false;
if (m_position.has_more() && (Symbol_(cr_lf()) || Char_('\n'))) {
if (m_position.has_more() && (Symbol_(m_cr_lf) || Char_('\n'))) {
retval = true;
//++m_position.line;
m_position.col = 1;
@ -2381,7 +2410,7 @@ namespace chaiscript
Depth_Counter dc{this};
const auto prev_stack_top = m_match_stack.size();
using SS = utility::Static_String;
constexpr const std::array<utility::Static_String, 6> prefix_opers{{
const std::array<utility::Static_String, 6> prefix_opers{{
SS{"++"},
SS{"--"},
SS{"-"},
@ -2414,16 +2443,19 @@ namespace chaiscript
}
bool Operator_Helper(const size_t t_precedence, std::string &oper) {
Depth_Counter dc{this};
for (auto & elem : m_operator_matches[t_precedence]) {
if (Symbol(elem)) {
oper = elem.c_str();
return true;
}
}
return false;
return m_operator_matches.any_of(t_precedence,
[&oper, this](const auto &elem){
if (Symbol(elem)) {
oper = elem.c_str();
return true;
} else {
return false;
}
}
);
}
bool Operator(const size_t t_precedence = 0) {
Depth_Counter dc{this};
bool retval = false;
@ -2661,7 +2693,9 @@ namespace chaiscript
/// Parses the given input string, tagging parsed ast_nodes with the given m_filename.
AST_NodePtr parse_internal(const std::string &t_input, std::string t_fname) {
m_position = Position(t_input.begin(), t_input.end());
const auto begin = t_input.empty() ? nullptr : &t_input.front();
const auto end = begin == nullptr ? nullptr : begin + t_input.size();
m_position = Position(begin, end);
m_filename = std::make_shared<std::string>(std::move(t_fname));
if ((t_input.size() > 1) && (t_input[0] == '#') && (t_input[1] == '!')) {

View File

@ -49,6 +49,19 @@ 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;
};

View File

@ -14,7 +14,7 @@ namespace chaiscript {
struct Noop_Tracer_Detail
{
template<typename T>
void trace(const chaiscript::detail::Dispatch_State &, const AST_Node_Impl<T> *)
constexpr void trace(const chaiscript::detail::Dispatch_State &, const AST_Node_Impl<T> *) noexcept
{
}
};
@ -23,13 +23,13 @@ namespace chaiscript {
struct Tracer : T...
{
Tracer() = default;
explicit Tracer(T ... t)
constexpr explicit Tracer(T ... t)
: T(std::move(t))...
{
}
void do_trace(const chaiscript::detail::Dispatch_State &ds, const AST_Node_Impl<Tracer<T...>> *node) {
(void)std::initializer_list<int>{ (static_cast<T&>(*this).trace(ds, node), 0)... };
(static_cast<T&>(*this).trace(ds, node), ... );
}
static void trace(const chaiscript::detail::Dispatch_State &ds, const AST_Node_Impl<Tracer<T...>> *node) {

View File

@ -0,0 +1,101 @@
// 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
#ifndef CHAISCRIPT_UTILITY_FNV1A_HPP_
#define CHAISCRIPT_UTILITY_FNV1A_HPP_
#include <cstdint>
#include "../chaiscript_defines.hpp"
namespace chaiscript
{
namespace utility
{
namespace fnv1a {
template<typename Itr>
static constexpr std::uint32_t hash(Itr begin, Itr end) noexcept {
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wsign-conversion"
#endif
#ifdef CHAISCRIPT_MSVC
#pragma warning(push)
#pragma warning(disable : 4307)
#endif
std::uint32_t h = 0x811c9dc5;
while (begin != end) {
h = (h ^ (*begin)) * 0x01000193;
++begin;
}
return h;
#ifdef CHAISCRIPT_MSVC
#pragma warning(pop)
#endif
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
}
template<size_t N>
static constexpr std::uint32_t hash(const char (&str)[N]) noexcept {
return hash(std::begin(str), std::end(str)-1);
}
static constexpr std::uint32_t hash(const std::string_view &sv) noexcept {
return hash(sv.begin(), sv.end());
}
static inline std::uint32_t hash(const std::string &s) noexcept {
return hash(s.begin(), s.end());
}
}
namespace jenkins_one_at_a_time {
template<typename Itr>
static constexpr std::uint32_t hash(Itr begin, Itr end) noexcept {
std::uint32_t hash = 0;
while (begin != end) {
hash += *begin;
hash += hash << 10;
hash ^= hash >> 6;
++begin;
}
hash += hash << 3;
hash ^= hash >> 11;
hash += hash << 15;
return hash;
}
template<size_t N>
static constexpr std::uint32_t hash(const char (&str)[N]) noexcept {
return hash(std::begin(str), std::end(str)-1);
}
static constexpr std::uint32_t hash(const std::string_view &sv) noexcept {
return hash(sv.begin(), sv.end());
}
static inline std::uint32_t hash(const std::string &s) noexcept {
return hash(s.begin(), s.end());
}
}
using fnv1a::hash;
}
}
#endif

View File

@ -3,7 +3,6 @@
//
#pragma once
#ifndef SIMPLEJSON_HPP
#define SIMPLEJSON_HPP
@ -19,7 +18,9 @@
#include <initializer_list>
#include <ostream>
#include <iostream>
#include <variant>
#include "../chaiscript_defines.hpp"
#include "quick_flat_map.hpp"
namespace json {
@ -37,7 +38,7 @@ class JSON
{
public:
enum class Class {
Null,
Null = 0,
Object,
Array,
String,
@ -48,155 +49,97 @@ class JSON
private:
struct QuickFlatMap
using Data = std::variant<std::nullptr_t, chaiscript::utility::QuickFlatMap<std::string, JSON>, std::vector<JSON>, std::string, double, std::int64_t, bool>;
struct Internal
{
auto find(const std::string &s) {
return std::find_if(std::begin(data), std::end(data), [&s](const auto &d) { return d.first == s; });
Internal(std::nullptr_t) : d(nullptr) { }
Internal() : d(nullptr) { }
Internal(Class c) : d(make_type(c)) { }
template<typename T> Internal(T t) : d(std::move(t)) { }
static Data make_type(Class c) {
switch (c) {
case Class::Null: return nullptr;
case Class::Object: return chaiscript::utility::QuickFlatMap<std::string, JSON>{};
case Class::Array: return std::vector<JSON>{};
case Class::String: return std::string{};
case Class::Floating: return double{};
case Class::Integral: return std::int64_t{};
case Class::Boolean: return bool{};
}
throw std::runtime_error("unknown type");
}
auto find(const std::string &s) const {
return std::find_if(std::begin(data), std::end(data), [&s](const auto &d) { return d.first == s; });
}
auto size() const {
return data.size();
}
auto begin() const {
return data.begin();
}
auto end() const {
return data.end();
}
auto begin() {
return data.begin();
}
auto end() {
return data.end();
}
JSON &operator[](const std::string &s) {
const auto itr = find(s);
if (itr != data.end()) {
return itr->second;
} else {
data.emplace_back(s, JSON());
return data.back().second;
void set_type(Class c) {
if (type() != c) {
d = make_type(c);
}
}
JSON &at(const std::string &s) {
const auto itr = find(s);
if (itr != data.end()) {
return itr->second;
Class type() const noexcept {
return Class(d.index());
}
template<auto ClassValue, typename Visitor, typename Or>
decltype(auto) visit_or(Visitor &&visitor, Or &&other) const
{
if (type() == Class(ClassValue)) {
return visitor(std::get<static_cast<std::size_t>(ClassValue)>(d));
} else {
throw std::out_of_range("Unknown key: " + s);
return other();
}
}
const JSON &at(const std::string &s) const {
const auto itr = find(s);
if (itr != data.end()) {
return itr->second;
} else {
throw std::out_of_range("Unknown key: " + s);
}
template<auto ClassValue>
auto &get_set_type() {
set_type(ClassValue);
return std::get<static_cast<std::size_t>(ClassValue)>(d);
}
size_t count(const std::string &s) const {
return (find(s) != data.end())?1:0;
auto &Map() {
return get_set_type<Class::Object>();
}
auto &Vector() {
return get_set_type<Class::Array>();
}
auto &String() {
return get_set_type<Class::String>();
}
auto &Int() {
return get_set_type<Class::Integral>();
}
auto &Float() {
return get_set_type<Class::Floating>();
}
auto &Bool() {
return get_set_type<Class::Boolean>();
}
std::vector<std::pair<std::string, JSON>> data;
using iterator = decltype(data)::iterator;
using const_iterator = decltype(data)::const_iterator;
auto Map() const noexcept {
return std::get_if<static_cast<std::size_t>(Class::Object)>(&d);
}
auto Vector() const noexcept {
return std::get_if<static_cast<std::size_t>(Class::Array)>(&d);
}
auto String() const noexcept {
return std::get_if<static_cast<std::size_t>(Class::String)>(&d);
}
auto Int() const noexcept {
return std::get_if<static_cast<std::size_t>(Class::Integral)>(&d);
}
auto Float() const noexcept {
return std::get_if<static_cast<std::size_t>(Class::Floating)>(&d);
}
auto Bool() const noexcept {
return std::get_if<static_cast<std::size_t>(Class::Boolean)>(&d);
}
Data d;
};
struct Internal {
template<typename T>
auto clone(const std::unique_ptr<T> &ptr) {
if (ptr != nullptr) {
return std::make_unique<T>(*ptr);
} else {
return std::unique_ptr<T>(nullptr);
}
}
Internal( double d ) : Float( d ), Type(Class::Floating) {}
Internal( int64_t l ) : Int( l ), Type(Class::Integral) {}
Internal( bool b ) : Bool( b ), Type(Class::Boolean) {}
Internal( std::string s ) : String(std::make_unique<std::string>(std::move(s))), Type(Class::String) {}
Internal() : Type(Class::Null) {}
Internal(Class t_type) {
set_type(t_type);
}
Internal(const Internal &other)
: List(clone(other.List)),
Map(clone(other.Map)),
String(clone(other.String)),
Float(other.Float),
Int(other.Int),
Bool(other.Bool),
Type(other.Type)
{
}
Internal &operator=(const Internal &other)
{
List = clone(other.List);
Map = clone(other.Map);
String = clone(other.String);
Float = other.Float;
Int = other.Int;
Bool = other.Bool;
Type = other.Type;
return *this;
}
void set_type( Class type ) {
if( type == Type ) {
return;
}
Map.reset();
List.reset();
String.reset();
switch( type ) {
case Class::Object: Map = std::make_unique<QuickFlatMap>(); break;
case Class::Array: List = std::make_unique<std::vector<JSON>>(); break;
case Class::String: String = std::make_unique<std::string>(); break;
case Class::Floating: Float = 0.0; break;
case Class::Integral: Int = 0; break;
case Class::Boolean: Bool = false; break;
case Class::Null: break;
}
Type = type;
}
Internal(Internal &&) = default;
Internal &operator=(Internal &&) = default;
std::unique_ptr<std::vector<JSON>> List;
std::unique_ptr<QuickFlatMap> Map;
std::unique_ptr<std::string> String;
double Float = 0;
int64_t Int = 0;
bool Bool = false;
Class Type = Class::Null;
};
Internal internal;
@ -224,8 +167,8 @@ class JSON
JSONConstWrapper( const Container *val ) : object( val ) {}
JSONConstWrapper( std::nullptr_t ) {}
typename Container::const_iterator begin() const { return object ? object->begin() : typename Container::const_iterator(); }
typename Container::const_iterator end() const { return object ? object->end() : typename Container::const_iterator(); }
typename Container::const_iterator begin() const noexcept { return object ? object->begin() : typename Container::const_iterator(); }
typename Container::const_iterator end() const noexcept { return object ? object->end() : typename Container::const_iterator(); }
};
JSON() = default;
@ -245,13 +188,13 @@ class JSON
}
template <typename T>
explicit JSON( T b, typename enable_if<is_same<T,bool>::value>::type* = nullptr ) : internal( static_cast<bool>(b) ) {}
explicit JSON( T b, typename enable_if<is_same<T,bool>::value>::type* = nullptr ) noexcept : internal( static_cast<bool>(b) ) {}
template <typename T>
explicit JSON( T i, typename enable_if<is_integral<T>::value && !is_same<T,bool>::value>::type* = nullptr ) : internal( static_cast<int64_t>(i) ) {}
explicit JSON( T i, typename enable_if<is_integral<T>::value && !is_same<T,bool>::value>::type* = nullptr ) noexcept : internal( static_cast<std::int64_t>(i) ) {}
template <typename T>
explicit JSON( T f, typename enable_if<is_floating_point<T>::value>::type* = nullptr ) : internal( static_cast<double>(f) ) {}
explicit JSON( T f, typename enable_if<is_floating_point<T>::value>::type* = nullptr ) noexcept : internal( static_cast<double>(f) ) {}
template <typename T>
explicit JSON( T s, typename enable_if<is_convertible<T,std::string>::value>::type* = nullptr ) : internal( static_cast<std::string>(s) ) {}
@ -261,17 +204,16 @@ class JSON
static JSON Load( const std::string & );
JSON& operator[]( const std::string &key ) {
internal.set_type( Class::Object );
return internal.Map->operator[]( key );
return internal.Map().operator[]( key );
}
JSON& operator[]( const size_t index ) {
internal.set_type( Class::Array );
if( index >= internal.List->size() ) {
internal.List->resize( index + 1 );
auto &vec = internal.Vector();
if( index >= vec.size() ) {
vec.resize( index + 1 );
}
return internal.List->operator[]( index );
return vec.operator[]( index );
}
@ -280,7 +222,10 @@ class JSON
}
const JSON &at( const std::string &key ) const {
return internal.Map->at( key );
return internal.visit_or<Class::Object>(
[&](const auto &m)->const JSON &{ return m.at(key); },
[]()->const JSON &{ throw std::range_error("Not an object, no keys"); }
);
}
JSON &at( size_t index ) {
@ -288,100 +233,84 @@ class JSON
}
const JSON &at( size_t index ) const {
return internal.List->at( index );
return internal.visit_or<Class::Array>(
[&](const auto &m)->const JSON&{ return m.at(index); },
[]()->const JSON &{ throw std::range_error("Not an array, no indexes"); }
);
}
auto length() const noexcept {
return internal.visit_or<Class::Array>(
[&](const auto &m){ return static_cast<int>(m.size()); },
[](){ return -1; }
);
}
long length() const {
if( internal.Type == Class::Array ) {
return static_cast<long>(internal.List->size());
bool has_key( const std::string &key ) const noexcept {
return internal.visit_or<Class::Object>(
[&](const auto &m){ return m.count(key) != 0; },
[](){ return false; }
);
}
int size() const noexcept {
if (auto m = internal.Map(); m != nullptr) {
return static_cast<int>(m->size());
} if (auto v = internal.Vector(); v != nullptr) {
return static_cast<int>(v->size());
} else {
return -1;
}
}
bool has_key( const std::string &key ) const {
if( internal.Type == Class::Object ) {
return internal.Map->count(key) != 0;
}
return false;
}
int size() const {
if( internal.Type == Class::Object ) {
return static_cast<int>(internal.Map->size());
} else if( internal.Type == Class::Array ) {
return static_cast<int>(internal.List->size());
} else {
return -1;
}
}
Class JSONType() const { return internal.Type; }
Class JSONType() const noexcept { return internal.type(); }
/// Functions for getting primitives from the JSON object.
bool is_null() const { return internal.Type == Class::Null; }
bool is_null() const noexcept { return internal.type() == Class::Null; }
std::string to_string() const { bool b; return to_string( b ); }
std::string to_string( bool &ok ) const {
ok = (internal.Type == Class::String);
return ok ? *internal.String : std::string("");
std::string to_string() const noexcept {
return internal.visit_or<Class::String>(
[](const auto &o){ return o; },
[](){ return std::string{}; }
);
}
double to_float() const noexcept {
return internal.visit_or<Class::Floating>(
[](const auto &o){ return o; },
[](){ return double{}; }
);
}
std::int64_t to_int() const noexcept {
return internal.visit_or<Class::Integral>(
[](const auto &o){ return o; },
[](){ return std::int64_t{}; }
);
}
bool to_bool() const noexcept {
return internal.visit_or<Class::Boolean>(
[](const auto &o){ return o; },
[](){ return false; }
);
}
double to_float() const { bool b; return to_float( b ); }
double to_float( bool &ok ) const {
ok = (internal.Type == Class::Floating);
return ok ? internal.Float : 0.0;
}
int64_t to_int() const { bool b; return to_int( b ); }
int64_t to_int( bool &ok ) const {
ok = (internal.Type == Class::Integral);
return ok ? internal.Int : 0;
}
bool to_bool() const { bool b; return to_bool( b ); }
bool to_bool( bool &ok ) const {
ok = (internal.Type == Class::Boolean);
return ok ? internal.Bool : false;
}
JSONWrapper<QuickFlatMap> object_range() {
if( internal.Type == Class::Object ) {
return JSONWrapper<QuickFlatMap>( internal.Map.get() );
} else {
return JSONWrapper<QuickFlatMap>( nullptr );
}
JSONWrapper<chaiscript::utility::QuickFlatMap<std::string, JSON>> object_range() {
return std::get_if<static_cast<std::size_t>(Class::Object)>(&internal.d);
}
JSONWrapper<std::vector<JSON>> array_range() {
if( internal.Type == Class::Array ) {
return JSONWrapper<std::vector<JSON>>( internal.List.get() );
} else {
return JSONWrapper<std::vector<JSON>>( nullptr );
}
return std::get_if<static_cast<std::size_t>(Class::Array)>(&internal.d);
}
JSONConstWrapper<QuickFlatMap> object_range() const {
if( internal.Type == Class::Object ) {
return JSONConstWrapper<QuickFlatMap>( internal.Map.get() );
} else {
return JSONConstWrapper<QuickFlatMap>( nullptr );
}
JSONConstWrapper<chaiscript::utility::QuickFlatMap<std::string, JSON>> object_range() const {
return std::get_if<static_cast<std::size_t>(Class::Object)>(&internal.d);
}
JSONConstWrapper<std::vector<JSON>> array_range() const {
if( internal.Type == Class::Array ) {
return JSONConstWrapper<std::vector<JSON>>( internal.List.get() );
} else {
return JSONConstWrapper<std::vector<JSON>>( nullptr );
}
return std::get_if<static_cast<std::size_t>(Class::Array)>(&internal.d);
}
std::string dump( long depth = 1, std::string tab = " ") const {
switch( internal.Type ) {
switch( internal.type() ) {
case Class::Null:
return "null";
case Class::Object: {
@ -390,7 +319,7 @@ class JSON
std::string s = "{\n";
bool skip = true;
for( auto &p : *internal.Map ) {
for( auto &p : *internal.Map() ) {
if( !skip ) { s += ",\n"; }
s += ( pad + "\"" + json_escape(p.first) + "\" : " + p.second.dump( depth + 1, tab ) );
skip = false;
@ -401,7 +330,7 @@ class JSON
case Class::Array: {
std::string s = "[";
bool skip = true;
for( auto &p : *internal.List ) {
for( auto &p : *internal.Vector() ) {
if( !skip ) { s += ", "; }
s += p.dump( depth + 1, tab );
skip = false;
@ -410,13 +339,13 @@ class JSON
return s;
}
case Class::String:
return "\"" + json_escape( *internal.String ) + "\"";
return "\"" + json_escape( *internal.String() ) + "\"";
case Class::Floating:
return std::to_string( internal.Float );
return std::to_string( *internal.Float() );
case Class::Integral:
return std::to_string( internal.Int );
return std::to_string( *internal.Int() );
case Class::Boolean:
return internal.Bool ? "true" : "false";
return *internal.Bool() ? "true" : "false";
}
throw std::runtime_error("Unhandled JSON type");
@ -447,7 +376,7 @@ class JSON
struct JSONParser {
static bool isspace(const char c)
static bool isspace(const char c) noexcept
{
#ifdef CHAISCRIPT_MSVC
// MSVC warns on these line in some circumstances
@ -568,7 +497,7 @@ struct JSONParser {
char c = '\0';
bool isDouble = false;
bool isNegative = false;
int64_t exp = 0;
std::int64_t exp = 0;
bool isExpNegative = false;
if( offset < str.size() && str.at(offset) == '-' ) {
isNegative = true;
@ -606,7 +535,7 @@ struct JSONParser {
break;
}
}
exp = chaiscript::parse_num<int64_t>( exp_str ) * (isExpNegative?-1:1);
exp = chaiscript::parse_num<std::int64_t>( exp_str ) * (isExpNegative?-1:1);
}
else if( offset < str.size() && (!isspace( c ) && c != ',' && c != ']' && c != '}' )) {
throw std::runtime_error(std::string("JSON ERROR: Number: unexpected character '") + c + "'");
@ -617,9 +546,9 @@ struct JSONParser {
return JSON((isNegative?-1:1) * chaiscript::parse_num<double>( val ) * std::pow( 10, exp ));
} else {
if( !exp_str.empty() ) {
return JSON((isNegative?-1:1) * static_cast<double>(chaiscript::parse_num<int64_t>( val )) * std::pow( 10, exp ));
return JSON((isNegative?-1:1) * static_cast<double>(chaiscript::parse_num<std::int64_t>( val )) * std::pow( 10, exp ));
} else {
return JSON((isNegative?-1:1) * chaiscript::parse_num<int64_t>( val ));
return JSON((isNegative?-1:1) * chaiscript::parse_num<std::int64_t>( val ));
}
}
}

View File

@ -0,0 +1,81 @@
#ifndef CHAISCRIPT_UTILITY_QUICK_FLAT_MAP_HPP
#define CHAISCRIPT_UTILITY_QUICK_FLAT_MAP_HPP
namespace chaiscript::utility {
template<typename Key, typename Value>
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; });
}
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; });
}
auto size() const noexcept {
return data.size();
}
auto begin() const noexcept {
return data.begin();
}
auto end() const noexcept {
return data.end();
}
auto begin() noexcept {
return data.begin();
}
auto end() noexcept {
return data.end();
}
Value &operator[](const Key &s) {
const auto itr = find(s);
if (itr != data.end()) {
return itr->second;
} else {
return data.emplace_back(s, Value()).second;
}
}
Value &at(const Key &s) {
const auto itr = find(s);
if (itr != data.end()) {
return itr->second;
} else {
throw std::out_of_range("Unknown key: " + s);
}
}
const Value &at(const Key &s) const {
const auto itr = find(s);
if (itr != data.end()) {
return itr->second;
} else {
throw std::out_of_range("Unknown key: " + s);
}
}
size_t count(const Key &s) const noexcept {
return (find(s) != data.end())?1:0;
}
std::vector<std::pair<Key, Value>> data;
using iterator = typename decltype(data)::iterator;
using const_iterator = typename decltype(data)::const_iterator;
};
}
#endif

View File

@ -15,19 +15,47 @@ namespace chaiscript
struct Static_String
{
template<size_t N>
constexpr Static_String(const char (&str)[N])
constexpr Static_String(const char (&str)[N]) noexcept
: m_size(N-1), data(&str[0])
{
}
constexpr size_t size() const {
constexpr size_t size() const noexcept {
return m_size;
}
constexpr const char *c_str() const {
constexpr const char *c_str() const noexcept {
return data;
}
constexpr auto begin() const noexcept {
return data;
}
constexpr auto end() const noexcept {
return data + m_size;
}
constexpr bool operator==(const std::string_view &other) const noexcept {
//return std::string_view(data, m_size) == other;
auto b1 = begin();
const auto e1 = end();
auto b2 = other.begin();
const auto e2 = other.end();
if (e1 - b1 != e2 - b2) { return false; }
while (b1 != e1) {
if (*b1 != *b2) { return false; }
++b1; ++b2;
}
return true;
}
bool operator==(const std::string &t_str) const noexcept {
return std::equal(begin(), end(), std::cbegin(t_str), std::cend(t_str));
}
const size_t m_size;
const char *data = nullptr;
};

View File

@ -7,7 +7,7 @@ double f(const std::string &, double, bool) noexcept {
int main()
{
chaiscript::ChaiScript chai(chaiscript::Std_Lib::library());
chaiscript::ChaiScript chai;
chai.add(chaiscript::fun(&f), "f");

View File

@ -7,7 +7,7 @@ double f(const std::string &, double, bool) noexcept {
int main()
{
chaiscript::ChaiScript chai(chaiscript::Std_Lib::library());
chaiscript::ChaiScript chai;
chai.add(chaiscript::fun(&f), "f");

View File

@ -12,8 +12,23 @@ class TestBaseType
TestBaseType(int) : val(10), const_val(15), mdarray{} { }
TestBaseType(int *) : val(10), const_val(15), mdarray{} { }
TestBaseType(const TestBaseType &) = default;
virtual ~TestBaseType() {}
TestBaseType(const TestBaseType &other)
: val(other.val), const_val(other.const_val), const_val_ptr(&const_val),
func_member(other.func_member)
{
}
TestBaseType(TestBaseType &&other)
: val(other.val), const_val(other.const_val), const_val_ptr(&const_val),
func_member(std::move(other.func_member))
{
}
TestBaseType &operator=(TestBaseType &&) = delete;
TestBaseType &operator=(const TestBaseType &) = delete;
virtual ~TestBaseType() = default;
virtual int func() { return 0; }
int base_only_func() { return -9; }
@ -36,8 +51,6 @@ class TestBaseType
t_str = "42";
}
private:
TestBaseType &operator=(const TestBaseType &) = delete;
};
class Type2
@ -78,22 +91,14 @@ int to_int(TestEnum t)
class TestDerivedType : public TestBaseType
{
public:
~TestDerivedType() override {}
TestDerivedType(const TestDerivedType &) = default;
TestDerivedType() = default;
virtual int func() override { return 1; }
int derived_only_func() { return 19; }
private:
TestDerivedType &operator=(const TestDerivedType &) = delete;
};
class TestMoreDerivedType : public TestDerivedType
{
public:
TestMoreDerivedType(const TestMoreDerivedType &) = default;
TestMoreDerivedType() = default;
virtual ~TestMoreDerivedType() {}
};
std::shared_ptr<TestBaseType> derived_type_factory()