Compare commits

..

1 Commits

Author SHA1 Message Date
Jason Turner
5c541c3d8e Implement valuetypes with small size optimizations
Reduces trivial types such as int down to 1 dynamic allocation instead
of 3.
2014-10-18 15:58:25 -06:00
64 changed files with 1621 additions and 2557 deletions

View File

@@ -1,25 +1,13 @@
compilers:
- name: "clang"
version: "3.5"
skip_packaging: true
cmake_extra_flags: -DUSE_LIBCXX:BOOL=OFF -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON
- name: "clang"
build_tag: AddressSanitizer
version: "3.5"
skip_packaging: true
cmake_extra_flags: -DUSE_LIBCXX:BOOL=OFF -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DENABLE_ADDRESS_SANITIZER:BOOL=ON
- name: "clang"
build_tag: ThreadSanitizer
version: "3.5"
skip_packaging: true
cmake_extra_flags: -DUSE_LIBCXX:BOOL=OFF -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DENABLE_THREAD_SANITIZER:BOOL=ON
- name: "gcc"
version: "4.8"
cmake_extra_flags: -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DBUILD_TESTING:BOOL=ON
- name: "gcc"
version: "4.6"
skip_packaging: true
cmake_extra_flags: -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON
- name: cppcheck
compiler_extra_flags: --enable=all -I include --inline-suppr -Umax --suppress="*:cmake*"
compiler_extra_flags: --enable=all -I include --inline-suppr

View File

@@ -1,9 +1,7 @@
compilers:
- name: clang
cmake_extra_flags: -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DCOMMIT_SHA=$COMMIT_SHA
build_package_generator: TBZ2
- name: clang
build_type: Debug
cmake_extra_flags: -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DCOMMIT_SHA=$COMMIT_SHA
skip_packaging: true

View File

@@ -2,21 +2,19 @@ compilers:
- name: Visual Studio
version: 14
cmake_extra_flags: -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DCOMMIT_SHA=%COMMIT_SHA%
compiler_extra_flags: /analyze
skip_packaging: true
compiler_extra_flags: /ANALYZE
- name: Visual Studio
version: 14
architecture: Win64
cmake_extra_flags: -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DCOMMIT_SHA=%COMMIT_SHA%
compiler_extra_flags: /analyze
skip_packaging: true
compiler_extra_flags: /ANALYZE
- name: Visual Studio
version: 12
cmake_extra_flags: -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DCOMMIT_SHA=%COMMIT_SHA%
compiler_extra_flags: /analyze
compiler_extra_flags: /ANALYZE
- name: Visual Studio
version: 12
architecture: Win64
cmake_extra_flags: -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DCOMMIT_SHA=%COMMIT_SHA%
compiler_extra_flags: /analyze
compiler_extra_flags: /ANALYZE

View File

@@ -36,38 +36,11 @@ if(CMAKE_COMPILER_IS_GNUCC OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
set(LINKER_FLAGS "${LINKER_FLAGS} -fsanitize=address")
endif()
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")
endif()
option(ENABLE_UNDEFINED_SANITIZER "Enable undefined behavior sanitizer testing in gcc/clang" FALSE)
if(ENABLE_UNDEFINED_SANITIZER)
add_definitions(-fsanitize=undefined -g)
set(LINKER_FLAGS "${LINKER_FLAGS} -fsanitize=undefined")
endif()
option(ENABLE_LTO "Enable Link Time Optimization" FALSE)
if (ENABLE_LTO)
add_definitions(-flto)
set(LINKER_FLAGS "${LINKER_FLAGS} -flto")
endif()
option(PROFILE_GENERATE "Generate profile data" FALSE)
if (PROFILE_GENERATE)
add_definitions(-fprofile-generate)
set(LINKER_FLAGS "${LINKER_FLAGS} -fprofile-generate")
endif()
option(PROFILE_USE "Use profile data" FALSE)
if (PROFILE_USE)
add_definitions(-fprofile-use)
set(LINKER_FLAGS "${LINKER_FLAGS} -fprofile-use")
endif()
endif()
list(APPEND CPACK_SOURCE_IGNORE_FILES "${CMAKE_CURRENT_BINARY_DIR}")
@@ -81,7 +54,7 @@ set(CPACK_RESOURCE_FILE_README "${CMAKE_CURRENT_SOURCE_DIR}/readme.md")
set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/description.txt")
set(CPACK_PACKAGE_VERSION_MAJOR 5)
set(CPACK_PACKAGE_VERSION_MINOR 6)
set(CPACK_PACKAGE_VERSION_MINOR 4)
set(CPACK_PACKAGE_VERSION_PATCH 0)
set(CPACK_PACKAGE_EXECUTABLES "chai;ChaiScript Eval")
@@ -152,13 +125,7 @@ if(MSVC)
# how to workaround or fix the error. So I'm disabling it globally.
add_definitions(/wd4503)
else()
add_definitions(-Wall -Wextra -Wshadow -Wnon-virtual-dtor -Wold-style-cast -Wcast-align -Wcast-qual -Woverloaded-virtual -pedantic ${CPP11_FLAG})
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
add_definitions(-Weverything -Wno-c++98-compat -Wno-documentation -Wno-switch-enum -Wno-weak-vtables -Wno-sign-conversion -Wno-missing-prototypes -Wno-padded -Wno-missing-noreturn)
else()
add_definitions(-Wnoexcept)
endif()
add_definitions(-Wall -Wextra -Wshadow -Wnon-virtual-dtor -pedantic ${CPP11_FLAG})
if(APPLE)
add_definitions(-Wno-sign-compare)
@@ -166,7 +133,7 @@ else()
endif()
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
option(USE_LIBCXX "Use clang's libcxx" TRUE)
option(USE_LIBCXX "Use clang's libcxx" FALSE)
if(USE_LIBCXX)
add_definitions(-stdlib=libc++)
@@ -187,7 +154,7 @@ endif()
include_directories(include)
set(Chai_INCLUDES include/chaiscript/chaiscript.hpp include/chaiscript/chaiscript_threading.hpp include/chaiscript/dispatchkit/bad_boxed_cast.hpp include/chaiscript/dispatchkit/bind_first.hpp include/chaiscript/dispatchkit/bootstrap.hpp include/chaiscript/dispatchkit/bootstrap_stl.hpp include/chaiscript/dispatchkit/boxed_cast.hpp include/chaiscript/dispatchkit/boxed_cast_helper.hpp include/chaiscript/dispatchkit/boxed_number.hpp include/chaiscript/dispatchkit/boxed_value.hpp include/chaiscript/dispatchkit/dispatchkit.hpp include/chaiscript/dispatchkit/type_conversions.hpp include/chaiscript/dispatchkit/dynamic_object.hpp include/chaiscript/dispatchkit/exception_specification.hpp include/chaiscript/dispatchkit/function_call.hpp include/chaiscript/dispatchkit/function_call_detail.hpp include/chaiscript/dispatchkit/handle_return.hpp include/chaiscript/dispatchkit/operators.hpp include/chaiscript/dispatchkit/proxy_constructors.hpp include/chaiscript/dispatchkit/proxy_functions.hpp include/chaiscript/dispatchkit/proxy_functions_detail.hpp include/chaiscript/dispatchkit/register_function.hpp include/chaiscript/dispatchkit/type_info.hpp include/chaiscript/language/chaiscript_algebraic.hpp include/chaiscript/language/chaiscript_common.hpp include/chaiscript/language/chaiscript_engine.hpp include/chaiscript/language/chaiscript_eval.hpp include/chaiscript/language/chaiscript_parser.hpp include/chaiscript/language/chaiscript_prelude.chai include/chaiscript/language/chaiscript_prelude_docs.hpp include/chaiscript/utility/utility.hpp)
set(Chai_INCLUDES include/chaiscript/chaiscript.hpp include/chaiscript/chaiscript_threading.hpp include/chaiscript/dispatchkit/bad_boxed_cast.hpp include/chaiscript/dispatchkit/bind_first.hpp include/chaiscript/dispatchkit/bootstrap.hpp include/chaiscript/dispatchkit/bootstrap_stl.hpp include/chaiscript/dispatchkit/boxed_cast.hpp include/chaiscript/dispatchkit/boxed_cast_helper.hpp include/chaiscript/dispatchkit/boxed_number.hpp include/chaiscript/dispatchkit/boxed_value.hpp include/chaiscript/dispatchkit/dispatchkit.hpp include/chaiscript/dispatchkit/dynamic_cast_conversion.hpp include/chaiscript/dispatchkit/dynamic_object.hpp include/chaiscript/dispatchkit/exception_specification.hpp include/chaiscript/dispatchkit/function_call.hpp include/chaiscript/dispatchkit/function_call_detail.hpp include/chaiscript/dispatchkit/handle_return.hpp include/chaiscript/dispatchkit/operators.hpp include/chaiscript/dispatchkit/proxy_constructors.hpp include/chaiscript/dispatchkit/proxy_functions.hpp include/chaiscript/dispatchkit/proxy_functions_detail.hpp include/chaiscript/dispatchkit/register_function.hpp include/chaiscript/dispatchkit/type_info.hpp include/chaiscript/language/chaiscript_algebraic.hpp include/chaiscript/language/chaiscript_common.hpp include/chaiscript/language/chaiscript_engine.hpp include/chaiscript/language/chaiscript_eval.hpp include/chaiscript/language/chaiscript_parser.hpp include/chaiscript/language/chaiscript_prelude.chai include/chaiscript/language/chaiscript_prelude_docs.hpp include/chaiscript/utility/utility.hpp)
set_source_files_properties(${Chai_INCLUDES} PROPERTIES HEADER_FILE_ONLY TRUE)
@@ -238,8 +205,6 @@ if(BUILD_SAMPLES)
target_link_libraries(memory_leak_test ${LIBS})
add_executable(inheritance samples/inheritance.cpp)
target_link_libraries(inheritance ${LIBS})
add_executable(fun_call_performance samples/fun_call_performance.cpp)
target_link_libraries(fun_call_performance ${LIBS})
endif()
@@ -302,10 +267,6 @@ if(BUILD_TESTING)
target_link_libraries(object_lifetime_test ${LIBS})
add_test(NAME Object_Lifetime_Test COMMAND object_lifetime_test)
add_executable(object_lifetime_test2 unittests/object_lifetime_test2.cpp)
target_link_libraries(object_lifetime_test2 ${LIBS})
add_test(NAME Object_Lifetime_Test2 COMMAND object_lifetime_test2)
add_executable(function_ordering_test unittests/function_ordering_test.cpp)
target_link_libraries(function_ordering_test ${LIBS})
add_test(NAME Function_Ordering_Test COMMAND function_ordering_test)

View File

@@ -40,7 +40,7 @@ PROJECT_NUMBER = ${CHAI_VERSION}
# for a project that appears at the top of each page and should give viewer
# a quick idea about the purpose of the project. Keep the description short.
PROJECT_BRIEF = "An easy to use embedded scripting language for C++."
PROJECT_BRIEF = ${CMAKE_BINARY_DIR}/docs
# With the PROJECT_LOGO tag one can specify an logo or icon that is
# included in the documentation. The maximum height of the logo should not

View File

@@ -1,7 +1,7 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_HPP_

View File

@@ -1,7 +1,7 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_DEFINES_HPP_
@@ -17,7 +17,7 @@
#endif
#if (defined(__GNUC__) && __GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)
/// Currently only g++>=4.8 supports this natively
/// Currently only g++>=4.8supports this natively
/// \todo Make this support other compilers when possible
#define CHAISCRIPT_HAS_THREAD_LOCAL
#endif
@@ -45,7 +45,7 @@
namespace chaiscript {
static const int version_major = 5;
static const int version_minor = 6;
static const int version_minor = 4;
static const int version_patch = 0;
}

View File

@@ -19,11 +19,6 @@
#include "dispatchkit/bootstrap_stl.hpp"
#include "dispatchkit/boxed_value.hpp"
#ifndef CHAISCRIPT_NO_THREADS
#include <future>
#endif
/// @file
///
/// This file generates the standard library that normal ChaiScript usage requires.
@@ -45,11 +40,6 @@ namespace chaiscript
lib->add(standard_library::map_type<std::map<std::string, Boxed_Value> >("Map"));
lib->add(standard_library::pair_type<std::pair<Boxed_Value, Boxed_Value > >("Pair"));
#ifndef CHAISCRIPT_NO_THREADS
lib->add(standard_library::future_type<std::future<chaiscript::Boxed_Value>>("future"));
lib->add(chaiscript::fun<std::future<Boxed_Value> (const std::function<chaiscript::Boxed_Value ()> &)>([](const std::function<chaiscript::Boxed_Value ()> &t_func){ return std::async(std::launch::async, t_func);}), "async");
#endif
return lib;
}

View File

@@ -1,7 +1,7 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_THREADING_HPP_
@@ -82,27 +82,16 @@ namespace chaiscript
t().erase(m_key);
}
inline const T *operator->() const
inline T *operator->() const
{
return &(t()[m_key]);
}
inline const T &operator*() const
inline T &operator*() const
{
return t()[m_key];
}
inline T *operator->()
{
return &(t()[m_key]);
}
inline T &operator*()
{
return t()[m_key];
}
void *m_key;
private:
@@ -128,22 +117,12 @@ namespace chaiscript
{
}
inline const T *operator->() const
inline T *operator->() const
{
return get_tls().get();
}
inline const T &operator*() const
{
return *get_tls();
}
inline T *operator->()
{
return get_tls().get();
}
inline T &operator*()
inline T &operator*() const
{
return *get_tls();
}

View File

@@ -26,8 +26,6 @@ namespace chaiscript {
{
}
bad_any_cast(const bad_any_cast &) = default;
virtual ~bad_any_cast() CHAISCRIPT_NOEXCEPT {}
/// \brief Description of what error occurred
@@ -46,31 +44,20 @@ namespace chaiscript {
private:
struct Data
{
Data(const std::type_info &t_type)
: m_type(t_type)
{
}
Data &operator=(const Data &) = delete;
virtual ~Data() {}
virtual void *data() = 0;
const std::type_info &type() const
{
return m_type;
}
virtual std::unique_ptr<Data> clone() const = 0;
const std::type_info &m_type;
};
template<typename T>
struct Data_Impl : Data
{
explicit Data_Impl(T t_type)
: Data(typeid(T)),
m_data(std::move(t_type))
: m_data(std::move(t_type))
{
}
@@ -92,34 +79,54 @@ namespace chaiscript {
};
std::unique_ptr<Data> m_data;
mutable std::array<uint8_t, 15> m_smallSize;
bool m_isSmall = false;
const std::type_info *m_type = &typeid(void);
public:
// construct/copy/destruct
Any() = default;
Any(const Any &t_any)
{
if (!t_any.empty())
{
m_data = t_any.m_data->clone();
} else {
m_data.reset();
}
: m_data(t_any.m_data?t_any.m_data->clone():nullptr),
m_smallSize(t_any.m_smallSize),
m_isSmall(t_any.m_isSmall),
m_type(t_any.m_type)
{
}
#if !defined(_MSC_VER) || _MSC_VER != 1800
#if _MSC_VER != 1800
Any(Any &&) = default;
Any &operator=(Any &&t_any) = default;
#endif
template<typename ValueType,
typename = typename std::enable_if<!std::is_same<Any, typename std::decay<ValueType>::type>::value>::type>
typename = typename std::enable_if<!std::is_same<Any, typename std::decay<ValueType>::type>::value>::type,
typename = typename std::enable_if< std::is_trivial<typename std::decay<ValueType>::type>::value>::type,
typename = typename std::enable_if<sizeof(typename std::decay<ValueType>::type) <= sizeof(decltype(m_smallSize)) >::type>
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_isSmall(true), m_type(&typeid(typename std::decay<ValueType>::type))
{
m_smallSize.fill(0);
*(static_cast<typename std::decay<ValueType>::type *>(static_cast<void *>(m_smallSize.data()))) = t_value;
// std::cout << "Setting type: " << typeid(typename std::decay<ValueType>::type).name() << " " << t_value << " actual val: " << *(static_cast<typename std::decay<ValueType>::type *>(static_cast<void *>(m_smallSize.data()))) << " cast: " << cast<typename std::decay<ValueType>::type>() << "\n";
}
template<typename ValueType,
typename = typename std::enable_if<!std::is_same<Any, typename std::decay<ValueType>::type>::value>::type,
typename = typename std::enable_if<
!std::is_trivial<typename std::decay<ValueType>::type>::value
|| !(sizeof(typename std::decay<ValueType>::type) <= sizeof(decltype(m_smallSize))) >::type>
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_isSmall(false),
m_type(&typeid(typename std::decay<ValueType>::type))
{
}
Any & operator=(const Any &t_any)
{
Any copy(t_any);
@@ -130,14 +137,20 @@ namespace chaiscript {
template<typename ToType>
ToType &cast() const
{
if (m_data && typeid(ToType) == m_data->type())
if (m_isSmall && typeid(ToType) == *m_type)
{
return *static_cast<ToType *>(static_cast<void *>(m_smallSize.data()));
} else if (!m_isSmall && m_data && typeid(ToType) == *m_type) {
return *static_cast<ToType *>(m_data->data());
} else {
throw chaiscript::detail::exception::bad_any_cast();
}
}
const std::type_info &type() const
{
return *m_type;
}
~Any()
{
@@ -146,25 +159,31 @@ namespace chaiscript {
// modifiers
Any & swap(Any &t_other)
{
std::swap(t_other.m_smallSize, m_smallSize);
std::swap(t_other.m_isSmall, m_isSmall);
std::swap(t_other.m_data, m_data);
std::swap(t_other.m_type, m_type);
return *this;
}
// queries
bool empty() const
{
return !bool(m_data);
return !bool(m_data) && !m_isSmall;
}
const std::type_info & type() const
void *data() const
{
if (m_data)
if (m_isSmall)
{
return m_data->type();
return static_cast<void *>(m_smallSize.data());
} else if (m_data) {
return m_data->data();
} else {
return typeid(void);
return nullptr;
}
}
};
}

View File

@@ -1,7 +1,7 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_BAD_BOXED_CAST_HPP_
@@ -10,7 +10,6 @@
#include <string>
#include <typeinfo>
#include "../chaiscript_defines.hpp"
#include "type_info.hpp"
namespace chaiscript {
@@ -29,14 +28,14 @@ namespace chaiscript
class bad_boxed_cast : public std::bad_cast
{
public:
bad_boxed_cast(Type_Info t_from, const std::type_info &t_to,
bad_boxed_cast(const Type_Info &t_from, const std::type_info &t_to,
std::string t_what) CHAISCRIPT_NOEXCEPT
: from(std::move(t_from)), to(&t_to), m_what(std::move(t_what))
: 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(std::move(t_from)), to(&t_to), m_what("Cannot perform boxed_cast")
bad_boxed_cast(const Type_Info &t_from, const std::type_info &t_to) CHAISCRIPT_NOEXCEPT
: from(t_from), to(&t_to), m_what("Cannot perform boxed_cast")
{
}
@@ -45,8 +44,7 @@ namespace chaiscript
{
}
bad_boxed_cast(const bad_boxed_cast &) = default;
virtual ~bad_boxed_cast() CHAISCRIPT_NOEXCEPT {}
virtual ~bad_boxed_cast() CHAISCRIPT_NOEXCEPT {}
/// \brief Description of what error occurred
virtual const char * what() const CHAISCRIPT_NOEXCEPT CHAISCRIPT_OVERRIDE

View File

@@ -1,7 +1,7 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_BIND_FIRST_HPP_
@@ -18,16 +18,16 @@ namespace chaiscript
{
static std::tuple<decltype(std::placeholders::_1),decltype(std::placeholders::_2),decltype(std::placeholders::_3),decltype(std::placeholders::_4),decltype(std::placeholders::_5),decltype(std::placeholders::_6),decltype(std::placeholders::_7),decltype(std::placeholders::_8),decltype(std::placeholders::_9),decltype(std::placeholders::_10)> placeholder() {
return std::tuple<decltype(std::placeholders::_1),decltype(std::placeholders::_2),decltype(std::placeholders::_3),decltype(std::placeholders::_4),decltype(std::placeholders::_5),decltype(std::placeholders::_6),decltype(std::placeholders::_7),decltype(std::placeholders::_8),decltype(std::placeholders::_9),decltype(std::placeholders::_10)>(std::placeholders::_1,std::placeholders::_2,std::placeholders::_3,std::placeholders::_4,std::placeholders::_5,std::placeholders::_6,std::placeholders::_7,std::placeholders::_8,std::placeholders::_9,std::placeholders::_10);
}
};
};
template<int count, int maxcount, typename Sig>
struct Bind_First
{
template<typename F, typename ... InnerParams>
static std::function<Sig> bind(F&& f, InnerParams ... innerparams)
static std::function<Sig> bind(F f, InnerParams ... innerparams)
{
return Bind_First<count - 1, maxcount, Sig>::bind(std::forward<F>(f), innerparams..., std::get<maxcount - count>(Placeholder::placeholder()));
return Bind_First<count - 1, maxcount, Sig>::bind(f, innerparams..., std::get<maxcount - count>(Placeholder::placeholder()));
}
};
@@ -35,42 +35,37 @@ namespace chaiscript
struct Bind_First<0, maxcount, Sig>
{
template<typename F, typename ... InnerParams>
static std::function<Sig> bind(F&& f, InnerParams ... innerparams)
static std::function<Sig> bind(F f, InnerParams ... innerparams)
{
return std::bind(std::forward<F>(f), innerparams...);
return std::bind(f, innerparams...);
}
};
template<typename O, typename Ret, typename P1, typename ... Param>
std::function<Ret (Param...)> bind_first(Ret (*f)(P1, Param...), O&& o)
std::function<Ret (Param...)> bind_first(Ret (*f)(P1, Param...), O o)
{
return Bind_First<sizeof...(Param), sizeof...(Param), Ret (Param...)>::bind(f, std::forward<O>(o));
return Bind_First<sizeof...(Param), sizeof...(Param), Ret (Param...)>::bind(f, o);
}
template<typename O, typename Ret, typename Class, typename ... Param>
std::function<Ret (Param...)> bind_first(Ret (Class::*f)(Param...), O&& o)
std::function<Ret (Param...)> bind_first(Ret (Class::*f)(Param...), O o)
{
return Bind_First<sizeof...(Param), sizeof...(Param), Ret (Param...)>::bind(f, std::forward<O>(o));
return Bind_First<sizeof...(Param), sizeof...(Param), Ret (Param...)>::bind(f, o);
}
template<typename O, typename Ret, typename Class, typename ... Param>
std::function<Ret (Param...)> bind_first(Ret (Class::*f)(Param...) const, O&& o)
std::function<Ret (Param...)> bind_first(Ret (Class::*f)(Param...) const, O o)
{
return Bind_First<sizeof...(Param), sizeof...(Param), Ret (Param...)>::bind(f, std::forward<O>(o));
return Bind_First<sizeof...(Param), sizeof...(Param), Ret (Param...)>::bind(f, o);
}
template<typename O, typename Ret, typename P1, typename ... Param>
std::function<Ret (Param...)> bind_first(const std::function<Ret (P1, Param...)> &f, O&& o)
std::function<Ret (Param...)> bind_first(const std::function<Ret (P1, Param...)> &f, O o)
{
return Bind_First<sizeof...(Param), sizeof...(Param), Ret (Param...)>::bind(f, std::forward<O>(o));
return Bind_First<sizeof...(Param), sizeof...(Param), Ret (Param...)>::bind(f, o);
}
template<typename O, typename Ret, typename P1, typename ... Param>
std::function<Ret (Param...)> bind_first(std::function<Ret (P1, Param...)> &&f, O&& o)
{
return Bind_First<sizeof...(Param), sizeof...(Param), Ret (Param...)>::bind(std::move(f), std::forward<O>(o));
}
}
}

View File

@@ -1,7 +1,7 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_BOOTSTRAP_HPP_
@@ -24,7 +24,7 @@
#include "boxed_number.hpp"
#include "boxed_value.hpp"
#include "dispatchkit.hpp"
#include "type_conversions.hpp"
#include "dynamic_cast_conversion.hpp"
#include "dynamic_object.hpp"
#include "operators.hpp"
#include "proxy_constructors.hpp"
@@ -156,7 +156,9 @@ namespace chaiscript
return p;
}
/// Specific version of shared_ptr_clone just for Proxy_Functions
/**
* Specific version of shared_ptr_clone just for Proxy_Functions
*/
template<typename Type>
std::shared_ptr<typename std::remove_const<Type>::type>
shared_ptr_unconst_clone(const std::shared_ptr<typename std::add_const<Type>::type> &p)
@@ -166,9 +168,11 @@ namespace chaiscript
/// Assignment function for shared_ptr objects, does not perform a copy of the
/// object pointed to, instead maintains the shared_ptr concept.
/// Similar to shared_ptr_clone. Used for Proxy_Function.
/**
* Assignment function for shared_ptr objects, does not perform a copy of the
* object pointed to, instead maintains the shared_ptr concept.
* Similar to shared_ptr_clone. Used for Proxy_Function.
*/
template<typename Type>
Boxed_Value ptr_assign(Boxed_Value lhs, const std::shared_ptr<Type> &rhs)
{
@@ -182,8 +186,10 @@ namespace chaiscript
}
}
/// Class consisting of only static functions. All default bootstrapping occurs
/// from this class.
/**
* Class consisting of only static functions. All default bootstrapping occurs
* from this class.
*/
class Bootstrap
{
private:
@@ -202,16 +208,18 @@ namespace chaiscript
static void print(const std::string &s)
{
fwrite(s.c_str(), 1, s.size(), stdout);
std::cout << s;
}
static void println(const std::string &s)
{
puts(s.c_str());
std::cout << s << std::endl;
}
/// Add all arithmetic operators for PODs
/**
* Add all arithmetic operators for PODs
*/
static void opers_arithmetic_pod(ModulePtr m = ModulePtr(new Module()))
{
m->add(fun(&Boxed_Number::equals), "==");
@@ -251,8 +259,11 @@ namespace chaiscript
}
/// Create a bound function object. The first param is the function to bind
/// the remaining parameters are the args to bind into the result
/**
* Create a bound function object. The first param is the function to bind
* the remaining parameters are the args to bind into the
* result
*/
static Boxed_Value bind_function(const std::vector<Boxed_Value> &params)
{
if (params.size() < 2)
@@ -262,7 +273,7 @@ namespace chaiscript
Const_Proxy_Function f = boxed_cast<Const_Proxy_Function>(params[0]);
return Boxed_Value(Const_Proxy_Function(std::make_shared<dispatch::Bound_Function>(f,
return Boxed_Value(Const_Proxy_Function(new dispatch::Bound_Function(f,
std::vector<Boxed_Value>(params.begin() + 1, params.end()))));
}
@@ -307,7 +318,9 @@ namespace chaiscript
return e.what();
}
/// Boolean specialization of internal to_string function
/**
* Boolean specialization of internal to_string function
*/
static std::string bool_to_string(bool b)
{
if (b)
@@ -337,7 +350,9 @@ namespace chaiscript
static bool has_parse_tree(const chaiscript::Const_Proxy_Function &t_pf)
{
if (auto pf = std::dynamic_pointer_cast<const chaiscript::dispatch::Dynamic_Proxy_Function>(t_pf))
std::shared_ptr<const chaiscript::dispatch::Dynamic_Proxy_Function> pf
= std::dynamic_pointer_cast<const chaiscript::dispatch::Dynamic_Proxy_Function>(t_pf);
if (pf)
{
if (pf->get_parse_tree())
{
@@ -352,7 +367,9 @@ namespace chaiscript
static chaiscript::AST_NodePtr get_parse_tree(const chaiscript::Const_Proxy_Function &t_pf)
{
if (auto pf = std::dynamic_pointer_cast<const chaiscript::dispatch::Dynamic_Proxy_Function>(t_pf))
std::shared_ptr<const chaiscript::dispatch::Dynamic_Proxy_Function> pf
= std::dynamic_pointer_cast<const chaiscript::dispatch::Dynamic_Proxy_Function>(t_pf);
if (pf)
{
if (pf->get_parse_tree())
{
@@ -396,9 +413,10 @@ namespace chaiscript
m->add(user_type<std::runtime_error>(), "runtime_error");
m->add(chaiscript::base_class<std::exception, std::runtime_error>());
m->add(constructor<std::runtime_error (const std::string &)>(), "runtime_error");
m->add(fun(std::function<std::string (const std::runtime_error &)>(&what)), "what");
m->add(fun(std::function<std::string (const std::runtime_error &)>(&what)), "what");
m->add(user_type<dispatch::Dynamic_Object>(), "Dynamic_Object");
m->add(constructor<dispatch::Dynamic_Object (const std::string &)>(), "Dynamic_Object");
@@ -442,7 +460,7 @@ namespace chaiscript
operators::assign<bool>(m);
operators::equal<bool>(m);
m->add(fun<std::string (const std::string &t_ss)>([](const std::string &s) -> std::string { return s; }), "to_string");
m->add(fun(&to_string<const std::string &>), "to_string");
m->add(fun(&Bootstrap::bool_to_string), "to_string");
m->add(fun(&unknown_assign), "=");
m->add(fun(&throw_exception), "throw");
@@ -486,12 +504,7 @@ namespace chaiscript
m->add(chaiscript::fun(&has_parse_tree), "has_parse_tree");
m->add(chaiscript::fun(&get_parse_tree), "get_parse_tree");
m->add(chaiscript::user_type<chaiscript::exception::eval_error>(), "eval_error");
m->add(chaiscript::base_class<std::runtime_error, chaiscript::exception::eval_error>());
m->add(chaiscript::user_type<chaiscript::exception::arithmetic_error>(), "arithmetic_error");
m->add(chaiscript::base_class<std::runtime_error, chaiscript::exception::arithmetic_error>());
m->add(chaiscript::base_class<std::exception, chaiscript::exception::eval_error>());
// chaiscript::bootstrap::standard_library::vector_type<std::vector<std::shared_ptr<chaiscript::AST_Node> > >("AST_NodeVector", m);

View File

@@ -1,7 +1,7 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
/// \file
@@ -246,7 +246,6 @@ namespace chaiscript
template<typename ContainerType>
ModulePtr random_access_container_type(const std::string &/*type*/, ModulePtr m = ModulePtr(new Module()))
{
// cppcheck-suppress syntaxError
typedef typename ContainerType::reference(ContainerType::*indexoper)(size_t);
typedef typename ContainerType::const_reference(ContainerType::*constindexoper)(size_t) const;
@@ -279,9 +278,9 @@ namespace chaiscript
template<typename ContainerType>
ModulePtr container_type(const std::string &/*type*/, ModulePtr m = ModulePtr(new Module()))
{
m->add(fun<size_t (const ContainerType *)>([](const ContainerType *a) { return a->size(); } ), "size");
m->add(fun<bool (const ContainerType *)>([](const ContainerType *a) { return a->empty(); } ), "empty");
m->add(fun<void (ContainerType *)>([](ContainerType *a) { a->clear(); } ), "clear");
m->add(fun( std::function<size_t (const ContainerType *)>( [](const ContainerType *a) { return a->size(); } ) ), "size");
m->add(fun( std::function<bool (const ContainerType *)>( [](const ContainerType *a) { return a->empty(); } ) ), "empty");
m->add(fun( std::function<void (ContainerType *)>( [](ContainerType *a) { a->clear(); } ) ), "clear");
return m;
}
@@ -494,26 +493,24 @@ namespace chaiscript
if (typeid(VectorType) == typeid(std::vector<Boxed_Value>))
{
m->eval(R"(
def Vector::`==`(rhs) : type_match(rhs, this) {
if ( rhs.size() != this.size() ) {
return false;
} else {
auto r1 = range(this);
auto r2 = range(rhs);
while (!r1.empty())
{
if (!eq(r1.front(), r2.front()))
{
return false;
}
r1.pop_front();
r2.pop_front();
}
true;
}
} )"
);
m->eval("def Vector::`==`(rhs) : type_match(rhs, this) { \
if ( rhs.size() != this.size() ) { \
return false; \
} else { \
auto r1 = range(this); \
auto r2 = range(rhs); \
while (!r1.empty()) \
{ \
if (!eq(r1.front(), r2.front())) \
{ \
return false; \
} \
r1.pop_front(); \
r2.pop_front(); \
} \
return true; \
} \
}");
}
return m;
@@ -565,25 +562,6 @@ namespace chaiscript
return m;
}
/// Add a MapType container
/// http://www.sgi.com/tech/stl/Map.html
template<typename FutureType>
ModulePtr future_type(const std::string &type, ModulePtr m = ModulePtr(new Module()))
{
m->add(user_type<FutureType>(), type);
m->add(fun<bool (const FutureType &)>([](const FutureType &t) { return t.valid(); }), "valid");
m->add(fun(&FutureType::get), "get");
m->add(fun(&FutureType::wait), "wait");
return m;
}
}
}
}

View File

@@ -1,7 +1,7 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_BOXED_CAST_HPP_
@@ -14,11 +14,11 @@
#include "bad_boxed_cast.hpp"
#include "boxed_cast_helper.hpp"
#include "boxed_value.hpp"
#include "type_conversions.hpp"
#include "dynamic_cast_conversion.hpp"
#include "type_info.hpp"
namespace chaiscript {
class Type_Conversions;
class Dynamic_Cast_Conversions;
namespace detail {
namespace exception {
class bad_any_cast;
@@ -72,7 +72,7 @@ namespace chaiscript
/// assert(i == 5);
/// \endcode
template<typename Type>
typename detail::Cast_Helper<Type>::Result_Type boxed_cast(const Boxed_Value &bv, const Type_Conversions *t_conversions = nullptr)
typename detail::Cast_Helper<Type>::Result_Type boxed_cast(const Boxed_Value &bv, const Dynamic_Cast_Conversions *t_conversions = nullptr)
{
try {
return detail::Cast_Helper<Type>::cast(bv, t_conversions);
@@ -86,18 +86,18 @@ namespace chaiscript
#pragma warning(disable : 4127)
#endif
if (t_conversions && t_conversions->convertable_type<Type>())
if (std::is_polymorphic<typename detail::Bare_Type<Type>::type>::value && t_conversions)
{
try {
// std::cout << "trying an up conversion " << typeid(Type).name() << '\n';
// std::cout << "trying an up conversion " << typeid(Type).name() << std::endl;
// We will not catch any bad_boxed_dynamic_cast that is thrown, let the user get it
// either way, we are not responsible if it doesn't work
return detail::Cast_Helper<Type>::cast(t_conversions->boxed_type_conversion<Type>(bv), t_conversions);
return detail::Cast_Helper<Type>::cast(t_conversions->boxed_dynamic_cast<Type>(bv), t_conversions);
} catch (...) {
try {
// std::cout << "trying a down conversion " << typeid(Type).name() << '\n';
// std::cout << "trying a down conversion " << typeid(Type).name() << std::endl;
// try going the other way - down the inheritance graph
return detail::Cast_Helper<Type>::cast(t_conversions->boxed_type_down_conversion<Type>(bv), t_conversions);
return detail::Cast_Helper<Type>::cast(t_conversions->boxed_dynamic_down_cast<Type>(bv), t_conversions);
} catch (const chaiscript::detail::exception::bad_any_cast &) {
throw exception::bad_boxed_cast(bv.get_type_info(), typeid(Type));
}

View File

@@ -1,7 +1,7 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_BOXED_CAST_HELPER_HPP_
@@ -17,7 +17,7 @@
namespace chaiscript
{
class Type_Conversions;
class Dynamic_Cast_Conversions;
namespace detail
{
@@ -36,7 +36,7 @@ namespace chaiscript
{
typedef typename std::reference_wrapper<typename std::add_const<Result>::type > Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *)
static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *)
{
if (ob.get_type_info().bare_equal_type_info(typeid(Result)))
{
@@ -63,7 +63,7 @@ namespace chaiscript
struct Cast_Helper_Inner<const Result *>
{
typedef const Result * Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *)
static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *)
{
if (ob.is_ref())
{
@@ -89,7 +89,7 @@ namespace chaiscript
struct Cast_Helper_Inner<Result *>
{
typedef Result * Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *)
static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *)
{
if (ob.is_ref())
{
@@ -107,7 +107,7 @@ namespace chaiscript
{
typedef Result& Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *)
static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *)
{
if (!ob.get_type_info().is_const() && ob.get_type_info().bare_equal_type_info(typeid(Result)))
{
@@ -124,7 +124,7 @@ namespace chaiscript
{
typedef typename std::shared_ptr<Result> Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *)
static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *)
{
return ob.get().cast<std::shared_ptr<Result> >();
}
@@ -136,7 +136,7 @@ namespace chaiscript
{
typedef typename std::shared_ptr<const Result> Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *)
static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *)
{
if (!ob.get_type_info().is_const())
{
@@ -178,7 +178,7 @@ namespace chaiscript
{
typedef const Boxed_Value & Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *)
static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *)
{
return ob;
}
@@ -190,7 +190,7 @@ namespace chaiscript
{
typedef Boxed_Value& Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *)
static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *)
{
return const_cast<Boxed_Value &>(ob);
}
@@ -246,7 +246,7 @@ namespace chaiscript
{
typedef typename Cast_Helper_Inner<T>::Result_Type Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *t_conversions)
static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *t_conversions)
{
return Cast_Helper_Inner<T>::cast(ob, t_conversions);
}

View File

@@ -1,7 +1,7 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_BOXED_NUMERIC_HPP_
@@ -19,22 +19,9 @@
#include "type_info.hpp"
namespace chaiscript {
class Type_Conversions;
class Dynamic_Cast_Conversions;
} // namespace chaiscript
namespace chaiscript
{
namespace exception
{
struct arithmetic_error : public std::runtime_error
{
arithmetic_error(const std::string& reason) : std::runtime_error("Arithmetic error: " + reason) {}
arithmetic_error(const arithmetic_error &) = default;
virtual ~arithmetic_error() CHAISCRIPT_NOEXCEPT {}
};
}
}
namespace chaiscript
{
@@ -46,37 +33,16 @@ namespace chaiscript
#pragma warning(disable : 4244 4018 4389 4146 4365)
#endif
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wsign-compare"
#pragma GCC diagnostic ignored "-Wfloat-equal"
#pragma GCC diagnostic ignored "-Wconversion"
#pragma GCC diagnostic ignored "-Wsign-conversion"
#endif
/// \brief Represents any numeric type, generically. Used internally for generic operations between POD values
class Boxed_Number
{
private:
template<typename T>
static void check_divide_by_zero(T t, typename std::enable_if<std::is_integral<T>::value>::type* = 0)
{
#ifndef CHAISCRIPT_NO_PROTECT_DIVIDEBYZERO
if (t == 0) {
throw chaiscript::exception::arithmetic_error("divide by zero");
}
#endif
}
template<typename T>
static void check_divide_by_zero(T, typename std::enable_if<std::is_floating_point<T>::value>::type* = 0)
{
}
struct boolean
{
#ifdef __GNUC__
#pragma GCC diagnostic ignored "-Wsign-compare"
#endif
template<typename T, typename U>
static Boxed_Value go(Operators::Opers t_oper, const T &t, const U &u, const Boxed_Value &)
{
@@ -95,7 +61,7 @@ namespace chaiscript
case Operators::not_equal:
return const_var(t != u);
default:
throw chaiscript::detail::exception::bad_any_cast();
throw chaiscript::detail::exception::bad_any_cast();
}
}
};
@@ -123,14 +89,13 @@ namespace chaiscript
t += u;
break;
case Operators::assign_quotient:
check_divide_by_zero(u);
t /= u;
break;
case Operators::assign_difference:
t -= u;
break;
default:
throw chaiscript::detail::exception::bad_any_cast();
throw chaiscript::detail::exception::bad_any_cast();
}
return t_lhs;
@@ -157,14 +122,13 @@ namespace chaiscript
t >>= u;
break;
case Operators::assign_remainder:
check_divide_by_zero(u);
t %= u;
break;
case Operators::assign_bitwise_xor:
t ^= u;
break;
default:
throw chaiscript::detail::exception::bad_any_cast();
throw chaiscript::detail::exception::bad_any_cast();
}
return t_lhs;
}
@@ -182,7 +146,6 @@ namespace chaiscript
case Operators::shift_right:
return const_var(t >> u);
case Operators::remainder:
check_divide_by_zero(u);
return const_var(t % u);
case Operators::bitwise_and:
return const_var(t & u);
@@ -193,7 +156,7 @@ namespace chaiscript
case Operators::bitwise_complement:
return const_var(~t);
default:
throw chaiscript::detail::exception::bad_any_cast();
throw chaiscript::detail::exception::bad_any_cast();
}
}
};
@@ -208,7 +171,6 @@ namespace chaiscript
case Operators::sum:
return const_var(t + u);
case Operators::quotient:
check_divide_by_zero(u);
return const_var(t / u);
case Operators::product:
return const_var(t * u);
@@ -219,7 +181,7 @@ namespace chaiscript
case Operators::unary_plus:
return const_var(+t);
default:
throw chaiscript::detail::exception::bad_any_cast();
throw chaiscript::detail::exception::bad_any_cast();
}
}
};
@@ -365,6 +327,7 @@ namespace chaiscript
return oss.str();
}
public:
Boxed_Number()
: bv(Boxed_Value(0))
@@ -377,13 +340,6 @@ namespace chaiscript
validate_boxed_number(bv);
}
Boxed_Number(const Boxed_Number &) = default;
#if !defined(_MSC_VER) || _MSC_VER != 1800
Boxed_Number(Boxed_Number &&) = default;
Boxed_Number& operator=(Boxed_Number &&) = default;
#endif
template<typename T> explicit Boxed_Number(T t)
: bv(Boxed_Value(t))
{
@@ -591,7 +547,6 @@ namespace chaiscript
}
}
// cppcheck-suppress operatorEq
Boxed_Number operator=(const Boxed_Value &v)
{
validate_boxed_number(v);
@@ -599,7 +554,6 @@ namespace chaiscript
return *this;
}
// cppcheck-suppress operatorEq
Boxed_Number operator=(const Boxed_Number &t_rhs) const
{
return oper(Operators::assign, this->bv, t_rhs.bv);
@@ -872,35 +826,37 @@ namespace chaiscript
namespace detail
{
/// Cast_Helper for converting from Boxed_Value to Boxed_Number
/**
* Cast_Helper for converting from Boxed_Value to Boxed_Number
*/
template<>
struct Cast_Helper<Boxed_Number>
{
typedef Boxed_Number Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *)
static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *)
{
return Boxed_Number(ob);
}
};
/// Cast_Helper for converting from Boxed_Value to Boxed_Number
/**
* Cast_Helper for converting from Boxed_Value to Boxed_Number
*/
template<>
struct Cast_Helper<const Boxed_Number &> : Cast_Helper<Boxed_Number>
{
};
/// Cast_Helper for converting from Boxed_Value to Boxed_Number
/**
* Cast_Helper for converting from Boxed_Value to Boxed_Number
*/
template<>
struct Cast_Helper<const Boxed_Number> : Cast_Helper<Boxed_Number>
{
};
};
}
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
#ifdef CHAISCRIPT_MSVC
#pragma warning(pop)
#endif

View File

@@ -1,7 +1,7 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_BOXED_VALUE_HPP_
@@ -13,7 +13,6 @@
#include <type_traits>
#include "../chaiscript_threading.hpp"
#include "../chaiscript_defines.hpp"
#include "any.hpp"
#include "type_info.hpp"
@@ -67,18 +66,17 @@ namespace chaiscript
Data &operator=(Data &&rhs) = default;
#endif
Type_Info m_type_info;
chaiscript::detail::Any m_obj;
void *m_data_ptr;
const void *m_const_data_ptr;
std::unique_ptr<std::map<std::string, Boxed_Value>> m_attrs;
bool m_is_ref;
std::unique_ptr<std::map<std::string, Boxed_Value>> m_attrs;
};
struct Object_Data
{
static std::shared_ptr<Data> get(Boxed_Value::Void_Type)
static std::shared_ptr<Data> get(Boxed_Value::Void_Type, bool, bool)
{
return std::make_shared<Data>(
detail::Get_Type_Info<void>::get(),
@@ -89,13 +87,13 @@ namespace chaiscript
}
template<typename T>
static std::shared_ptr<Data> get(const std::shared_ptr<T> *obj)
static std::shared_ptr<Data> get(const std::shared_ptr<T> *obj, bool, bool)
{
return get(*obj);
}
template<typename T>
static std::shared_ptr<Data> get(const std::shared_ptr<T> &obj)
static std::shared_ptr<Data> get(const std::shared_ptr<T> &obj, bool, bool)
{
return std::make_shared<Data>(
detail::Get_Type_Info<T>::get(),
@@ -106,7 +104,7 @@ namespace chaiscript
}
template<typename T>
static std::shared_ptr<Data> get(std::shared_ptr<T> &&obj)
static std::shared_ptr<Data> get(std::shared_ptr<T> &&obj, bool, bool)
{
auto ptr = obj.get();
return std::make_shared<Data>(
@@ -124,14 +122,7 @@ namespace chaiscript
}
template<typename T>
static std::shared_ptr<Data> get(const T *t)
{
return get(std::cref(*t));
}
template<typename T>
static std::shared_ptr<Data> get(std::reference_wrapper<T> obj)
static std::shared_ptr<Data> get(std::reference_wrapper<T> obj, bool, bool)
{
auto p = &obj.get();
return std::make_shared<Data>(
@@ -143,22 +134,57 @@ namespace chaiscript
}
template<typename T>
static std::shared_ptr<Data> get(T t)
static std::shared_ptr<Data> get(T t, bool t_value_type, bool t_make_const)
{
auto p = std::make_shared<T>(std::move(t));
auto ptr = p.get();
return std::make_shared<Data>(
detail::Get_Type_Info<T>::get(),
chaiscript::detail::Any(std::move(p)),
false,
ptr
);
typedef typename std::add_const<T>::type const_type;
if (t_make_const)
{
if (t_value_type)
{
chaiscript::detail::Any a(std::move(t));
return std::make_shared<Data>(
detail::Get_Type_Info<const_type>::get(),
std::move(a),
false,
nullptr
);
} else {
auto p = std::make_shared<const_type>(std::move(t));
auto ptr = p.get();
return std::make_shared<Data>(
detail::Get_Type_Info<const_type>::get(),
chaiscript::detail::Any(std::move(p)),
false,
ptr
);
}
} else {
if (t_value_type)
{
chaiscript::detail::Any a(std::move(t));
return std::make_shared<Data>(
detail::Get_Type_Info<T>::get(),
std::move(a),
false,
nullptr
);
} else {
auto p = std::make_shared<T>(std::move(t));
auto ptr = p.get();
return std::make_shared<Data>(
detail::Get_Type_Info<T>::get(),
chaiscript::detail::Any(std::move(p)),
false,
ptr
);
}
}
}
static std::shared_ptr<Data> get()
{
return std::make_shared<Data>(
Type_Info(),
Type_Info(),
chaiscript::detail::Any(),
false,
nullptr
@@ -171,9 +197,10 @@ namespace chaiscript
/// Basic Boxed_Value constructor
template<typename T,
typename = typename std::enable_if<!std::is_same<Boxed_Value, typename std::decay<T>::type>::value>::type>
explicit Boxed_Value(T &&t)
: m_data(Object_Data::get(std::forward<T>(t)))
explicit Boxed_Value(T &&t, bool t_make_const=false, bool t_value_type = std::is_trivial<typename std::decay<T>::type>::value)
: m_data(Object_Data::get(std::forward<T>(t), t_make_const, t_value_type))
{
//std::cout << "typeid: " << typeid(T).name() << " is trivial " << std::is_trivial<typename std::decay<T>::type>::value << "\n";
}
/// Unknown-type constructor
@@ -246,12 +273,22 @@ namespace chaiscript
void *get_ptr() const CHAISCRIPT_NOEXCEPT
{
return m_data->m_data_ptr;
if (m_data->m_data_ptr)
{
return m_data->m_data_ptr;
} else {
return m_data->m_obj.data();
}
}
const void *get_const_ptr() const CHAISCRIPT_NOEXCEPT
{
return m_data->m_const_data_ptr;
if (m_data->m_const_data_ptr)
{
return m_data->m_const_data_ptr;
} else {
return m_data->m_obj.data();
}
}
Boxed_Value get_attr(const std::string &t_name)
@@ -312,7 +349,7 @@ namespace chaiscript
template<typename T>
Boxed_Value const_var_impl(const T &t)
{
return Boxed_Value(std::make_shared<typename std::add_const<T>::type >(t));
return Boxed_Value(std::make_shared<typename std::add_const<T>::type >(t), true);
}
/// \brief Takes a pointer to a value, adds const to the pointed to type and returns an immutable Boxed_Value.

View File

@@ -1,7 +1,7 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_DISPATCHKIT_HPP_
@@ -27,7 +27,7 @@
#include "boxed_cast.hpp"
#include "boxed_cast_helper.hpp"
#include "boxed_value.hpp"
#include "type_conversions.hpp"
#include "dynamic_cast_conversion.hpp"
#include "dynamic_object.hpp"
#include "proxy_constructors.hpp"
#include "proxy_functions.hpp"
@@ -62,8 +62,6 @@ namespace chaiscript
{
}
reserved_word_error(const reserved_word_error &) = default;
virtual ~reserved_word_error() CHAISCRIPT_NOEXCEPT {}
std::string word() const
@@ -84,8 +82,6 @@ namespace chaiscript
{
}
illegal_name_error(const illegal_name_error &) = default;
virtual ~illegal_name_error() CHAISCRIPT_NOEXCEPT {}
std::string name() const
@@ -107,8 +103,6 @@ namespace chaiscript
{
}
name_conflict_error(const name_conflict_error &) = default;
virtual ~name_conflict_error() CHAISCRIPT_NOEXCEPT {}
std::string name() const
@@ -131,7 +125,6 @@ namespace chaiscript
{
}
global_non_const(const global_non_const &) = default;
virtual ~global_non_const() CHAISCRIPT_NOEXCEPT {}
};
}
@@ -148,7 +141,7 @@ namespace chaiscript
return *this;
}
Module &add(Type_Conversion d)
Module &add(Dynamic_Cast_Conversion d)
{
m_conversions.push_back(std::move(d));
return *this;
@@ -164,7 +157,7 @@ namespace chaiscript
{
if (!t_bv.is_const())
{
throw chaiscript::exception::global_non_const();
// throw chaiscript::exception::global_non_const();
}
m_globals.emplace_back(std::move(t_bv), std::move(t_name));
@@ -173,9 +166,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;
}
@@ -204,7 +197,7 @@ namespace chaiscript
std::vector<std::pair<Proxy_Function, std::string> > m_funcs;
std::vector<std::pair<Boxed_Value, std::string> > m_globals;
std::vector<std::string> m_evals;
std::vector<Type_Conversion> m_conversions;
std::vector<Dynamic_Cast_Conversion> m_conversions;
template<typename T, typename InItr>
static void apply(InItr begin, const InItr end, T &t)
@@ -264,7 +257,7 @@ namespace chaiscript
{
public:
Dispatch_Function(std::vector<Proxy_Function> t_funcs)
: Proxy_Function_Base(build_type_infos(t_funcs), calculate_arity(t_funcs)),
: Proxy_Function_Base(build_type_infos(t_funcs)),
m_funcs(std::move(t_funcs))
{
}
@@ -272,7 +265,7 @@ namespace chaiscript
virtual bool operator==(const dispatch::Proxy_Function_Base &rhs) const CHAISCRIPT_OVERRIDE
{
try {
const auto &dispatchfun = dynamic_cast<const Dispatch_Function &>(rhs);
const Dispatch_Function &dispatchfun = dynamic_cast<const Dispatch_Function &>(rhs);
return m_funcs == dispatchfun.m_funcs;
} catch (const std::bad_cast &) {
return false;
@@ -287,15 +280,15 @@ namespace chaiscript
}
static int calculate_arity(const std::vector<Proxy_Function> &t_funcs)
virtual int get_arity() const CHAISCRIPT_OVERRIDE
{
if (t_funcs.empty()) {
if (m_funcs.empty()) {
return -1;
}
const auto arity = t_funcs.front()->get_arity();
const int arity = m_funcs.front()->get_arity();
for (const auto &func : t_funcs)
for (const auto &func : m_funcs)
{
if (arity != func->get_arity())
{
@@ -307,10 +300,17 @@ namespace chaiscript
return arity;
}
virtual bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
virtual bool call_match(const std::vector<Boxed_Value> &vals, const Dynamic_Cast_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
{
return std::any_of(m_funcs.cbegin(), m_funcs.cend(),
[&vals, &t_conversions](const Proxy_Function &f){ return f->call_match(vals, t_conversions); });
for (const auto &func : m_funcs)
{
if (func->call_match(vals, t_conversions))
{
return true;
}
}
return false;
}
virtual std::string annotation() const CHAISCRIPT_OVERRIDE
@@ -319,9 +319,9 @@ namespace chaiscript
}
protected:
virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
{
return dispatch::dispatch(m_funcs, params, t_conversions);
return dispatch::dispatch(m_funcs.begin(), m_funcs.end(), params, t_conversions);
}
private:
@@ -329,8 +329,10 @@ namespace chaiscript
static std::vector<Type_Info> build_type_infos(const std::vector<Proxy_Function> &t_funcs)
{
auto begin = t_funcs.cbegin();
const auto &end = t_funcs.cend();
typedef std::vector<Proxy_Function> function_vec;
auto begin = t_funcs.begin();
const function_vec::const_iterator end = t_funcs.end();
if (begin != end)
{
@@ -378,8 +380,10 @@ namespace chaiscript
namespace detail
{
/// Main class for the dispatchkit. Handles management
/// of the object stack, functions and registered types.
/**
* Main class for the dispatchkit. Handles management
* of the object stack, functions and registered types.
*/
class Dispatch_Engine
{
public:
@@ -396,8 +400,6 @@ namespace chaiscript
std::set<std::string> m_reserved_words;
State &operator=(const State &) = default;
State() = default;
State(const State &) = default;
};
Dispatch_Engine()
@@ -418,7 +420,7 @@ namespace chaiscript
}
/// Add a new conversion for upcasting to a base class
void add(const Type_Conversion &d)
void add(const Dynamic_Cast_Conversion &d)
{
m_conversions.add_conversion(d);
}
@@ -435,12 +437,12 @@ namespace chaiscript
void add(const Boxed_Value &obj, const std::string &name)
{
validate_object_name(name);
auto &stack = get_stack_data();
StackData &stack = get_stack_data();
for (auto stack_elem = stack.rbegin(); stack_elem != stack.rend(); ++stack_elem)
for (int i = static_cast<int>(stack.size())-1; i >= 0; --i)
{
auto itr = stack_elem->find(name);
if (itr != stack_elem->end())
const auto itr = stack[i].find(name);
if (itr != stack[i].end())
{
itr->second = std::move(obj);
return;
@@ -452,13 +454,17 @@ namespace chaiscript
/// Adds a named object to the current scope
/// \warning This version does not check the validity of the name
/// it is meant for internal use only
void add_object(const std::string &name, const Boxed_Value &obj)
void add_object(const std::string &name, const Boxed_Value &obj) const
{
if (!get_stack_data().back().insert(std::make_pair(name, obj)).second)
StackData &stack = get_stack_data();
validate_object_name(name);
const Scope &scope = stack.back();
if (scope.find(name) != scope.end())
{
throw chaiscript::exception::name_conflict_error(name);
} else {
stack.back().insert(std::make_pair(name, std::move(obj)));
}
}
@@ -468,7 +474,7 @@ namespace chaiscript
validate_object_name(name);
if (!obj.is_const())
{
throw chaiscript::exception::global_non_const();
// throw chaiscript::exception::global_non_const();
}
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l(m_global_object_mutex);
@@ -502,13 +508,11 @@ namespace chaiscript
void new_scope()
{
get_stack_data().emplace_back();
m_stack_holder->call_params.emplace_back();
}
/// Pops the current scope from the stack
void pop_scope()
{
m_stack_holder->call_params.pop_back();
StackData &stack = get_stack_data();
if (stack.size() > 1)
{
@@ -542,13 +546,13 @@ namespace chaiscript
return m_place_holder;
}
auto &stack = get_stack_data();
StackData &stack = get_stack_data();
// Is it in the stack?
for (auto stack_elem = stack.rbegin(); stack_elem != stack.rend(); ++stack_elem)
for (int i = static_cast<int>(stack.size())-1; i >= 0; --i)
{
const auto stackitr = stack_elem->find(name);
if (stackitr != stack_elem->end())
const auto stackitr = stack[i].find(name);
if (stackitr != stack[i].end())
{
return stackitr->second;
}
@@ -668,7 +672,7 @@ namespace chaiscript
/// the current scope.
std::map<std::string, Boxed_Value> get_parent_locals() const
{
auto &stack = get_stack_data();
StackData &stack = get_stack_data();
if (stack.size() > 1)
{
return stack[1];
@@ -680,8 +684,8 @@ namespace chaiscript
/// \returns All values in the local thread state, added through the add() function
std::map<std::string, Boxed_Value> get_locals() const
{
auto &stack = get_stack_data();
auto &scope = stack.front();
StackData &stack = get_stack_data();
Scope &scope = stack.front();
return scope;
}
@@ -692,8 +696,8 @@ namespace chaiscript
/// Any existing locals are removed and the given set of variables is added
void set_locals(const std::map<std::string, Boxed_Value> &t_locals)
{
auto &stack = get_stack_data();
auto &scope = stack.front();
StackData &stack = get_stack_data();
Scope &scope = stack.front();
scope = t_locals;
}
@@ -704,10 +708,10 @@ namespace chaiscript
///
std::map<std::string, Boxed_Value> get_scripting_objects() const
{
const Stack_Holder &s = *m_stack_holder;
Stack_Holder &s = *m_stack_holder;
// We don't want the current context, but one up if it exists
const StackData &stack = (s.stacks.size()==1)?(s.stacks.back()):(s.stacks[s.stacks.size()-2]);
StackData &stack = (s.stacks.size()==1)?(s.stacks.back()):(s.stacks[s.stacks.size()-2]);
std::map<std::string, Boxed_Value> retval;
@@ -775,14 +779,16 @@ namespace chaiscript
m_state.m_reserved_words.insert(name);
}
const Type_Conversions &conversions() const
const Dynamic_Cast_Conversions &conversions() const
{
return m_conversions;
}
Boxed_Value call_function(const std::string &t_name, const std::vector<Boxed_Value> &params) const
{
return dispatch::dispatch(get_function(t_name), params, m_conversions);
std::vector<Proxy_Function> functions = get_function(t_name);
return dispatch::dispatch(functions.begin(), functions.end(), params, m_conversions);
}
Boxed_Value call_function(const std::string &t_name) const
@@ -803,7 +809,7 @@ namespace chaiscript
/// Dump object info to stdout
void dump_object(const Boxed_Value &o) const
{
std::cout << (o.is_const()?"const ":"") << type_name(o) << '\n';
std::cout << (o.is_const()?"const ":"") << type_name(o) << std::endl;
}
/// Dump type info to stdout
@@ -837,14 +843,14 @@ namespace chaiscript
}
}
std::cout << ") \n";
std::cout << ") " << std::endl;
}
/// Returns true if a call can be made that consists of the first parameter
/// (the function) with the remaining parameters as its arguments.
Boxed_Value call_exists(const std::vector<Boxed_Value> &params)
{
if (params.empty())
if (params.size() < 1)
{
throw chaiscript::exception::arity_error(static_cast<int>(params.size()), 1);
}
@@ -857,7 +863,7 @@ namespace chaiscript
/// Dump all system info to stdout
void dump_system() const
{
std::cout << "Registered Types: \n";
std::cout << "Registered Types: " << std::endl;
std::vector<std::pair<std::string, Type_Info> > types = get_types();
for (std::vector<std::pair<std::string, Type_Info> >::const_iterator itr = types.begin();
itr != types.end();
@@ -865,20 +871,20 @@ namespace chaiscript
{
std::cout << itr->first << ": ";
std::cout << itr->second.bare_name();
std::cout << '\n';
std::cout << std::endl;
}
std::cout << '\n';
std::cout << std::endl;
std::vector<std::pair<std::string, Proxy_Function > > funcs = get_functions();
std::cout << "Functions: \n";
std::cout << "Functions: " << std::endl;
for (std::vector<std::pair<std::string, Proxy_Function > >::const_iterator itr = funcs.begin();
itr != funcs.end();
++itr)
{
dump_function(*itr);
}
std::cout << '\n';
std::cout << std::endl;
}
/// return true if the Boxed_Value matches the registered type by name
@@ -922,39 +928,15 @@ namespace chaiscript
m_state = t_state;
}
void save_function_params(std::initializer_list<Boxed_Value> t_params)
{
Stack_Holder &s = *m_stack_holder;
s.call_params.back().insert(s.call_params.back().begin(), std::move(t_params));
}
void save_function_params(std::vector<Boxed_Value> &&t_params)
{
Stack_Holder &s = *m_stack_holder;
for (auto &&param : t_params)
{
s.call_params.back().insert(s.call_params.back().begin(), std::move(param));
}
}
void save_function_params(const std::vector<Boxed_Value> &t_params)
{
Stack_Holder &s = *m_stack_holder;
s.call_params.back().insert(s.call_params.back().begin(), t_params.begin(), t_params.end());
s.call_params.insert(s.call_params.begin(), t_params.begin(), t_params.end());
}
void new_function_call()
{
Stack_Holder &s = *m_stack_holder;
if (s.call_depth == 0)
{
m_conversions.enable_conversion_saves(true);
}
++s.call_depth;
save_function_params(m_conversions.take_saves());
++m_stack_holder->call_depth;
}
void pop_function_call()
@@ -966,20 +948,16 @@ namespace chaiscript
if (s.call_depth == 0)
{
s.call_params.back().clear();
m_conversions.enable_conversion_saves(false);
/// \todo Critical: this needs to be smarter, memory can expand quickly
/// in tight loops involving function calls
s.call_params.clear();
}
}
private:
/// Returns the current stack
/// make const/non const versions
const StackData &get_stack_data() const
{
return m_stack_holder->stacks.back();
}
StackData &get_stack_data()
StackData &get_stack_data() const
{
return m_stack_holder->stacks.back();
}
@@ -1006,17 +984,17 @@ namespace chaiscript
static bool function_less_than(const Proxy_Function &lhs, const Proxy_Function &rhs)
{
const auto &lhsparamtypes = lhs->get_param_types();
const auto &rhsparamtypes = rhs->get_param_types();
const std::vector<Type_Info> &lhsparamtypes = lhs->get_param_types();
const std::vector<Type_Info> &rhsparamtypes = rhs->get_param_types();
const auto lhssize = lhsparamtypes.size();
const auto rhssize = rhsparamtypes.size();
const size_t lhssize = lhsparamtypes.size();
const size_t rhssize = rhsparamtypes.size();
CHAISCRIPT_CONSTEXPR auto boxed_type = user_type<Boxed_Value>();
CHAISCRIPT_CONSTEXPR auto boxed_pod_type = user_type<Boxed_Number>();
const Type_Info boxed_type = user_type<Boxed_Value>();
const Type_Info boxed_pod_type = user_type<Boxed_Number>();
auto dynamic_lhs(std::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(lhs));
auto dynamic_rhs(std::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(rhs));
std::shared_ptr<const dispatch::Dynamic_Proxy_Function> dynamic_lhs(std::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(lhs));
std::shared_ptr<const dispatch::Dynamic_Proxy_Function> dynamic_rhs(std::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(rhs));
if (dynamic_lhs && dynamic_rhs)
{
@@ -1163,16 +1141,15 @@ namespace chaiscript
: call_depth(0)
{
stacks.emplace_back(1);
call_params.emplace_back();
}
std::deque<StackData> stacks;
std::deque<std::list<Boxed_Value>> call_params;
std::list<Boxed_Value> call_params;
int call_depth;
};
Type_Conversions m_conversions;
Dynamic_Cast_Conversions m_conversions;
chaiscript::detail::threading::Thread_Storage<Stack_Holder> m_stack_holder;

View File

@@ -0,0 +1,294 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_DYNAMIC_CAST_CONVERSION_HPP_
#define CHAISCRIPT_DYNAMIC_CAST_CONVERSION_HPP_
#include <memory>
#include <set>
#include <stdexcept>
#include <string>
#include <type_traits>
#include <typeinfo>
#include "../chaiscript_threading.hpp"
#include "bad_boxed_cast.hpp"
#include "boxed_cast_helper.hpp"
#include "boxed_value.hpp"
#include "type_info.hpp"
namespace chaiscript
{
namespace exception
{
class bad_boxed_dynamic_cast : public bad_boxed_cast
{
public:
bad_boxed_dynamic_cast(const Type_Info &t_from, const std::type_info &t_to,
const std::string &t_what) CHAISCRIPT_NOEXCEPT
: bad_boxed_cast(t_from, t_to, t_what)
{
}
bad_boxed_dynamic_cast(const Type_Info &t_from, const std::type_info &t_to) CHAISCRIPT_NOEXCEPT
: bad_boxed_cast(t_from, t_to)
{
}
bad_boxed_dynamic_cast(const std::string &w) CHAISCRIPT_NOEXCEPT
: bad_boxed_cast(w)
{
}
virtual ~bad_boxed_dynamic_cast() CHAISCRIPT_NOEXCEPT {}
};
}
namespace detail
{
class Dynamic_Conversion
{
public:
virtual Boxed_Value convert(const Boxed_Value &derived) const = 0;
virtual Boxed_Value convert_down(const Boxed_Value &base) const = 0;
const Type_Info &base() const
{
return m_base;
}
const Type_Info &derived() const
{
return m_derived;
}
protected:
Dynamic_Conversion(const Type_Info &t_base, const Type_Info &t_derived)
: m_base(t_base), m_derived(t_derived)
{
}
virtual ~Dynamic_Conversion() {}
private:
Type_Info m_base;
Type_Info m_derived;
};
template<typename From, typename To>
class Dynamic_Caster
{
public:
static Boxed_Value cast(const Boxed_Value &t_from)
{
if (t_from.get_type_info().bare_equal(user_type<From>()))
{
if (t_from.is_pointer())
{
// Dynamic cast out the contained boxed value, which we know is the type we want
if (t_from.is_const())
{
std::shared_ptr<const To> data
= std::dynamic_pointer_cast<const To>(detail::Cast_Helper<std::shared_ptr<const From> >::cast(t_from, nullptr));
if (!data)
{
throw std::bad_cast();
}
return Boxed_Value(data);
} else {
std::shared_ptr<To> data
= std::dynamic_pointer_cast<To>(detail::Cast_Helper<std::shared_ptr<From> >::cast(t_from, nullptr));
if (!data)
{
throw std::bad_cast();
}
return Boxed_Value(data);
}
} else {
// Pull the reference out of the contained boxed value, which we know is the type we want
if (t_from.is_const())
{
const From &d = detail::Cast_Helper<const From &>::cast(t_from, nullptr);
const To &data = dynamic_cast<const To &>(d);
return Boxed_Value(std::cref(data));
} else {
From &d = detail::Cast_Helper<From &>::cast(t_from, nullptr);
To &data = dynamic_cast<To &>(d);
return Boxed_Value(std::ref(data));
}
}
} else {
throw chaiscript::exception::bad_boxed_dynamic_cast(t_from.get_type_info(), typeid(To), "Unknown dynamic_cast_conversion");
}
}
};
template<typename Base, typename Derived>
class Dynamic_Conversion_Impl : public Dynamic_Conversion
{
public:
Dynamic_Conversion_Impl()
: Dynamic_Conversion(user_type<Base>(), user_type<Derived>())
{
}
virtual Boxed_Value convert_down(const Boxed_Value &t_base) const CHAISCRIPT_OVERRIDE
{
return Dynamic_Caster<Base, Derived>::cast(t_base);
}
virtual Boxed_Value convert(const Boxed_Value &t_derived) const CHAISCRIPT_OVERRIDE
{
return Dynamic_Caster<Derived, Base>::cast(t_derived);
}
};
}
class Dynamic_Cast_Conversions
{
public:
Dynamic_Cast_Conversions()
{
}
Dynamic_Cast_Conversions(const Dynamic_Cast_Conversions &t_other)
: m_conversions(t_other.get_conversions())
{
}
void add_conversion(const std::shared_ptr<detail::Dynamic_Conversion> &conversion)
{
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
m_conversions.insert(conversion);
}
template<typename Base, typename Derived>
bool dynamic_cast_converts() const
{
return dynamic_cast_converts(user_type<Base>(), user_type<Derived>());
}
bool dynamic_cast_converts(const Type_Info &base, const Type_Info &derived) const
{
return has_conversion(base, derived) || has_conversion(derived, base);
}
template<typename Base>
Boxed_Value boxed_dynamic_cast(const Boxed_Value &derived) const
{
try {
return get_conversion(user_type<Base>(), derived.get_type_info())->convert(derived);
} catch (const std::out_of_range &) {
throw exception::bad_boxed_dynamic_cast(derived.get_type_info(), typeid(Base), "No known conversion");
} catch (const std::bad_cast &) {
throw exception::bad_boxed_dynamic_cast(derived.get_type_info(), typeid(Base), "Unable to perform dynamic_cast operation");
}
}
template<typename Derived>
Boxed_Value boxed_dynamic_down_cast(const Boxed_Value &base) const
{
try {
return get_conversion(base.get_type_info(), user_type<Derived>())->convert_down(base);
} catch (const std::out_of_range &) {
throw exception::bad_boxed_dynamic_cast(base.get_type_info(), typeid(Derived), "No known conversion");
} catch (const std::bad_cast &) {
throw exception::bad_boxed_dynamic_cast(base.get_type_info(), typeid(Derived), "Unable to perform dynamic_cast operation");
}
}
bool has_conversion(const Type_Info &base, const Type_Info &derived) const
{
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
return find(base, derived) != m_conversions.end();
}
std::shared_ptr<detail::Dynamic_Conversion> get_conversion(const Type_Info &base, const Type_Info &derived) const
{
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
auto itr =
find(base, derived);
if (itr != m_conversions.end())
{
return *itr;
} else {
throw std::out_of_range("No such conversion exists from " + derived.bare_name() + " to " + base.bare_name());
}
}
private:
std::set<std::shared_ptr<detail::Dynamic_Conversion> >::const_iterator find(
const Type_Info &base, const Type_Info &derived) const
{
for (auto itr = m_conversions.begin();
itr != m_conversions.end();
++itr)
{
if ((*itr)->base().bare_equal(base) && (*itr)->derived().bare_equal(derived))
{
return itr;
}
}
return m_conversions.end();
}
std::set<std::shared_ptr<detail::Dynamic_Conversion> > get_conversions() const
{
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
return m_conversions;
}
mutable chaiscript::detail::threading::shared_mutex m_mutex;
std::set<std::shared_ptr<detail::Dynamic_Conversion> > m_conversions;
};
typedef std::shared_ptr<chaiscript::detail::Dynamic_Conversion> Dynamic_Cast_Conversion;
/// \brief Used to register a base / parent class relationship with ChaiScript. Necessary if you
/// want automatic conversions up your inheritance hierarchy.
///
/// Create a new base class registration for applying to a module or to the ChaiScript engine
/// Currently, due to limitations in module loading on Windows, and for the sake of portability,
/// if you have a type that is introduced in a loadable module and is used by multiple modules
/// (through a tertiary dll that is shared between the modules, static linking the new type
/// into both loadable modules would not be portable), you need to register the base type
/// relationship in all modules that use the newly added type in a polymorphic way.
///
/// Example:
/// \code
/// class Base
/// {};
/// class Derived : public Base
/// {};
///
/// chaiscript::ChaiScript chai;
/// chai.add(chaiscript::base_class<Base, Derived>());
/// \endcode
///
template<typename Base, typename Derived>
Dynamic_Cast_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");
static_assert(std::is_polymorphic<Base>::value, "Base class must be polymorphic");
static_assert(std::is_polymorphic<Derived>::value, "Derived class must be polymorphic");
return std::shared_ptr<detail::Dynamic_Conversion>(new detail::Dynamic_Conversion_Impl<Base, Derived>());
}
}
#endif

View File

@@ -1,7 +1,7 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_DYNAMIC_OBJECT_HPP_
@@ -19,10 +19,11 @@
#include "boxed_cast.hpp"
#include "boxed_cast_helper.hpp"
#include "boxed_value.hpp"
#include "proxy_functions.hpp"
#include "type_info.hpp"
namespace chaiscript {
class Type_Conversions;
class Dynamic_Cast_Conversions;
namespace dispatch {
class Proxy_Function_Base;
} // namespace dispatch
@@ -61,6 +62,234 @@ namespace chaiscript
std::map<std::string, Boxed_Value> m_attrs;
};
namespace detail
{
/**
* A Proxy_Function implementation designed for calling a function
* that is automatically guarded based on the first param based on the
* param's type name
*/
class Dynamic_Object_Function : public Proxy_Function_Base
{
public:
Dynamic_Object_Function(
std::string t_type_name,
const Proxy_Function &t_func)
: Proxy_Function_Base(t_func->get_param_types()),
m_type_name(std::move(t_type_name)), m_func(t_func), m_doti(user_type<Dynamic_Object>())
{
assert( (t_func->get_arity() > 0 || t_func->get_arity() < 0)
&& "Programming error, Dynamic_Object_Function must have at least one parameter (this)");
}
Dynamic_Object_Function(
std::string t_type_name,
const Proxy_Function &t_func,
const Type_Info &t_ti)
: Proxy_Function_Base(build_param_types(t_func->get_param_types(), t_ti)),
m_type_name(std::move(t_type_name)), m_func(t_func), m_ti(new Type_Info(t_ti)), m_doti(user_type<Dynamic_Object>())
{
assert( (t_func->get_arity() > 0 || t_func->get_arity() < 0)
&& "Programming error, Dynamic_Object_Function must have at least one parameter (this)");
}
virtual ~Dynamic_Object_Function() {}
Dynamic_Object_Function &operator=(const Dynamic_Object_Function) = delete;
virtual bool operator==(const Proxy_Function_Base &f) const CHAISCRIPT_OVERRIDE
{
const Dynamic_Object_Function *df = dynamic_cast<const Dynamic_Object_Function *>(&f);
if (df)
{
return df->m_type_name == m_type_name && (*df->m_func) == (*m_func);
} else {
return false;
}
}
virtual bool call_match(const std::vector<Boxed_Value> &vals, const Dynamic_Cast_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
{
if (dynamic_object_typename_match(vals, m_type_name, m_ti, t_conversions))
{
return m_func->call_match(vals, t_conversions);
} else {
return false;
}
}
virtual std::vector<Const_Proxy_Function> get_contained_functions() const CHAISCRIPT_OVERRIDE
{
return {m_func};
}
virtual int get_arity() const CHAISCRIPT_OVERRIDE
{
return m_func->get_arity();
}
virtual std::string annotation() const CHAISCRIPT_OVERRIDE
{
return m_func->annotation();
}
protected:
virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
{
if (dynamic_object_typename_match(params, m_type_name, m_ti, t_conversions))
{
return (*m_func)(params, t_conversions);
} else {
throw exception::guard_error();
}
}
virtual bool compare_first_type(const Boxed_Value &bv, const Dynamic_Cast_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
{
return dynamic_object_typename_match(bv, m_type_name, m_ti, t_conversions);
}
private:
static std::vector<Type_Info> build_param_types(
const std::vector<Type_Info> &t_inner_types, const Type_Info& t_objectti)
{
std::vector<Type_Info> types(t_inner_types);
assert(types.size() > 1);
assert(types[1].bare_equal(user_type<Boxed_Value>()));
types[1] = t_objectti;
return types;
}
bool dynamic_object_typename_match(const Boxed_Value &bv, const std::string &name,
const std::shared_ptr<Type_Info> &ti, const Dynamic_Cast_Conversions &t_conversions) const
{
if (bv.get_type_info().bare_equal(m_doti))
{
try {
const Dynamic_Object &d = boxed_cast<const Dynamic_Object &>(bv, &t_conversions);
return name == "Dynamic_Object" || d.get_type_name() == name;
} catch (const std::bad_cast &) {
return false;
}
} else {
if (ti)
{
return bv.get_type_info().bare_equal(*ti);
} else {
return false;
}
}
}
bool dynamic_object_typename_match(const std::vector<Boxed_Value> &bvs, const std::string &name,
const std::shared_ptr<Type_Info> &ti, const Dynamic_Cast_Conversions &t_conversions) const
{
if (bvs.size() > 0)
{
return dynamic_object_typename_match(bvs[0], name, ti, t_conversions);
} else {
return false;
}
}
std::string m_type_name;
Proxy_Function m_func;
std::shared_ptr<Type_Info> m_ti;
const Type_Info m_doti;
};
/**
* A Proxy_Function implementation designed for creating a new
* Dynamic_Object
* that is automatically guarded based on the first param based on the
* param's type name
*/
class Dynamic_Object_Constructor : public Proxy_Function_Base
{
public:
Dynamic_Object_Constructor(
std::string t_type_name,
const Proxy_Function &t_func)
: Proxy_Function_Base(build_type_list(t_func->get_param_types())),
m_type_name(std::move(t_type_name)), m_func(t_func)
{
assert( (t_func->get_arity() > 0 || t_func->get_arity() < 0)
&& "Programming error, Dynamic_Object_Function must have at least one parameter (this)");
}
static std::vector<Type_Info> build_type_list(const std::vector<Type_Info> &tl)
{
auto begin = tl.begin();
auto end = tl.end();
if (begin != end)
{
++begin;
}
return std::vector<Type_Info>(begin, end);
}
virtual ~Dynamic_Object_Constructor() {}
virtual bool operator==(const Proxy_Function_Base &f) const CHAISCRIPT_OVERRIDE
{
const Dynamic_Object_Constructor *dc = dynamic_cast<const Dynamic_Object_Constructor*>(&f);
if (dc)
{
return dc->m_type_name == m_type_name && (*dc->m_func) == (*m_func);
} else {
return false;
}
}
virtual bool call_match(const std::vector<Boxed_Value> &vals, const Dynamic_Cast_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
{
std::vector<Boxed_Value> new_vals;
new_vals.push_back(Boxed_Value(Dynamic_Object(m_type_name)));
new_vals.insert(new_vals.end(), vals.begin(), vals.end());
return m_func->call_match(new_vals, t_conversions);
}
virtual int get_arity() const CHAISCRIPT_OVERRIDE
{
// "this" is not considered part of the arity
return m_func->get_arity() - 1;
}
virtual std::string annotation() const CHAISCRIPT_OVERRIDE
{
return m_func->annotation();
}
protected:
virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
{
std::vector<Boxed_Value> new_params;
chaiscript::Boxed_Value bv = var(Dynamic_Object(m_type_name));
new_params.push_back(bv);
new_params.insert(new_params.end(), params.begin(), params.end());
(*m_func)(new_params, t_conversions);
return bv;
}
private:
std::string m_type_name;
Proxy_Function m_func;
};
}
}
}
#endif

View File

@@ -1,251 +0,0 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_DYNAMIC_OBJECT_DETAIL_HPP_
#define CHAISCRIPT_DYNAMIC_OBJECT_DETAIL_HPP_
#include <cassert>
#include <map>
#include <memory>
#include <string>
#include <typeinfo>
#include <utility>
#include <vector>
#include "../chaiscript_defines.hpp"
#include "boxed_cast.hpp"
#include "boxed_cast_helper.hpp"
#include "boxed_value.hpp"
#include "proxy_functions.hpp"
#include "type_info.hpp"
#include "dynamic_object.hpp"
namespace chaiscript {
class Type_Conversions;
namespace dispatch {
class Proxy_Function_Base;
} // namespace dispatch
} // namespace chaiscript
namespace chaiscript
{
namespace dispatch
{
namespace detail
{
/// A Proxy_Function implementation designed for calling a function
/// that is automatically guarded based on the first param based on the
/// param's type name
class Dynamic_Object_Function : public Proxy_Function_Base
{
public:
Dynamic_Object_Function(
std::string t_type_name,
const Proxy_Function &t_func)
: Proxy_Function_Base(t_func->get_param_types(), t_func->get_arity()),
m_type_name(std::move(t_type_name)), m_func(t_func), m_doti(user_type<Dynamic_Object>())
{
assert( (t_func->get_arity() > 0 || t_func->get_arity() < 0)
&& "Programming error, Dynamic_Object_Function must have at least one parameter (this)");
}
Dynamic_Object_Function(
std::string t_type_name,
const Proxy_Function &t_func,
const Type_Info &t_ti)
: Proxy_Function_Base(build_param_types(t_func->get_param_types(), t_ti), t_func->get_arity()),
m_type_name(std::move(t_type_name)), m_func(t_func), m_ti(new Type_Info(t_ti)), m_doti(user_type<Dynamic_Object>())
{
assert( (t_func->get_arity() > 0 || t_func->get_arity() < 0)
&& "Programming error, Dynamic_Object_Function must have at least one parameter (this)");
}
virtual ~Dynamic_Object_Function() {}
Dynamic_Object_Function &operator=(const Dynamic_Object_Function) = delete;
Dynamic_Object_Function(Dynamic_Object_Function &) = delete;
virtual bool operator==(const Proxy_Function_Base &f) const CHAISCRIPT_OVERRIDE
{
if (const auto *df = dynamic_cast<const Dynamic_Object_Function *>(&f))
{
return df->m_type_name == m_type_name && (*df->m_func) == (*m_func);
} else {
return false;
}
}
virtual bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
{
if (dynamic_object_typename_match(vals, m_type_name, m_ti, t_conversions))
{
return m_func->call_match(vals, t_conversions);
} else {
return false;
}
}
virtual std::vector<Const_Proxy_Function> get_contained_functions() const CHAISCRIPT_OVERRIDE
{
return {m_func};
}
virtual std::string annotation() const CHAISCRIPT_OVERRIDE
{
return m_func->annotation();
}
protected:
virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
{
if (dynamic_object_typename_match(params, m_type_name, m_ti, t_conversions))
{
return (*m_func)(params, t_conversions);
} else {
throw exception::guard_error();
}
}
virtual bool compare_first_type(const Boxed_Value &bv, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
{
return dynamic_object_typename_match(bv, m_type_name, m_ti, t_conversions);
}
private:
static std::vector<Type_Info> build_param_types(
const std::vector<Type_Info> &t_inner_types, const Type_Info& t_objectti)
{
std::vector<Type_Info> types(t_inner_types);
assert(types.size() > 1);
//assert(types[1].bare_equal(user_type<Boxed_Value>()));
types[1] = t_objectti;
return types;
}
bool dynamic_object_typename_match(const Boxed_Value &bv, const std::string &name,
const std::unique_ptr<Type_Info> &ti, const Type_Conversions &t_conversions) const
{
if (bv.get_type_info().bare_equal(m_doti))
{
try {
const Dynamic_Object &d = boxed_cast<const Dynamic_Object &>(bv, &t_conversions);
return name == "Dynamic_Object" || d.get_type_name() == name;
} catch (const std::bad_cast &) {
return false;
}
} else {
if (ti)
{
return bv.get_type_info().bare_equal(*ti);
} else {
return false;
}
}
}
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 &t_conversions) const
{
if (bvs.size() > 0)
{
return dynamic_object_typename_match(bvs[0], name, ti, t_conversions);
} else {
return false;
}
}
std::string m_type_name;
Proxy_Function m_func;
std::unique_ptr<Type_Info> m_ti;
const Type_Info m_doti;
};
/**
* A Proxy_Function implementation designed for creating a new
* Dynamic_Object
* that is automatically guarded based on the first param based on the
* param's type name
*/
class Dynamic_Object_Constructor : public Proxy_Function_Base
{
public:
Dynamic_Object_Constructor(
std::string t_type_name,
const Proxy_Function &t_func)
: Proxy_Function_Base(build_type_list(t_func->get_param_types()), t_func->get_arity() - 1),
m_type_name(std::move(t_type_name)), m_func(t_func)
{
assert( (t_func->get_arity() > 0 || t_func->get_arity() < 0)
&& "Programming error, Dynamic_Object_Function must have at least one parameter (this)");
}
static std::vector<Type_Info> build_type_list(const std::vector<Type_Info> &tl)
{
auto begin = tl.begin();
auto end = tl.end();
if (begin != end)
{
++begin;
}
return std::vector<Type_Info>(begin, end);
}
virtual ~Dynamic_Object_Constructor() {}
virtual bool operator==(const Proxy_Function_Base &f) const CHAISCRIPT_OVERRIDE
{
const Dynamic_Object_Constructor *dc = dynamic_cast<const Dynamic_Object_Constructor*>(&f);
if (dc)
{
return dc->m_type_name == m_type_name && (*dc->m_func) == (*m_func);
} else {
return false;
}
}
virtual bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
{
std::vector<Boxed_Value> new_vals{Boxed_Value(Dynamic_Object(m_type_name))};
new_vals.insert(new_vals.end(), vals.begin(), vals.end());
return m_func->call_match(new_vals, t_conversions);
}
virtual std::string annotation() const CHAISCRIPT_OVERRIDE
{
return m_func->annotation();
}
protected:
virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
{
auto bv = var(Dynamic_Object(m_type_name));
std::vector<Boxed_Value> new_params{bv};
new_params.insert(new_params.end(), params.begin(), params.end());
(*m_func)(new_params, t_conversions);
return bv;
}
private:
std::string m_type_name;
Proxy_Function m_func;
};
}
}
}
#endif

View File

@@ -1,7 +1,7 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_EXCEPTION_SPECIFICATION_HPP_

View File

@@ -1,7 +1,7 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_FUNCTION_CALL_HPP_
@@ -18,7 +18,7 @@
namespace chaiscript {
class Boxed_Value;
class Type_Conversions;
class Dynamic_Cast_Conversions;
namespace detail {
template <typename T> struct Cast_Helper;
} // namespace detail
@@ -28,56 +28,66 @@ namespace chaiscript
{
namespace dispatch
{
/// Build a function caller that knows how to dispatch on a set of functions
/// example:
/// std::function<void (int)> f =
/// build_function_caller(dispatchkit.get_function("print"));
/// \returns A std::function object for dispatching
/// \param[in] funcs the set of functions to dispatch on.
/**
* Build a function caller that knows how to dispatch on a set of functions
* example:
* std::function<void (int)> f =
* build_function_caller(dispatchkit.get_function("print"));
* \returns A std::function object for dispatching
* \param[in] funcs the set of functions to dispatch on.
*/
template<typename FunctionType>
std::function<FunctionType>
functor(const std::vector<Const_Proxy_Function> &funcs, const Type_Conversions *t_conversions)
functor(const std::vector<Const_Proxy_Function> &funcs, const Dynamic_Cast_Conversions *t_conversions)
{
FunctionType *p=nullptr;
return detail::build_function_caller_helper(p, funcs, t_conversions);
}
/// Build a function caller for a particular Proxy_Function object
/// useful in the case that a function is being pass out from scripting back
/// into code
/// example:
/// void my_function(Proxy_Function f)
/// {
/// std::function<void (int)> local_f =
/// build_function_caller(f);
/// }
/// \returns A std::function object for dispatching
/// \param[in] func A function to execute.
/**
* Build a function caller for a particular Proxy_Function object
* useful in the case that a function is being pass out from scripting back
* into code
* example:
* void my_function(Proxy_Function f)
* {
* std::function<void (int)> local_f =
* build_function_caller(f);
* }
* \returns A std::function object for dispatching
* \param[in] func A function to execute.
*/
template<typename FunctionType>
std::function<FunctionType>
functor(Const_Proxy_Function func, const Type_Conversions *t_conversions)
functor(Const_Proxy_Function func, const Dynamic_Cast_Conversions *t_conversions)
{
return functor<FunctionType>(std::vector<Const_Proxy_Function>({func}), t_conversions);
std::vector<Const_Proxy_Function> funcs;
funcs.push_back(func);
return functor<FunctionType>(funcs, t_conversions);
}
/// Helper for automatically unboxing a Boxed_Value that contains a function object
/// and creating a typesafe C++ function caller from it.
/**
* Helper for automatically unboxing a Boxed_Value that contains a function object
* and creating a typesafe C++ function caller from it.
*/
template<typename FunctionType>
std::function<FunctionType>
functor(const Boxed_Value &bv, const Type_Conversions *t_conversions)
functor(const Boxed_Value &bv, const Dynamic_Cast_Conversions *t_conversions)
{
return functor<FunctionType>(boxed_cast<Const_Proxy_Function >(bv, t_conversions), t_conversions);
}
}
namespace detail{
/// Cast helper to handle automatic casting to const std::function &
/**
* Cast helper to handle automatic casting to const std::function &
*/
template<typename Signature>
struct Cast_Helper<const std::function<Signature> &>
{
typedef std::function<Signature> Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *t_conversions)
static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *t_conversions)
{
if (ob.get_type_info().bare_equal(user_type<Const_Proxy_Function>()))
{
@@ -88,13 +98,15 @@ namespace chaiscript
}
};
/// Cast helper to handle automatic casting to std::function
/**
* Cast helper to handle automatic casting to std::function
*/
template<typename Signature>
struct Cast_Helper<std::function<Signature> >
{
typedef std::function<Signature> Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *t_conversions)
static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *t_conversions)
{
if (ob.get_type_info().bare_equal(user_type<Const_Proxy_Function>()))
{
@@ -105,13 +117,15 @@ namespace chaiscript
}
};
/// Cast helper to handle automatic casting to const std::function
/**
* Cast helper to handle automatic casting to const std::function
*/
template<typename Signature>
struct Cast_Helper<const std::function<Signature> >
{
typedef std::function<Signature> Result_Type;
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *t_conversions)
static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *t_conversions)
{
if (ob.get_type_info().bare_equal(user_type<Const_Proxy_Function>()))
{

View File

@@ -1,7 +1,7 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_FUNCTION_CALL_DETAIL_HPP_
@@ -17,7 +17,7 @@
#include "boxed_cast.hpp"
#include "boxed_number.hpp"
#include "boxed_value.hpp"
#include "type_conversions.hpp"
#include "dynamic_cast_conversion.hpp"
#include "proxy_functions.hpp"
namespace chaiscript
@@ -26,13 +26,15 @@ namespace chaiscript
{
namespace detail
{
/// Internal helper class for handling the return
/// value of a build_function_caller
/**
* Internal helper class for handling the return
* value of a build_function_caller
*/
template<typename Ret, bool is_arithmetic>
struct Function_Caller_Ret
{
static Ret call(const std::vector<Const_Proxy_Function> &t_funcs,
const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions)
const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions)
{
return boxed_cast<Ret>(dispatch::dispatch(t_funcs, params, t_conversions));
}
@@ -45,7 +47,7 @@ namespace chaiscript
struct Function_Caller_Ret<Ret, true>
{
static Ret call(const std::vector<Const_Proxy_Function> &t_funcs,
const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions)
const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions)
{
return Boxed_Number(dispatch::dispatch(t_funcs, params, t_conversions)).get_as<Ret>();
}
@@ -59,7 +61,7 @@ namespace chaiscript
struct Function_Caller_Ret<void, false>
{
static void call(const std::vector<Const_Proxy_Function> &t_funcs,
const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions)
const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions)
{
dispatch::dispatch(t_funcs, params, t_conversions);
}
@@ -71,7 +73,7 @@ namespace chaiscript
template<typename Ret, typename ... Param>
struct Build_Function_Caller_Helper
{
Build_Function_Caller_Helper(std::vector<Const_Proxy_Function> t_funcs, const Type_Conversions &t_conversions)
Build_Function_Caller_Helper(std::vector<Const_Proxy_Function> t_funcs, const Dynamic_Cast_Conversions &t_conversions)
: m_funcs(std::move(t_funcs)),
m_conversions(t_conversions)
{
@@ -88,13 +90,13 @@ namespace chaiscript
}
std::vector<Const_Proxy_Function> m_funcs;
Type_Conversions m_conversions;
Dynamic_Cast_Conversions m_conversions;
};
template<typename Ret, typename ... Params>
std::function<Ret (Params...)> build_function_caller_helper(Ret (Params...), const std::vector<Const_Proxy_Function> &funcs, const Type_Conversions *t_conversions)
std::function<Ret (Params...)> build_function_caller_helper(Ret (Params...), const std::vector<Const_Proxy_Function> &funcs, const Dynamic_Cast_Conversions *t_conversions)
{
if (funcs.size() == 1)
{
@@ -110,7 +112,7 @@ namespace chaiscript
// we cannot make any other guesses or assumptions really, so continuing
}
return std::function<Ret (Params...)>(Build_Function_Caller_Helper<Ret, Params...>(funcs, t_conversions?*t_conversions:Type_Conversions()));
return std::function<Ret (Params...)>(Build_Function_Caller_Helper<Ret, Params...>(funcs, t_conversions?*t_conversions:Dynamic_Cast_Conversions()));
}
}
}

View File

@@ -1,7 +1,7 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_HANDLE_RETURN_HPP_
@@ -37,11 +37,6 @@ namespace chaiscript
{
return const_var(r);
}
static Boxed_Value handle(Ret &&r)
{
return Boxed_Value(std::move(r));
}
};
template<typename Ret>
@@ -53,15 +48,6 @@ namespace chaiscript
}
};
template<typename Ret>
struct Handle_Return<const Ret *>
{
static Boxed_Value handle(const Ret *p)
{
return Boxed_Value(p);
}
};
template<typename Ret>
struct Handle_Return<std::shared_ptr<Ret> &>
{

View File

@@ -1,7 +1,7 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_OPERATORS_HPP_

View File

@@ -1,15 +1,13 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_PROXY_CONSTRUCTORS_HPP_
#define CHAISCRIPT_PROXY_CONSTRUCTORS_HPP_
#include "proxy_functions.hpp"
namespace chaiscript
{
namespace dispatch

View File

@@ -1,7 +1,7 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
@@ -24,10 +24,9 @@
#include "boxed_value.hpp"
#include "proxy_functions_detail.hpp"
#include "type_info.hpp"
#include "dynamic_object.hpp"
namespace chaiscript {
class Type_Conversions;
class Dynamic_Cast_Conversions;
namespace exception {
class bad_boxed_cast;
struct arity_error;
@@ -43,95 +42,6 @@ namespace chaiscript
namespace dispatch
{
class Param_Types
{
public:
Param_Types()
: m_has_types(false),
m_doti(user_type<Dynamic_Object>())
{}
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>())
{
update_has_types();
}
void push_front(std::string t_name, Type_Info t_ti)
{
m_types.emplace(m_types.begin(), std::move(t_name), std::move(t_ti));
update_has_types();
}
bool operator==(const Param_Types &t_rhs) const
{
return m_types == t_rhs.m_types;
}
bool match(const std::vector<Boxed_Value> &vals, const Type_Conversions &t_conversions) const
{
if (!m_has_types) return true;
if (vals.size() != m_types.size()) return false;
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))
{
try {
const Dynamic_Object &d = boxed_cast<const Dynamic_Object &>(bv, &t_conversions);
return name == "Dynamic_Object" || d.get_type_name() == name;
} catch (const std::bad_cast &) {
return false;
}
} else {
const auto &ti = m_types[i].second;
if (!ti.is_undef())
{
if (!bv.get_type_info().bare_equal(ti)) {
return false;
}
} else {
return false;
}
}
}
}
return true;
}
const std::vector<std::pair<std::string, Type_Info>> &types() const
{
return m_types;
}
private:
void update_has_types()
{
for (const auto &type : m_types)
{
if (!type.first.empty())
{
m_has_types = true;
return;
}
}
m_has_types = false;
}
std::vector<std::pair<std::string, Type_Info>> m_types;
bool m_has_types;
Type_Info m_doti;
};
/**
* Pure virtual base class for all Proxy_Function implementations
* Proxy_Functions are a type erasure of type safe C++
@@ -145,7 +55,7 @@ namespace chaiscript
public:
virtual ~Proxy_Function_Base() {}
Boxed_Value operator()(const std::vector<Boxed_Value> &params, const chaiscript::Type_Conversions &t_conversions) const
Boxed_Value operator()(const std::vector<Boxed_Value> &params, const chaiscript::Dynamic_Cast_Conversions &t_conversions) const
{
Boxed_Value bv = do_call(params, t_conversions);
return bv;
@@ -158,7 +68,7 @@ namespace chaiscript
const std::vector<Type_Info> &get_param_types() const { return m_types; }
virtual bool operator==(const Proxy_Function_Base &) const = 0;
virtual bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions &t_conversions) const = 0;
virtual bool call_match(const std::vector<Boxed_Value> &vals, const Dynamic_Cast_Conversions &t_conversions) const = 0;
bool has_arithmetic_param() const
{
@@ -172,13 +82,15 @@ 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 &t_conversions) const
bool filter(const std::vector<Boxed_Value> &vals, const Dynamic_Cast_Conversions &t_conversions) const
{
if (m_arity < 0)
int arity = get_arity();
if (arity < 0)
{
return true;
} else if (size_t(m_arity) == vals.size()) {
if (m_arity == 0)
} else if (size_t(arity) == vals.size()) {
if (arity == 0)
{
return true;
} else {
@@ -190,14 +102,11 @@ namespace chaiscript
}
/// \returns the number of arguments the function takes or -1 if it is variadic
int get_arity() const
{
return m_arity;
}
virtual int get_arity() const = 0;
virtual std::string annotation() const = 0;
static bool compare_type_to_param(const Type_Info &ti, const Boxed_Value &bv, const Type_Conversions &t_conversions)
static bool compare_type_to_param(const Type_Info &ti, const Boxed_Value &bv, const Dynamic_Cast_Conversions &t_conversions)
{
if (ti.is_undef()
|| ti.bare_equal(user_type<Boxed_Value>())
@@ -205,7 +114,7 @@ namespace chaiscript
&& (ti.bare_equal(user_type<Boxed_Number>())
|| ti.bare_equal(bv.get_type_info())
|| bv.get_type_info().bare_equal(user_type<std::shared_ptr<const Proxy_Function_Base> >())
|| t_conversions.converts(ti, bv.get_type_info())
|| t_conversions.dynamic_cast_converts(ti, bv.get_type_info())
)
)
)
@@ -216,10 +125,10 @@ namespace chaiscript
}
}
protected:
virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions) const = 0;
virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions) const = 0;
Proxy_Function_Base(std::vector<Type_Info> t_types, int t_arity)
: m_types(std::move(t_types)), m_arity(t_arity), m_has_arithmetic_param(false)
Proxy_Function_Base(std::vector<Type_Info> t_types)
: m_types(std::move(t_types)), m_has_arithmetic_param(false)
{
for (size_t i = 1; i < m_types.size(); ++i)
{
@@ -232,7 +141,7 @@ namespace chaiscript
}
virtual bool compare_first_type(const Boxed_Value &bv, const Type_Conversions &t_conversions) const
virtual bool compare_first_type(const Boxed_Value &bv, const Dynamic_Cast_Conversions &t_conversions) const
{
const std::vector<Type_Info> &types = get_param_types();
@@ -265,8 +174,8 @@ namespace chaiscript
}
std::vector<Type_Info> m_types;
int m_arity;
bool m_has_arithmetic_param;
};
}
@@ -287,8 +196,6 @@ namespace chaiscript
: std::runtime_error("Guard evaluation failed")
{ }
guard_error(const guard_error &) = default;
virtual ~guard_error() CHAISCRIPT_NOEXCEPT
{ }
};
@@ -307,13 +214,10 @@ namespace chaiscript
std::function<Boxed_Value (const std::vector<Boxed_Value> &)> t_f,
int t_arity=-1,
AST_NodePtr t_parsenode = AST_NodePtr(),
Param_Types t_param_types = Param_Types(),
std::string t_description = "",
Proxy_Function t_guard = Proxy_Function())
: Proxy_Function_Base(build_param_type_list(t_param_types), t_arity),
m_param_types(std::move(t_param_types)),
m_guard(std::move(t_guard)), m_parsenode(std::move(t_parsenode)), m_description(std::move(t_description)),
m_f(std::move(t_f))
: Proxy_Function_Base(build_param_type_list(t_arity)),
m_f(std::move(t_f)), m_arity(t_arity), m_description(std::move(t_description)), m_guard(std::move(t_guard)), m_parsenode(std::move(t_parsenode))
{
}
@@ -326,16 +230,19 @@ namespace chaiscript
return this == &rhs
|| (prhs
&& this->m_arity == prhs->m_arity
&& !this->m_guard && !prhs->m_guard
&& this->m_param_types == prhs->m_param_types);
&& !this->m_guard && !prhs->m_guard);
}
virtual bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
virtual bool call_match(const std::vector<Boxed_Value> &vals, const Dynamic_Cast_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
{
return (m_arity < 0 || (vals.size() == size_t(m_arity) && m_param_types.match(vals, t_conversions)))
return (m_arity < 0 || vals.size() == size_t(m_arity))
&& test_guard(vals, t_conversions);
}
}
virtual int get_arity() const CHAISCRIPT_OVERRIDE
{
return m_arity;
}
Proxy_Function get_guard() const
{
@@ -353,11 +260,12 @@ namespace chaiscript
}
protected:
virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
{
if (m_arity < 0 || params.size() == size_t(m_arity))
{
if (call_match(params, t_conversions) && test_guard(params, t_conversions))
if (test_guard(params, t_conversions))
{
return m_f(params);
} else {
@@ -370,7 +278,7 @@ namespace chaiscript
}
private:
bool test_guard(const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions) const
bool test_guard(const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions) const
{
if (m_guard)
{
@@ -386,30 +294,29 @@ namespace chaiscript
}
}
static std::vector<Type_Info> build_param_type_list(const Param_Types &t_types)
static std::vector<Type_Info> build_param_type_list(int arity)
{
std::vector<Type_Info> types;
// For the return type
types.push_back(chaiscript::detail::Get_Type_Info<Boxed_Value>::get());
for (const auto &t : t_types.types())
if (arity > 0)
{
if (t.second.is_undef()) {
for (int i = 0; i < arity; ++i)
{
types.push_back(chaiscript::detail::Get_Type_Info<Boxed_Value>::get());
} else {
types.push_back(t.second);
}
}
return types;
}
Param_Types m_param_types;
std::function<Boxed_Value (const std::vector<Boxed_Value> &)> m_f;
int m_arity;
std::string m_description;
Proxy_Function m_guard;
AST_NodePtr m_parsenode;
std::string m_description;
std::function<Boxed_Value (const std::vector<Boxed_Value> &)> m_f;
};
/**
@@ -431,8 +338,8 @@ namespace chaiscript
public:
Bound_Function(const Const_Proxy_Function &t_f,
const std::vector<Boxed_Value> &t_args)
: Proxy_Function_Base(build_param_type_info(t_f, t_args), (t_f->get_arity()<0?-1:static_cast<int>(build_param_type_info(t_f, t_args).size())-1)),
m_f(t_f), m_args(t_args)
: Proxy_Function_Base(build_param_type_info(t_f, t_args)),
m_f(t_f), m_args(t_args), m_arity(t_f->get_arity()<0?-1:static_cast<int>(get_param_types().size())-1)
{
assert(m_f->get_arity() < 0 || m_f->get_arity() == static_cast<int>(m_args.size()));
}
@@ -444,7 +351,7 @@ namespace chaiscript
virtual ~Bound_Function() {}
virtual bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
virtual bool call_match(const std::vector<Boxed_Value> &vals, const Dynamic_Cast_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
{
return m_f->call_match(build_param_list(vals), t_conversions);
}
@@ -488,6 +395,11 @@ namespace chaiscript
return args;
}
virtual int get_arity() const CHAISCRIPT_OVERRIDE
{
return m_arity;
}
virtual std::string annotation() const CHAISCRIPT_OVERRIDE
{
return "Bound: " + m_f->annotation();
@@ -517,7 +429,7 @@ namespace chaiscript
return retval;
}
virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
{
return (*m_f)(build_param_list(params), t_conversions);
}
@@ -525,24 +437,30 @@ namespace chaiscript
private:
Const_Proxy_Function m_f;
std::vector<Boxed_Value> m_args;
int m_arity;
};
class Proxy_Function_Impl_Base : public Proxy_Function_Base
{
public:
Proxy_Function_Impl_Base(const std::vector<Type_Info> &t_types)
: Proxy_Function_Base(t_types, static_cast<int>(t_types.size()) - 1)
Proxy_Function_Impl_Base(std::vector<Type_Info> t_types)
: Proxy_Function_Base(std::move(t_types))
{
}
virtual ~Proxy_Function_Impl_Base() {}
virtual int get_arity() const CHAISCRIPT_OVERRIDE
{
return static_cast<int>(m_types.size()) - 1;
}
virtual std::string annotation() const CHAISCRIPT_OVERRIDE
{
return "";
}
virtual bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
virtual bool call_match(const std::vector<Boxed_Value> &vals, const Dynamic_Cast_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
{
if (int(vals.size()) != get_arity())
{
@@ -552,7 +470,7 @@ namespace chaiscript
return compare_types(m_types, vals) || compare_types_with_cast(vals, t_conversions);
}
virtual bool compare_types_with_cast(const std::vector<Boxed_Value> &vals, const Type_Conversions &t_conversions) const = 0;
virtual bool compare_types_with_cast(const std::vector<Boxed_Value> &vals, const Dynamic_Cast_Conversions &t_conversions) const = 0;
};
/**
@@ -572,7 +490,7 @@ namespace chaiscript
virtual ~Proxy_Function_Impl() {}
virtual bool compare_types_with_cast(const std::vector<Boxed_Value> &vals, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
virtual bool compare_types_with_cast(const std::vector<Boxed_Value> &vals, const Dynamic_Cast_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
{
return detail::compare_types_cast(m_dummy_func, vals, t_conversions);
}
@@ -588,7 +506,7 @@ namespace chaiscript
}
protected:
virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions) const
virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions) const
{
return detail::Do_Call<typename std::function<Func>::result_type>::go(m_f, params, t_conversions);
}
@@ -606,8 +524,8 @@ namespace chaiscript
{
public:
Attribute_Access(T Class::* t_attr)
: Proxy_Function_Base(param_types(), 1),
m_attr(t_attr)
: Proxy_Function_Base(param_types()),
m_attr(t_attr)
{
}
@@ -625,7 +543,13 @@ namespace chaiscript
}
}
virtual bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions &) const CHAISCRIPT_OVERRIDE
virtual int get_arity() const CHAISCRIPT_OVERRIDE
{
return 1;
}
virtual bool call_match(const std::vector<Boxed_Value> &vals, const Dynamic_Cast_Conversions &) const CHAISCRIPT_OVERRIDE
{
if (vals.size() != 1)
{
@@ -641,7 +565,7 @@ namespace chaiscript
}
protected:
virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
virtual Boxed_Value do_call(const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
{
if (params.size() == 1)
{
@@ -656,7 +580,7 @@ namespace chaiscript
}
} else {
throw exception::arity_error(static_cast<int>(params.size()), 1);
}
}
}
private:
@@ -685,7 +609,6 @@ namespace chaiscript
{
}
dispatch_error(const dispatch_error &) = default;
virtual ~dispatch_error() CHAISCRIPT_NOEXCEPT {}
std::vector<Boxed_Value> parameters;
@@ -699,7 +622,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 &t_conversions)
const Dynamic_Cast_Conversions &t_conversions)
{
if (t_func->get_arity() != static_cast<int>(plist.size()))
{
@@ -727,7 +650,7 @@ namespace chaiscript
template<typename InItr>
Boxed_Value dispatch_with_conversions(InItr begin, const InItr &end, const std::vector<Boxed_Value> &plist,
const Type_Conversions &t_conversions)
const Dynamic_Cast_Conversions &t_conversions)
{
InItr orig(begin);
@@ -789,42 +712,17 @@ namespace chaiscript
* each function against the set of parameters, in order, until a matching
* function is found or throw dispatch_error if no matching function is found
*/
template<typename Funcs>
Boxed_Value dispatch(const Funcs &funcs,
const std::vector<Boxed_Value> &plist, const Type_Conversions &t_conversions)
template<typename InItr>
Boxed_Value dispatch(InItr begin, const InItr &end,
const std::vector<Boxed_Value> &plist, const Dynamic_Cast_Conversions &t_conversions)
{
std::multimap<size_t, const Proxy_Function_Base *> ordered_funcs;
for (const auto &func : funcs)
{
size_t numdiffs = 0;
const auto arity = func->get_arity();
if (arity == -1)
{
numdiffs = plist.size();
} else if (arity == static_cast<int>(plist.size())) {
for (size_t i = 0; i < plist.size(); ++i)
{
if (!func->get_param_types()[i+1].bare_equal(plist[i].get_type_info()))
{
++numdiffs;
}
}
} else {
continue;
}
ordered_funcs.insert(std::make_pair(numdiffs, func.get()));
}
for (const auto &func : ordered_funcs )
InItr orig(begin);
while (begin != end)
{
try {
if (func.second->filter(plist, t_conversions))
if ((*begin)->filter(plist, t_conversions))
{
return (*(func.second))(plist, t_conversions);
return (*(*begin))(plist, t_conversions);
}
} catch (const exception::bad_boxed_cast &) {
//parameter failed to cast, try again
@@ -834,9 +732,22 @@ namespace chaiscript
//guard failed to allow the function to execute,
//try again
}
++begin;
}
return detail::dispatch_with_conversions(funcs.cbegin(), funcs.cend(), plist, t_conversions);
return detail::dispatch_with_conversions(orig, end, plist, t_conversions);
}
/**
* Take a vector of functions and a vector of parameters. Attempt to execute
* each function against the set of parameters, in order, until a matching
* function is found or throw dispatch_error if no matching function is found
*/
template<typename Funcs>
Boxed_Value dispatch(const Funcs &funcs,
const std::vector<Boxed_Value> &plist, const Dynamic_Cast_Conversions &t_conversions)
{
return dispatch::dispatch(funcs.begin(), funcs.end(), plist, t_conversions);
}
}
}

View File

@@ -1,7 +1,7 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_PROXY_FUNCTIONS_DETAIL_HPP_
@@ -20,7 +20,7 @@
#include "type_info.hpp"
namespace chaiscript {
class Type_Conversions;
class Dynamic_Cast_Conversions;
namespace exception {
class bad_boxed_cast;
} // namespace exception
@@ -42,8 +42,6 @@ namespace chaiscript
{
}
arity_error(const arity_error &) = default;
virtual ~arity_error() CHAISCRIPT_NOEXCEPT {}
int got;
@@ -74,7 +72,7 @@ namespace chaiscript
template<typename Param, typename ... Rest>
struct Try_Cast<Param, Rest...>
{
static void do_try(const std::vector<Boxed_Value> &params, size_t generation, const Type_Conversions &t_conversions)
static void do_try(const std::vector<Boxed_Value> &params, int generation, const Dynamic_Cast_Conversions &t_conversions)
{
boxed_cast<Param>(params[generation], &t_conversions);
Try_Cast<Rest...>::do_try(params, generation+1, t_conversions);
@@ -85,7 +83,7 @@ namespace chaiscript
template<>
struct Try_Cast<>
{
static void do_try(const std::vector<Boxed_Value> &, size_t, const Type_Conversions &)
static void do_try(const std::vector<Boxed_Value> &, int, const Dynamic_Cast_Conversions &)
{
}
};
@@ -98,7 +96,7 @@ namespace chaiscript
*/
template<typename Ret, typename ... Params>
bool compare_types_cast(Ret (*)(Params...),
const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions)
const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions)
{
try {
Try_Cast<Params...>::do_try(params, 0, t_conversions);
@@ -115,7 +113,7 @@ namespace chaiscript
template<typename ... InnerParams>
static Ret do_call(const std::function<Ret (Params...)> &f,
const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions, InnerParams &&... innerparams)
const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions, InnerParams &&... innerparams)
{
return Call_Func<Ret, count - 1, Params...>::do_call(f, params, t_conversions, std::forward<InnerParams>(innerparams)..., params[sizeof...(Params) - count]);
}
@@ -130,7 +128,7 @@ namespace chaiscript
#endif
template<typename ... InnerParams>
static Ret do_call(const std::function<Ret (Params...)> &f,
const std::vector<Boxed_Value> &, const Type_Conversions &t_conversions, InnerParams &&... innerparams)
const std::vector<Boxed_Value> &, const Dynamic_Cast_Conversions &t_conversions, InnerParams &&... innerparams)
{
return f(boxed_cast<Params>(std::forward<InnerParams>(innerparams), &t_conversions)...);
}
@@ -147,7 +145,7 @@ namespace chaiscript
*/
template<typename Ret, typename ... Params>
Ret call_func(const std::function<Ret (Params...)> &f,
const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions)
const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions)
{
if (params.size() == sizeof...(Params))
{
@@ -173,7 +171,7 @@ namespace chaiscript
struct Do_Call
{
template<typename Fun>
static Boxed_Value go(const std::function<Fun> &fun, const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions)
static Boxed_Value go(const std::function<Fun> &fun, const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions)
{
return Handle_Return<Ret>::handle(call_func(fun, params, t_conversions));
}
@@ -183,7 +181,7 @@ namespace chaiscript
struct Do_Call<void>
{
template<typename Fun>
static Boxed_Value go(const std::function<Fun> &fun, const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions)
static Boxed_Value go(const std::function<Fun> &fun, const std::vector<Boxed_Value> &params, const Dynamic_Cast_Conversions &t_conversions)
{
call_func(fun, params, t_conversions);
return Handle_Return<void>::handle();

View File

@@ -1,7 +1,7 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_REGISTER_FUNCTION_HPP_

View File

@@ -1,453 +0,0 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_DYNAMIC_CAST_CONVERSION_HPP_
#define CHAISCRIPT_DYNAMIC_CAST_CONVERSION_HPP_
#include <atomic>
#include <memory>
#include <set>
#include <stdexcept>
#include <string>
#include <type_traits>
#include <typeinfo>
#include "../chaiscript_threading.hpp"
#include "bad_boxed_cast.hpp"
#include "boxed_cast_helper.hpp"
#include "boxed_value.hpp"
#include "type_info.hpp"
namespace chaiscript
{
namespace exception
{
class bad_boxed_dynamic_cast : public bad_boxed_cast
{
public:
bad_boxed_dynamic_cast(const Type_Info &t_from, const std::type_info &t_to,
const std::string &t_what) CHAISCRIPT_NOEXCEPT
: bad_boxed_cast(t_from, t_to, t_what)
{
}
bad_boxed_dynamic_cast(const Type_Info &t_from, const std::type_info &t_to) CHAISCRIPT_NOEXCEPT
: bad_boxed_cast(t_from, t_to)
{
}
bad_boxed_dynamic_cast(const std::string &w) CHAISCRIPT_NOEXCEPT
: bad_boxed_cast(w)
{
}
bad_boxed_dynamic_cast(const bad_boxed_dynamic_cast &) = default;
virtual ~bad_boxed_dynamic_cast() CHAISCRIPT_NOEXCEPT {}
};
class bad_boxed_type_cast : public bad_boxed_cast
{
public:
bad_boxed_type_cast(const Type_Info &t_from, const std::type_info &t_to,
const std::string &t_what) CHAISCRIPT_NOEXCEPT
: bad_boxed_cast(t_from, t_to, t_what)
{
}
bad_boxed_type_cast(const Type_Info &t_from, const std::type_info &t_to) CHAISCRIPT_NOEXCEPT
: bad_boxed_cast(t_from, t_to)
{
}
bad_boxed_type_cast(const std::string &w) CHAISCRIPT_NOEXCEPT
: bad_boxed_cast(w)
{
}
bad_boxed_type_cast(const bad_boxed_type_cast &) = default;
virtual ~bad_boxed_type_cast() CHAISCRIPT_NOEXCEPT {}
};
}
namespace detail
{
class Type_Conversion_Base
{
public:
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
{
return m_to;
}
const Type_Info &from() const
{
return m_from;
}
protected:
Type_Conversion_Base(const Type_Info &t_to, const Type_Info &t_from)
: m_to(t_to), m_from(t_from)
{
}
virtual ~Type_Conversion_Base() {}
private:
Type_Info m_to;
Type_Info m_from;
};
template<typename From, typename To>
class Dynamic_Caster
{
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())
{
// Dynamic cast out the contained boxed value, which we know is the type we want
if (t_from.is_const())
{
std::shared_ptr<const To> data
= std::dynamic_pointer_cast<const To>(detail::Cast_Helper<std::shared_ptr<const From> >::cast(t_from, nullptr));
if (!data)
{
throw std::bad_cast();
}
return Boxed_Value(data);
} else {
std::shared_ptr<To> data
= std::dynamic_pointer_cast<To>(detail::Cast_Helper<std::shared_ptr<From> >::cast(t_from, nullptr));
if (!data)
{
throw std::bad_cast();
}
return Boxed_Value(data);
}
} else {
// Pull the reference out of the contained boxed value, which we know is the type we want
if (t_from.is_const())
{
const From &d = detail::Cast_Helper<const From &>::cast(t_from, nullptr);
const To &data = dynamic_cast<const To &>(d);
return Boxed_Value(std::cref(data));
} else {
From &d = detail::Cast_Helper<From &>::cast(t_from, nullptr);
To &data = dynamic_cast<To &>(d);
return Boxed_Value(std::ref(data));
}
}
} else {
throw chaiscript::exception::bad_boxed_dynamic_cast(t_from.get_type_info(), typeid(To), "Unknown dynamic_cast_conversion");
}
}
};
template<typename Base, typename Derived>
class Dynamic_Conversion_Impl : public Type_Conversion_Base
{
public:
Dynamic_Conversion_Impl()
: Type_Conversion_Base(chaiscript::user_type<Base>(), chaiscript::user_type<Derived>())
{
}
virtual Boxed_Value convert_down(const Boxed_Value &t_base) const CHAISCRIPT_OVERRIDE
{
return Dynamic_Caster<Base, Derived>::cast(t_base);
}
virtual Boxed_Value convert(const Boxed_Value &t_derived) const CHAISCRIPT_OVERRIDE
{
return Dynamic_Caster<Derived, Base>::cast(t_derived);
}
};
template<typename Callable>
class Type_Conversion_Impl : public Type_Conversion_Base
{
public:
Type_Conversion_Impl(Type_Info t_from, Type_Info t_to, Callable t_func)
: Type_Conversion_Base(std::move(t_to), std::move(t_from)),
m_func(std::move(t_func))
{
}
virtual Boxed_Value convert_down(const Boxed_Value &) const CHAISCRIPT_OVERRIDE
{
throw chaiscript::exception::bad_boxed_type_cast("No conversion exists");
}
virtual Boxed_Value convert(const Boxed_Value &t_from) const CHAISCRIPT_OVERRIDE
{
/// \todo better handling of errors from the conversion function
return m_func(t_from);
}
private:
Callable m_func;
};
}
class Type_Conversions
{
public:
struct Less_Than
{
bool operator()(const std::type_info *t_lhs, const std::type_info *t_rhs) const
{
return *t_lhs != *t_rhs && t_lhs->before(*t_rhs);
}
};
Type_Conversions()
: m_mutex(),
m_conversions(),
m_convertableTypes(),
m_num_types(0),
m_thread_cache(this),
m_conversion_saves(this)
{
}
Type_Conversions(const Type_Conversions &t_other)
: m_mutex(),
m_conversions(t_other.get_conversions()),
m_convertableTypes(),
m_num_types(m_conversions.size()),
m_thread_cache(this),
m_conversion_saves(this)
{
}
const std::set<const std::type_info *, Less_Than> &thread_cache() const
{
auto &cache = *m_thread_cache;
if (cache.size() != m_num_types)
{
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
cache = m_convertableTypes;
}
return cache;
}
void add_conversion(const std::shared_ptr<detail::Type_Conversion_Base> &conversion)
{
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
/// \todo error if a conversion already exists
m_conversions.insert(conversion);
m_convertableTypes.insert({conversion->to().bare_type_info(), conversion->from().bare_type_info()});
m_num_types = m_convertableTypes.size();
}
template<typename T>
bool convertable_type() const
{
return thread_cache().count(user_type<T>().bare_type_info()) != 0;
}
template<typename To, typename From>
bool converts() const
{
return converts(user_type<To>(), user_type<From>());
}
bool converts(const Type_Info &to, const Type_Info &from) const
{
const auto &types = thread_cache();
if (types.count(to.bare_type_info()) != 0 && types.count(from.bare_type_info()) != 0)
{
return has_conversion(to, from) || has_conversion(from, to);
} else {
return false;
}
}
template<typename To>
Boxed_Value boxed_type_conversion(const Boxed_Value &from) const
{
try {
Boxed_Value ret = get_conversion(user_type<To>(), from.get_type_info())->convert(from);
if (m_conversion_saves->enabled) m_conversion_saves->saves.push_back(ret);
return ret;
} catch (const std::out_of_range &) {
throw exception::bad_boxed_dynamic_cast(from.get_type_info(), typeid(To), "No known conversion");
} catch (const std::bad_cast &) {
throw exception::bad_boxed_dynamic_cast(from.get_type_info(), typeid(To), "Unable to perform dynamic_cast operation");
}
}
template<typename From>
Boxed_Value boxed_type_down_conversion(const Boxed_Value &to) const
{
try {
Boxed_Value ret = get_conversion(to.get_type_info(), user_type<From>())->convert_down(to);
if (m_conversion_saves->enabled) m_conversion_saves->saves.push_back(ret);
return ret;
} catch (const std::out_of_range &) {
throw exception::bad_boxed_dynamic_cast(to.get_type_info(), typeid(From), "No known conversion");
} catch (const std::bad_cast &) {
throw exception::bad_boxed_dynamic_cast(to.get_type_info(), typeid(From), "Unable to perform dynamic_cast operation");
}
}
void enable_conversion_saves(bool t_val)
{
m_conversion_saves->enabled = t_val;
}
std::vector<Boxed_Value> take_saves()
{
std::vector<Boxed_Value> ret;
std::swap(ret, m_conversion_saves->saves);
return ret;
}
bool has_conversion(const Type_Info &to, const Type_Info &from) const
{
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
return find(to, from) != m_conversions.end();
}
std::shared_ptr<detail::Type_Conversion_Base> get_conversion(const Type_Info &to, const Type_Info &from) const
{
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
auto itr = find(to, from);
if (itr != m_conversions.end())
{
return *itr;
} else {
throw std::out_of_range("No such conversion exists from " + from.bare_name() + " to " + to.bare_name());
}
}
private:
std::set<std::shared_ptr<detail::Type_Conversion_Base> >::const_iterator find(
const Type_Info &to, const Type_Info &from) const
{
return std::find_if(m_conversions.begin(), m_conversions.end(),
[&to, &from](const std::shared_ptr<detail::Type_Conversion_Base> &conversion)
{
return conversion->to().bare_equal(to) && conversion->from().bare_equal(from);
}
);
}
std::set<std::shared_ptr<detail::Type_Conversion_Base>> get_conversions() const
{
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
return m_conversions;
}
struct Conversion_Saves
{
Conversion_Saves()
: enabled(false)
{}
bool enabled;
std::vector<Boxed_Value> saves;
};
mutable chaiscript::detail::threading::shared_mutex m_mutex;
std::set<std::shared_ptr<detail::Type_Conversion_Base>> m_conversions;
std::set<const std::type_info *, Less_Than> m_convertableTypes;
std::atomic_size_t m_num_types;
mutable chaiscript::detail::threading::Thread_Storage<std::set<const std::type_info *, Less_Than>> m_thread_cache;
mutable chaiscript::detail::threading::Thread_Storage<Conversion_Saves> m_conversion_saves;
};
typedef std::shared_ptr<chaiscript::detail::Type_Conversion_Base> Type_Conversion;
/// \brief Used to register a to / parent class relationship with ChaiScript. Necessary if you
/// want automatic conversions up your inheritance hierarchy.
///
/// Create a new to class registration for applying to a module or to the ChaiScript engine
/// Currently, due to limitations in module loading on Windows, and for the sake of portability,
/// if you have a type that is introduced in a loadable module and is used by multiple modules
/// (through a tertiary dll that is shared between the modules, static linking the new type
/// into both loadable modules would not be portable), you need to register the type
/// relationship in all modules that use the newly added type in a polymorphic way.
///
/// Example:
/// \code
/// class Base
/// {};
/// class Derived : public Base
/// {};
///
/// chaiscript::ChaiScript chai;
/// chai.add(chaiscript::to_class<Base, Derived>());
/// \endcode
///
template<typename Base, typename Derived>
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");
static_assert(std::is_polymorphic<Base>::value, "Base class must be polymorphic");
static_assert(std::is_polymorphic<Derived>::value, "Derived class must be polymorphic");
return std::make_shared<detail::Dynamic_Conversion_Impl<Base, Derived>>();
}
template<typename Callable>
Type_Conversion type_conversion(const Type_Info &t_from, const Type_Info &t_to,
const Callable &t_func)
{
return std::make_shared<detail::Type_Conversion_Impl<Callable>>(t_from, t_to, t_func);
}
template<typename From, typename To, typename Callable>
Type_Conversion type_conversion(const Callable &t_function)
{
auto func = [t_function](const Boxed_Value &t_bv) -> Boxed_Value {
// not even attempting to call boxed_cast so that we don't get caught in some call recursion
return chaiscript::Boxed_Value(t_function(detail::Cast_Helper<const From &>::cast(t_bv, nullptr)));
};
return std::make_shared<detail::Type_Conversion_Impl<decltype(func)>>(user_type<From>(), user_type<To>(), func);
}
template<typename From, typename To>
Type_Conversion type_conversion()
{
static_assert(std::is_convertible<From, To>::value, "Types are not automatically convertible");
auto func = [](const Boxed_Value &t_bv) -> Boxed_Value {
// not even attempting to call boxed_cast so that we don't get caught in some call recursion
auto &&from = detail::Cast_Helper<From>::cast(t_bv, nullptr);
To to(from);
return chaiscript::Boxed_Value(to);
};
return std::make_shared<detail::Type_Conversion_Impl<decltype(func)>>(user_type<From>(), user_type<To>(), func);
}
}
#endif

View File

@@ -1,7 +1,7 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_TYPE_INFO_HPP_
@@ -111,11 +111,6 @@ namespace chaiscript
}
}
CHAISCRIPT_CONSTEXPR const std::type_info *bare_type_info() const
{
return m_bare_type_info;
}
private:
const std::type_info *m_type_info;
const std::type_info *m_bare_type_info;

View File

@@ -1,7 +1,7 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_ALGEBRAIC_HPP_

View File

@@ -1,7 +1,7 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_COMMON_HPP_
@@ -37,7 +37,7 @@ namespace chaiscript
Comparison, Addition, Subtraction, Multiplication, Division, Modulus, Array_Call, Dot_Access, Quoted_String, Single_Quoted_String,
Lambda, Block, Def, While, If, For, Inline_Array, Inline_Map, Return, File, Prefix, Break, Continue, Map_Pair, Value_Range,
Inline_Range, Annotation, Try, Catch, Finally, Method, Attr_Decl, Shift, Equality, Bitwise_And, Bitwise_Xor, Bitwise_Or,
Logical_And, Logical_Or, Reference, Switch, Case, Default, Ternary_Cond, Noop, Class, Binary, Arg
Logical_And, Logical_Or, Reference, Switch, Case, Default, Ternary_Cond, Noop, Class
};
};
@@ -50,7 +50,7 @@ namespace chaiscript
"Comparison", "Addition", "Subtraction", "Multiplication", "Division", "Modulus", "Array_Call", "Dot_Access", "Quoted_String", "Single_Quoted_String",
"Lambda", "Block", "Def", "While", "If", "For", "Inline_Array", "Inline_Map", "Return", "File", "Prefix", "Break", "Continue", "Map_Pair", "Value_Range",
"Inline_Range", "Annotation", "Try", "Catch", "Finally", "Method", "Attr_Decl", "Shift", "Equality", "Bitwise_And", "Bitwise_Xor", "Bitwise_Or",
"Logical_And", "Logical_Or", "Reference", "Switch", "Case", "Default", "Ternary Condition", "Noop", "Class", "Binary", "Arg"};
"Logical_And", "Logical_Or", "Reference", "Switch", "Case", "Default", "Ternary Condition", "Noop"};
return ast_node_types[ast_node_type];
}
@@ -112,27 +112,25 @@ namespace chaiscript
reason(t_why)
{}
eval_error(const eval_error &) = default;
std::string pretty_print() const
{
std::ostringstream ss;
ss << what();
if (call_stack.size() > 0) {
ss << "during evaluation at (" << fname(call_stack[0]) << " " << startpos(call_stack[0]) << ")\n";
ss << '\n' << detail << '\n';
ss << "during evaluation at (" << fname(call_stack[0]) << " " << startpos(call_stack[0]) << ")" << std::endl;
ss << std::endl << detail << std::endl;
ss << " " << fname(call_stack[0]) << " (" << startpos(call_stack[0]) << ") '" << pretty(call_stack[0]) << "'";
for (size_t j = 1; j < call_stack.size(); ++j) {
if (id(call_stack[j]) != chaiscript::AST_Node_Type::Block
&& id(call_stack[j]) != chaiscript::AST_Node_Type::File)
{
ss << '\n';
ss << std::endl;
ss << " from " << fname(call_stack[j]) << " (" << startpos(call_stack[j]) << ") '" << pretty(call_stack[j]) << "'";
}
}
}
ss << '\n';
ss << std::endl;
return ss.str();
}
@@ -266,13 +264,13 @@ namespace chaiscript
std::stringstream ss;
if (t_functions.size() == 1)
{
ss << " Expected: " << format_types(t_functions[0], t_dot_notation, t_ss) << '\n';
ss << " Expected: " << format_types(t_functions[0], t_dot_notation, t_ss) << std::endl;
} else {
ss << " " << t_functions.size() << " overloads available:\n";
ss << " " << t_functions.size() << " overloads available:" << std::endl;
for (const auto & t_function : t_functions)
{
ss << " " << format_types((t_function), t_dot_notation, t_ss) << '\n';
ss << " " << format_types((t_function), t_dot_notation, t_ss) << std::endl;
}
}
@@ -397,7 +395,6 @@ namespace chaiscript
: std::runtime_error("File Not Found: " + t_filename)
{ }
file_not_found_error(const file_not_found_error &) = default;
virtual ~file_not_found_error() CHAISCRIPT_NOEXCEPT {}
};
@@ -433,7 +430,7 @@ namespace chaiscript
std::ostringstream oss;
oss << t_prepend << "(" << ast_node_type_to_string(this->identifier) << ") "
<< this->text << " : " << this->start.line << ", " << this->start.column << '\n';
<< this->text << " : " << this->start.line << ", " << this->start.column << std::endl;
for (size_t j = 0; j < this->children.size(); ++j) {
oss << this->children[j]->to_string(t_prepend + " ");
@@ -552,11 +549,6 @@ namespace chaiscript
m_de.save_function_params(t_params);
}
void save_params(std::initializer_list<Boxed_Value> t_params)
{
m_de.save_function_params(std::move(t_params));
}
private:

View File

@@ -1,7 +1,7 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_ENGINE_HPP_
@@ -26,7 +26,7 @@
#include "../dispatchkit/boxed_cast_helper.hpp"
#include "../dispatchkit/boxed_value.hpp"
#include "../dispatchkit/dispatchkit.hpp"
#include "../dispatchkit/type_conversions.hpp"
#include "../dispatchkit/dynamic_cast_conversion.hpp"
#include "../dispatchkit/proxy_functions.hpp"
#include "chaiscript_common.hpp"
@@ -61,8 +61,9 @@ namespace chaiscript
{
}
load_module_error(const load_module_error &) = default;
virtual ~load_module_error() CHAISCRIPT_NOEXCEPT {}
virtual ~load_module_error() CHAISCRIPT_NOEXCEPT
{
}
};
}
@@ -352,13 +353,6 @@ namespace chaiscript
m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::get_type_name, std::ref(m_engine)), "name");
m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::get_type, std::ref(m_engine)), "type");
m_engine.add(fun<void (const Type_Info &, const Type_Info &, const std::function<Boxed_Value (const Boxed_Value &)> &)> (
[=](const Type_Info &t_from, const Type_Info &t_to, const std::function<Boxed_Value (const Boxed_Value &)> &t_func) {
m_engine.add(chaiscript::type_conversion(t_from, t_to, t_func));
}
), "add_type_conversion");
typedef std::string (ChaiScript::*load_mod_1)(const std::string&);
typedef void (ChaiScript::*load_mod_2)(const std::string&, const std::string&);
@@ -370,10 +364,10 @@ namespace chaiscript
m_engine.add(fun(&ChaiScript::internal_eval, this), "eval");
m_engine.add(fun(&ChaiScript::internal_eval_ast, this), "eval");
m_engine.add(fun(&ChaiScript::version_major), "version_major");
m_engine.add(fun(&ChaiScript::version_minor), "version_minor");
m_engine.add(fun(&ChaiScript::version_patch), "version_patch");
m_engine.add(fun(&ChaiScript::version), "version");
m_engine.add(fun(&ChaiScript::version_major, this), "version_major");
m_engine.add(fun(&ChaiScript::version_minor, this), "version_minor");
m_engine.add(fun(&ChaiScript::version_patch, this), "version_patch");
m_engine.add(fun(&ChaiScript::version, this), "version");
m_engine.add(fun(&ChaiScript::add_global_const, this), "add_global_const");
m_engine.add(fun(&ChaiScript::add_global, this), "add_global");
@@ -463,7 +457,7 @@ namespace chaiscript
memset( &rInfo, 0, sizeof(rInfo) );
cast_union u;
u.in_ptr = &ChaiScript::use;
if ( dladdr(static_cast<void*>(u.out_ptr), &rInfo) && rInfo.dli_fname ) {
if ( dladdr((void*)(u.out_ptr), &rInfo) && rInfo.dli_fname ) {
std::string dllpath(rInfo.dli_fname);
const size_t lastslash = dllpath.rfind('/');
if (lastslash != std::string::npos)
@@ -490,22 +484,22 @@ namespace chaiscript
build_eval_system(ModulePtr());
}
static int version_major()
int version_major() const
{
return chaiscript::version_major;
}
static int version_minor()
int version_minor() const
{
return chaiscript::version_minor;
}
static int version_patch()
int version_patch() const
{
return chaiscript::version_patch;
}
static std::string version()
std::string version() const
{
std::stringstream ss;
ss << version_major() << "." << version_minor() << "." << version_patch();
@@ -580,8 +574,6 @@ namespace chaiscript
}
/// \brief Represents the current state of the ChaiScript system. State and be saved and restored
/// \warning State object does not contain the user defined type conversions of the engine. They
/// are left out due to performance considerations involved in tracking the state
/// \sa ChaiScript::get_state
/// \sa ChaiScript::set_state
struct State
@@ -604,7 +596,7 @@ namespace chaiscript
/// chaiscript::ChaiScript chai;
/// chaiscript::ChaiScript::State s = chai.get_state(); // represents bootstrapped initial state
/// \endcode
State get_state() const
State get_state()
{
chaiscript::detail::threading::lock_guard<chaiscript::detail::threading::recursive_mutex> l(m_use_mutex);
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l2(m_mutex);
@@ -687,7 +679,7 @@ namespace chaiscript
/// chaiscript::ChaiScript chai;
/// chai.add(chaiscript::base_class<std::runtime_error, chaiscript::dispatch_error>());
/// \endcode
ChaiScript &add(const Type_Conversion &d)
ChaiScript &add(const Dynamic_Cast_Conversion &d)
{
m_engine.add(d);
return *this;
@@ -707,7 +699,7 @@ namespace chaiscript
/// \param[in] t_module_name Name of the module to load
///
/// The module is searched for in the registered module path folders (chaiscript::ChaiScript::ChaiScript)
/// and with standard prefixes and postfixes: ("lib"|"")\<t_module_name\>(".dll"|".so"|".bundle"|"").
/// and with standard prefixes and postfixes: ("lib"|"")\<t_module_name\>(".dll"|".so"|"").
///
/// Once the file is located, the system looks for the symbol "create_chaiscript_module_\<t_module_name\>".
/// If no file can be found matching the search criteria and containing the appropriate entry point
@@ -726,7 +718,7 @@ namespace chaiscript
std::vector<std::string> prefixes{"lib", "cyg", ""};
std::vector<std::string> postfixes{".dll", ".so", ".bundle", ""};
std::vector<std::string> postfixes{".dll", ".so", ""};
for (auto & elem : m_modulepaths)
{
@@ -736,11 +728,11 @@ namespace chaiscript
{
try {
const auto name = elem + prefix + t_module_name + postfix;
// std::cerr << "trying location: " << name << '\n';
// std::cerr << "trying location: " << name << std::endl;
load_module(version_stripped_name, name);
return name;
} catch (const chaiscript::exception::load_module_error &e) {
// std::cerr << "error: " << e.what() << '\n';
// std::cerr << "error: " << e.what() << std::endl;
errors.push_back(e);
// Try next set
}

View File

@@ -1,7 +1,7 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_EVAL_HPP_
@@ -25,7 +25,6 @@
#include "../dispatchkit/boxed_number.hpp"
#include "../dispatchkit/boxed_value.hpp"
#include "../dispatchkit/dispatchkit.hpp"
#include "../dispatchkit/dynamic_object_detail.hpp"
#include "../dispatchkit/proxy_functions.hpp"
#include "../dispatchkit/proxy_functions_detail.hpp"
#include "../dispatchkit/register_function.hpp"
@@ -64,21 +63,25 @@ namespace chaiscript
struct Binary_Operator_AST_Node : public AST_Node {
public:
Binary_Operator_AST_Node(const std::string &t_oper) :
AST_Node(t_oper, AST_Node_Type::Binary, std::make_shared<std::string>(""), 0, 0, 0, 0),
m_oper(Operators::to_operator(t_oper))
Binary_Operator_AST_Node(std::string t_ast_node_text, int t_id, const std::shared_ptr<std::string> &t_fname, int t_start_line, int t_start_col, int t_end_line, int t_end_col) :
AST_Node(std::move(t_ast_node_text), t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col)
{ }
virtual ~Binary_Operator_AST_Node() {}
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE {
return do_oper(t_ss, m_oper, text,
return do_oper(t_ss, Operators::to_operator(children[1]->text), children[1]->text,
this->children[0]->eval(t_ss),
this->children[1]->eval(t_ss));
this->children[2]->eval(t_ss));
}
virtual std::string pretty_print() const CHAISCRIPT_OVERRIDE
{
return "(" + this->children[0]->pretty_print() + " " + text + " " + this->children[1]->pretty_print() + ")";
if (children.size() == 3)
{
return "(" + this->children[0]->pretty_print() + " " + this->children[1]->text + " " + this->children[2]->pretty_print() + ")";
} else {
return "(" + this->children[0]->pretty_print() + " " + text + " " + this->children[1]->pretty_print() + ")";
}
}
protected:
@@ -94,8 +97,6 @@ namespace chaiscript
// If it's an arithmetic operation we want to short circuit dispatch
try{
return Boxed_Number::do_oper(t_oper, t_lhs, t_rhs);
} catch (const chaiscript::exception::arithmetic_error &) {
throw;
} catch (...) {
throw exception::eval_error("Error with numeric operator calling: " + t_oper_string);
}
@@ -109,9 +110,6 @@ namespace chaiscript
throw exception::eval_error("Can not find appropriate '" + t_oper_string + "' operator.", e.parameters, e.functions, false, t_ss);
}
}
private:
Operators::Opers m_oper;
};
struct Int_AST_Node : public AST_Node {
@@ -294,7 +292,6 @@ namespace chaiscript
virtual ~Inplace_Fun_Call_AST_Node() {}
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE{
std::vector<Boxed_Value> params;
chaiscript::eval::detail::Function_Push_Pop fpp(t_ss);
if ((this->children.size() > 1) && (this->children[1]->identifier == AST_Node_Type::Arg_List)) {
for (const auto &child : this->children[1]->children) {
@@ -318,6 +315,8 @@ namespace chaiscript
}
catch(const exception::bad_boxed_cast &){
// handle the case where there is only 1 function to try to call and dispatch fails on it
std::vector<Const_Proxy_Function> funcs;
funcs.push_back(fn);
throw exception::eval_error("Error calling function '" + this->children[0]->text + "'", params, {fn}, false, t_ss);
}
catch(const exception::arity_error &e){
@@ -352,28 +351,6 @@ namespace chaiscript
};
struct Arg_AST_Node : public AST_Node {
public:
Arg_AST_Node(std::string t_ast_node_text = "", const std::shared_ptr<std::string> &t_fname=std::shared_ptr<std::string>(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) :
AST_Node(std::move(t_ast_node_text), AST_Node_Type::Arg_List, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { }
virtual ~Arg_AST_Node() {}
virtual std::string pretty_print() const CHAISCRIPT_OVERRIDE
{
std::ostringstream oss;
for (size_t j = 0; j < this->children.size(); ++j) {
if (j != 0)
{
oss << " ";
}
oss << this->children[j]->pretty_print();
}
return oss.str();
}
};
struct Arg_List_AST_Node : public AST_Node {
public:
Arg_List_AST_Node(std::string t_ast_node_text = "", const std::shared_ptr<std::string> &t_fname=std::shared_ptr<std::string>(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) :
@@ -394,53 +371,6 @@ namespace chaiscript
return oss.str();
}
static std::string get_arg_name(const AST_NodePtr &t_node) {
if (t_node->children.empty())
{
return t_node->text;
} else if (t_node->children.size() == 1) {
return t_node->children[0]->text;
} else {
return t_node->children[1]->text;
}
}
static std::vector<std::string> get_arg_names(const AST_NodePtr &t_node) {
std::vector<std::string> retval;
for (const auto &node : t_node->children)
{
retval.push_back(get_arg_name(node));
}
return retval;
}
static std::pair<std::string, Type_Info> get_arg_type(const AST_NodePtr &t_node, chaiscript::detail::Dispatch_Engine &t_ss)
{
if (t_node->children.size() < 2)
{
return std::pair<std::string, Type_Info>();
} else {
try {
return std::pair<std::string, Type_Info>(t_node->children[0]->text, t_ss.get_type(t_node->children[0]->text));
} catch (const std::range_error &) {
return std::pair<std::string, Type_Info>(t_node->children[0]->text, Type_Info());
}
}
}
static dispatch::Param_Types get_arg_types(const AST_NodePtr &t_node, chaiscript::detail::Dispatch_Engine &t_ss) {
std::vector<std::pair<std::string, Type_Info>> retval;
for (const auto &child : t_node->children)
{
retval.push_back(get_arg_type(child, t_ss));
}
return dispatch::Param_Types(std::move(retval));
}
};
struct Equation_AST_Node : public AST_Node {
@@ -451,7 +381,6 @@ namespace chaiscript
virtual ~Equation_AST_Node() {}
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE {
chaiscript::eval::detail::Function_Push_Pop fpp(t_ss);
Boxed_Value retval = this->children.back()->eval(t_ss);
@@ -524,7 +453,7 @@ namespace chaiscript
{
return this->children[0]->eval(t_ss);
} else {
const std::string &idname = this->children[0]->text;
std::string idname = this->children[0]->text;
Boxed_Value bv;
try {
@@ -547,6 +476,72 @@ namespace chaiscript
};
struct Comparison_AST_Node : public Binary_Operator_AST_Node {
public:
Comparison_AST_Node(std::string t_ast_node_text = "", const std::shared_ptr<std::string> &t_fname=std::shared_ptr<std::string>(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) :
Binary_Operator_AST_Node(std::move(t_ast_node_text), AST_Node_Type::Comparison, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { }
virtual ~Comparison_AST_Node() {}
};
struct Addition_AST_Node : public Binary_Operator_AST_Node {
public:
Addition_AST_Node(std::string t_ast_node_text = "+",
const std::shared_ptr<std::string> &t_fname=std::shared_ptr<std::string>(),
int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) :
Binary_Operator_AST_Node(std::move(t_ast_node_text), AST_Node_Type::Addition, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { }
virtual ~Addition_AST_Node() {}
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE {
return do_oper(t_ss, Operators::sum, "+", this->children[0]->eval(t_ss), this->children[1]->eval(t_ss));
}
};
struct Subtraction_AST_Node : public Binary_Operator_AST_Node {
public:
Subtraction_AST_Node(std::string t_ast_node_text = "-",
const std::shared_ptr<std::string> &t_fname=std::shared_ptr<std::string>(), int t_start_line = 0,
int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) :
Binary_Operator_AST_Node(std::move(t_ast_node_text), AST_Node_Type::Subtraction, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { }
virtual ~Subtraction_AST_Node() {}
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE {
return do_oper(t_ss, Operators::difference, "-", this->children[0]->eval(t_ss), this->children[1]->eval(t_ss));
}
};
struct Multiplication_AST_Node : public Binary_Operator_AST_Node {
public:
Multiplication_AST_Node(std::string t_ast_node_text = "*",
const std::shared_ptr<std::string> &t_fname=std::shared_ptr<std::string>(), int t_start_line = 0,
int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) :
Binary_Operator_AST_Node(std::move(t_ast_node_text), AST_Node_Type::Multiplication, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { }
virtual ~Multiplication_AST_Node() {}
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE {
return do_oper(t_ss, Operators::product, "*", this->children[0]->eval(t_ss), this->children[1]->eval(t_ss));
}
};
struct Division_AST_Node : public Binary_Operator_AST_Node {
public:
Division_AST_Node(std::string t_ast_node_text = "/",
const std::shared_ptr<std::string> &t_fname=std::shared_ptr<std::string>(), int t_start_line = 0,
int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) :
Binary_Operator_AST_Node(std::move(t_ast_node_text), AST_Node_Type::Division, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { }
virtual ~Division_AST_Node() {}
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE {
return do_oper(t_ss, Operators::quotient, "/", this->children[0]->eval(t_ss), this->children[1]->eval(t_ss));
}
};
struct Modulus_AST_Node : public Binary_Operator_AST_Node {
public:
Modulus_AST_Node(std::string t_ast_node_text = "%",
const std::shared_ptr<std::string> &t_fname=std::shared_ptr<std::string>(), int t_start_line = 0,
int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) :
Binary_Operator_AST_Node(std::move(t_ast_node_text), AST_Node_Type::Modulus, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { }
virtual ~Modulus_AST_Node() {}
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE {
return do_oper(t_ss, Operators::remainder, "%", this->children[0]->eval(t_ss), this->children[1]->eval(t_ss));
}
};
struct Array_Call_AST_Node : public AST_Node {
public:
@@ -599,11 +594,11 @@ namespace chaiscript
AST_Node(t_ast_node_text, AST_Node_Type::Dot_Access, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { }
virtual ~Dot_Access_AST_Node() {}
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE{
chaiscript::eval::detail::Function_Push_Pop fpp(t_ss);
Boxed_Value retval = this->children[0]->eval(t_ss);
if (this->children.size() > 1) {
for (size_t i = 2; i < this->children.size(); i+=2) {
chaiscript::eval::detail::Function_Push_Pop fpp(t_ss);
std::vector<Boxed_Value> params{retval};
if (this->children[i]->children.size() > 1) {
@@ -708,12 +703,13 @@ namespace chaiscript
size_t numparams = 0;
dispatch::Param_Types param_types;
if (!this->children.empty() && (this->children[0]->identifier == AST_Node_Type::Arg_List)) {
numparams = this->children[0]->children.size();
t_param_names = Arg_List_AST_Node::get_arg_names(this->children[0]);
param_types = Arg_List_AST_Node::get_arg_types(this->children[0], t_ss);
for (const auto &child : this->children[0]->children)
{
t_param_names.push_back(child->text);
}
}
const auto &lambda_node = this->children.back();
@@ -723,7 +719,7 @@ namespace chaiscript
{
return detail::eval_function(t_ss, lambda_node, t_param_names, t_params);
},
static_cast<int>(numparams), lambda_node, param_types)));
static_cast<int>(numparams), lambda_node)));
}
};
@@ -767,12 +763,13 @@ namespace chaiscript
size_t numparams = 0;
AST_NodePtr guardnode;
dispatch::Param_Types param_types;
if ((this->children.size() > 2) && (this->children[1]->identifier == AST_Node_Type::Arg_List)) {
numparams = this->children[1]->children.size();
t_param_names = Arg_List_AST_Node::get_arg_names(this->children[1]);
param_types = Arg_List_AST_Node::get_arg_types(this->children[1], t_ss);
for (const auto &child : this->children[1]->children)
{
t_param_names.push_back(child->text);
}
if (this->children.size() > 3) {
guardnode = this->children[2];
@@ -805,7 +802,7 @@ namespace chaiscript
{
return detail::eval_function(t_ss, func_node, t_param_names, t_params);
}, static_cast<int>(numparams), this->children.back(),
param_types, l_annotation, guard)), l_function_name);
l_annotation, guard)), l_function_name);
}
catch (const exception::reserved_word_error &e) {
throw exception::eval_error("Reserved word used as function name '" + e.word() + "'");
@@ -1146,9 +1143,8 @@ namespace chaiscript
struct Prefix_AST_Node : public AST_Node {
public:
Prefix_AST_Node(Operators::Opers t_oper) :
AST_Node("", AST_Node_Type::Prefix, std::make_shared<std::string>(""), 0, 0, 0, 0),
m_oper(t_oper)
Prefix_AST_Node(std::string t_ast_node_text = "", const std::shared_ptr<std::string> &t_fname=std::shared_ptr<std::string>(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) :
AST_Node(std::move(t_ast_node_text), AST_Node_Type::Prefix, t_fname, t_start_line, t_start_col, t_end_line, t_end_col)
{ }
virtual ~Prefix_AST_Node() {}
@@ -1156,11 +1152,12 @@ namespace chaiscript
chaiscript::eval::detail::Function_Push_Pop fpp(t_ss);
Boxed_Value bv(this->children[1]->eval(t_ss));
Operators::Opers oper = Operators::to_operator(children[0]->text, true);
try {
// short circuit arithmetic operations
if (m_oper != Operators::invalid && bv.get_type_info().is_arithmetic())
if (bv.get_type_info().is_arithmetic() && oper != Operators::invalid)
{
return Boxed_Number::do_oper(m_oper, std::move(bv));
return Boxed_Number::do_oper(oper, std::move(bv));
} else {
chaiscript::eval::detail::Stack_Push_Pop spp(t_ss);
fpp.save_params({bv});
@@ -1171,8 +1168,6 @@ namespace chaiscript
}
}
private:
Operators::Opers m_oper;
};
struct Break_AST_Node : public AST_Node {
@@ -1256,74 +1251,11 @@ namespace chaiscript
Try_AST_Node(const std::string &t_ast_node_text = "", const std::shared_ptr<std::string> &t_fname=std::shared_ptr<std::string>(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) :
AST_Node(t_ast_node_text, AST_Node_Type::Try, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { }
virtual ~Try_AST_Node() {}
Boxed_Value handle_exception(chaiscript::detail::Dispatch_Engine &t_ss, const Boxed_Value &t_except) const
{
Boxed_Value retval;
size_t end_point = this->children.size();
if (this->children.back()->identifier == AST_Node_Type::Finally) {
assert(end_point > 0);
end_point = this->children.size() - 1;
}
for (size_t i = 1; i < end_point; ++i) {
chaiscript::eval::detail::Scope_Push_Pop catchscope(t_ss);
AST_NodePtr catch_block = this->children[i];
if (catch_block->children.size() == 1) {
//No variable capture, no guards
retval = catch_block->children[0]->eval(t_ss);
break;
} else if (catch_block->children.size() == 2 || catch_block->children.size() == 3) {
const auto name = Arg_List_AST_Node::get_arg_name(catch_block->children[0]);
if (dispatch::Param_Types(
std::vector<std::pair<std::string, Type_Info>>{Arg_List_AST_Node::get_arg_type(catch_block->children[0], t_ss)}
).match(std::vector<Boxed_Value>{t_except}, t_ss.conversions()))
{
t_ss.add_object(name, t_except);
if (catch_block->children.size() == 2) {
//Variable capture, no guards
retval = catch_block->children[1]->eval(t_ss);
break;
}
else if (catch_block->children.size() == 3) {
//Variable capture, guards
bool guard = false;
try {
guard = boxed_cast<bool>(catch_block->children[1]->eval(t_ss));
} catch (const exception::bad_boxed_cast &) {
if (this->children.back()->identifier == AST_Node_Type::Finally) {
this->children.back()->children[0]->eval(t_ss);
}
throw exception::eval_error("Guard condition not boolean");
}
if (guard) {
retval = catch_block->children[2]->eval(t_ss);
break;
}
}
}
}
else {
if (this->children.back()->identifier == AST_Node_Type::Finally) {
this->children.back()->children[0]->eval(t_ss);
}
throw exception::eval_error("Internal error: catch block size unrecognized");
}
}
return retval;
}
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE{
Boxed_Value retval;
chaiscript::eval::detail::Scope_Push_Pop spp(t_ss);
try {
retval = this->children[0]->eval(t_ss);
}
@@ -1334,11 +1266,98 @@ namespace chaiscript
throw;
}
catch (const std::exception &e) {
retval = handle_exception(t_ss, Boxed_Value(std::ref(e)));
Boxed_Value except(std::ref(e));
size_t end_point = this->children.size();
if (this->children.back()->identifier == AST_Node_Type::Finally) {
assert(end_point > 0);
end_point = this->children.size() - 1;
}
for (size_t i = 1; i < end_point; ++i) {
chaiscript::eval::detail::Scope_Push_Pop catchscope(t_ss);
AST_NodePtr catch_block = this->children[i];
if (catch_block->children.size() == 1) {
//No variable capture, no guards
retval = catch_block->children[0]->eval(t_ss);
break;
}
else if (catch_block->children.size() == 2) {
//Variable capture, no guards
t_ss.add_object(catch_block->children[0]->text, except);
retval = catch_block->children[1]->eval(t_ss);
break;
}
else if (catch_block->children.size() == 3) {
//Variable capture, no guards
t_ss.add_object(catch_block->children[0]->text, except);
bool guard = false;
try {
guard = boxed_cast<bool>(catch_block->children[1]->eval(t_ss));
} catch (const exception::bad_boxed_cast &) {
if (this->children.back()->identifier == AST_Node_Type::Finally) {
this->children.back()->children[0]->eval(t_ss);
}
throw exception::eval_error("Guard condition not boolean");
}
if (guard) {
retval = catch_block->children[2]->eval(t_ss);
break;
}
}
else {
if (this->children.back()->identifier == AST_Node_Type::Finally) {
this->children.back()->children[0]->eval(t_ss);
}
throw exception::eval_error("Internal error: catch block size unrecognized");
}
}
}
catch (Boxed_Value &e) {
retval = handle_exception(t_ss, e);
catch (Boxed_Value &except) {
for (size_t i = 1; i < this->children.size(); ++i) {
chaiscript::eval::detail::Scope_Push_Pop catchscope(t_ss);
const auto &catch_block = this->children[i];
if (catch_block->children.size() == 1) {
//No variable capture, no guards
retval = catch_block->children[0]->eval(t_ss);
break;
}
else if (catch_block->children.size() == 2) {
//Variable capture, no guards
t_ss.add_object(catch_block->children[0]->text, except);
retval = catch_block->children[1]->eval(t_ss);
break;
}
else if (catch_block->children.size() == 3) {
//Variable capture, guards
t_ss.add_object(catch_block->children[0]->text, except);
bool guard;
try {
guard = boxed_cast<bool>(catch_block->children[1]->eval(t_ss));
}
catch (const exception::bad_boxed_cast &) {
if (this->children.back()->identifier == AST_Node_Type::Finally) {
this->children.back()->children[0]->eval(t_ss);
}
throw exception::eval_error("Guard condition not boolean");
}
if (guard) {
retval = catch_block->children[2]->eval(t_ss);
break;
}
}
else {
if (this->children.back()->identifier == AST_Node_Type::Finally) {
this->children.back()->children[0]->eval(t_ss);
}
throw exception::eval_error("Internal error: catch block size unrecognized");
}
}
}
catch (...) {
if (this->children.back()->identifier == AST_Node_Type::Finally) {
@@ -1347,7 +1366,6 @@ namespace chaiscript
throw;
}
if (this->children.back()->identifier == AST_Node_Type::Finally) {
retval = this->children.back()->children[0]->eval(t_ss);
}
@@ -1380,29 +1398,29 @@ namespace chaiscript
AST_NodePtr guardnode;
const auto d = t_ss.get_parent_locals();
const auto itr = d.find("_current_class_name");
const auto class_offset = (itr != d.end())?-1:0;
auto d = t_ss.get_parent_locals();
auto itr = d.find("_current_class_name");
int class_offset = 0;
if (itr != d.end()) class_offset = -1;
const std::string & class_name = (itr != d.end())?std::string(boxed_cast<std::string>(itr->second)):this->children[0]->text;
//The first param of a method is always the implied this ptr.
std::vector<std::string> t_param_names{"this"};
dispatch::Param_Types param_types;
if ((this->children.size() > static_cast<size_t>(3 + class_offset)) && (this->children[static_cast<size_t>(2 + class_offset)]->identifier == AST_Node_Type::Arg_List)) {
auto args = Arg_List_AST_Node::get_arg_names(this->children[static_cast<size_t>(2 + class_offset)]);
t_param_names.insert(t_param_names.end(), args.begin(), args.end());
param_types = Arg_List_AST_Node::get_arg_types(this->children[static_cast<size_t>(2 + class_offset)], t_ss);
if ((this->children.size() > static_cast<size_t>(3 + class_offset)) && (this->children[(2 + class_offset)]->identifier == AST_Node_Type::Arg_List)) {
for (const auto &child : this->children[(2 + class_offset)]->children) {
t_param_names.push_back(child->text);
}
if (this->children.size() > static_cast<size_t>(4 + class_offset)) {
guardnode = this->children[static_cast<size_t>(3 + class_offset)];
guardnode = this->children[(3 + class_offset)];
}
}
else {
//no parameters
if (this->children.size() > static_cast<size_t>(3 + class_offset)) {
guardnode = this->children[static_cast<size_t>(2 + class_offset)];
guardnode = this->children[(2 + class_offset)];
}
}
@@ -1419,38 +1437,32 @@ namespace chaiscript
try {
const std::string & l_annotation = this->annotation?this->annotation->text:"";
const std::string & function_name = this->children[static_cast<size_t>(1 + class_offset)]->text;
const std::string & function_name = this->children[(1 + class_offset)]->text;
if (function_name == class_name) {
param_types.push_front(class_name, Type_Info());
t_ss.add(std::make_shared<dispatch::detail::Dynamic_Object_Constructor>(class_name, std::make_shared<dispatch::Dynamic_Proxy_Function>(std::bind(chaiscript::eval::detail::eval_function,
std::ref(t_ss), this->children.back(), t_param_names, std::placeholders::_1),
static_cast<int>(numparams), this->children.back(), param_types, l_annotation, guard)),
static_cast<int>(numparams), this->children.back(), l_annotation, guard)),
function_name);
}
else {
try {
// Do know type name (if this line fails, the catch block is called and the
// other version is called, with no Type_Info object known)
auto type = t_ss.get_type(class_name);
param_types.push_front(class_name, type);
// Do know type name
t_ss.add(
std::make_shared<dispatch::detail::Dynamic_Object_Function>(class_name,
std::make_shared<dispatch::Dynamic_Proxy_Function>(std::bind(chaiscript::eval::detail::eval_function,
std::ref(t_ss), this->children.back(),
t_param_names, std::placeholders::_1), static_cast<int>(numparams), this->children.back(),
param_types, l_annotation, guard), type), function_name);
l_annotation, guard), t_ss.get_type(class_name)), function_name);
} catch (const std::range_error &) {
param_types.push_front(class_name, Type_Info());
// Do not know type name
t_ss.add(
std::make_shared<dispatch::detail::Dynamic_Object_Function>(class_name,
std::make_shared<dispatch::Dynamic_Proxy_Function>(std::bind(chaiscript::eval::detail::eval_function,
std::ref(t_ss), this->children.back(),
t_param_names, std::placeholders::_1), static_cast<int>(numparams), this->children.back(),
param_types, l_annotation, guard)), function_name);
l_annotation, guard)), function_name);
}
}
}
@@ -1473,23 +1485,24 @@ namespace chaiscript
{
const auto &d = t_ss.get_parent_locals();
const auto itr = d.find("_current_class_name");
const auto class_offset = (itr != d.end())?-1:0;
int class_offset = 0;
if (itr != d.end()) class_offset = -1;
std::string class_name = (itr != d.end())?std::string(boxed_cast<std::string>(itr->second)):this->children[0]->text;
try {
t_ss.add(
std::make_shared<dispatch::detail::Dynamic_Object_Function>(
std::move(class_name),
class_name,
fun(std::function<Boxed_Value (dispatch::Dynamic_Object &)>(std::bind(&dispatch::Dynamic_Object::get_attr,
std::placeholders::_1,
this->children[static_cast<size_t>(1 + class_offset)]->text
this->children[(1 + class_offset)]->text
))
)
), this->children[static_cast<size_t>(1 + class_offset)]->text);
), this->children[(1 + class_offset)]->text);
}
catch (const exception::reserved_word_error &) {
throw exception::eval_error("Reserved word used as attribute '" + this->children[static_cast<size_t>(1 + class_offset)]->text + "'");
throw exception::eval_error("Reserved word used as attribute '" + this->children[(1 + class_offset)]->text + "'");
} catch (const exception::name_conflict_error &e) {
throw exception::eval_error("Attribute redefined '" + e.name() + "'");
}
@@ -1498,6 +1511,40 @@ namespace chaiscript
};
struct Shift_AST_Node : public Binary_Operator_AST_Node {
public:
Shift_AST_Node(const std::string &t_ast_node_text = "", const std::shared_ptr<std::string> &t_fname=std::shared_ptr<std::string>(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) :
Binary_Operator_AST_Node(t_ast_node_text, AST_Node_Type::Shift, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { }
virtual ~Shift_AST_Node() {}
};
struct Equality_AST_Node : public Binary_Operator_AST_Node {
public:
Equality_AST_Node(const std::string &t_ast_node_text = "", const std::shared_ptr<std::string> &t_fname=std::shared_ptr<std::string>(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) :
Binary_Operator_AST_Node(t_ast_node_text, AST_Node_Type::Equality, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { }
virtual ~Equality_AST_Node() {}
};
struct Bitwise_And_AST_Node : public Binary_Operator_AST_Node {
public:
Bitwise_And_AST_Node(const std::string &t_ast_node_text = "", const std::shared_ptr<std::string> &t_fname=std::shared_ptr<std::string>(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) :
Binary_Operator_AST_Node(t_ast_node_text, AST_Node_Type::Bitwise_And, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { }
virtual ~Bitwise_And_AST_Node() {}
};
struct Bitwise_Xor_AST_Node : public Binary_Operator_AST_Node {
public:
Bitwise_Xor_AST_Node(const std::string &t_ast_node_text = "", const std::shared_ptr<std::string> &t_fname=std::shared_ptr<std::string>(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) :
Binary_Operator_AST_Node(t_ast_node_text, AST_Node_Type::Bitwise_Xor, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { }
virtual ~Bitwise_Xor_AST_Node() {}
};
struct Bitwise_Or_AST_Node : public Binary_Operator_AST_Node {
public:
Bitwise_Or_AST_Node(const std::string &t_ast_node_text = "", const std::shared_ptr<std::string> &t_fname=std::shared_ptr<std::string>(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) :
Binary_Operator_AST_Node(t_ast_node_text, AST_Node_Type::Bitwise_Or, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { }
virtual ~Bitwise_Or_AST_Node() {}
};
struct Logical_And_AST_Node : public AST_Node {
public:

View File

@@ -1,7 +1,7 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_PARSER_HPP_
@@ -171,7 +171,7 @@ namespace chaiscript
/// Prints the parsed ast_nodes as a tree
/*
void debug_print(AST_NodePtr t, std::string prepend = "") {
std::cout << prepend << "(" << ast_node_type_to_string(t->identifier) << ") " << t->text << " : " << t->start.line << ", " << t->start.column << '\n';
std::cout << prepend << "(" << ast_node_type_to_string(t->identifier) << ") " << t->text << " : " << t->start.line << ", " << t->start.column << std::endl;
for (unsigned int j = 0; j < t->children.size(); ++j) {
debug_print(t->children[j], prepend + " ");
}
@@ -223,8 +223,8 @@ namespace chaiscript
t_t->end.column = pos_col_stop;
if (is_deep) {
t_t->children.assign(m_match_stack.begin() + static_cast<int>(t_match_start), m_match_stack.end());
m_match_stack.erase(m_match_stack.begin() + static_cast<int>(t_match_start), m_match_stack.end());
t_t->children.assign(m_match_stack.begin() + t_match_start, m_match_stack.end());
m_match_stack.erase(m_match_stack.begin() + t_match_start, m_match_stack.end());
}
/// \todo fix the fact that a successful match that captured no ast_nodes doesn't have any real start position
@@ -266,27 +266,16 @@ namespace chaiscript
return false;
}
/// Skips ChaiScript whitespace, which means space and tab, but not cr/lf
/// jespada: Modified SkipWS to skip optionally CR ('\n') and/or LF+CR ("\r\n")
bool SkipWS(bool skip_cr=false) {
/// jespada: Modified SkipWS to skip optionally CR ('\n')
bool SkipWS(const bool skip_cr=false) {
bool retval = false;
while (has_more_input()) {
auto end_line = (*m_input_pos != 0) && ((*m_input_pos == '\n') || (*m_input_pos == '\r' && *(m_input_pos+1) == '\n'));
if ( char_in_alphabet(*m_input_pos,detail::white_alphabet) || (skip_cr && end_line)) {
if(end_line) {
if ( char_in_alphabet(*m_input_pos,detail::white_alphabet) || (skip_cr && (*m_input_pos == '\n'))) {
if(*m_input_pos == '\n') {
m_col = 1;
++m_line;
if(*(m_input_pos) == '\r') {
// discards lf
++m_input_pos;
}
}
else {
} else {
++m_col;
}
++m_input_pos;
@@ -295,14 +284,14 @@ namespace chaiscript
}
else if (SkipComment()) {
retval = true;
} else {
}
else {
break;
}
}
return retval;
}
/// Reads a floating point value from input, without skipping initial whitespace
bool Float_() {
if (has_more_input() && char_in_alphabet(*m_input_pos,detail::float_alphabet) ) {
@@ -431,13 +420,21 @@ namespace chaiscript
}
}
std::stringstream ss(t_val.substr(0, i));
if (float_)
{
return const_var(std::stof(t_val.substr(0,i)));
float f;
ss >> f;
return const_var(f);
} else if (long_) {
return const_var(std::stold(t_val.substr(0,i)));
long double f;
ss >> f;
return const_var(f);
} else {
return const_var(std::stod(t_val.substr(0,i)));
double f;
ss >> f;
return const_var(f);
}
}
@@ -691,25 +688,6 @@ namespace chaiscript
}
}
/// Reads an argument from input
bool Arg() {
const auto prev_stack_top = m_match_stack.size();
SkipWS();
if (!Id(true)) {
return false;
}
SkipWS();
Id(true);
build_match(std::make_shared<eval::Arg_AST_Node>(), prev_stack_top);
return true;
}
/// Checks for a node annotation of the form "#<annotation>"
bool Annotation() {
SkipWS();
@@ -798,7 +776,7 @@ namespace chaiscript
//If we've seen previous interpolation, add on instead of making a new one
m_match_stack.push_back(std::make_shared<eval::Quoted_String_AST_Node>(match, m_filename, prev_line, prev_col, m_line, m_col));
build_match(std::make_shared<eval::Binary_Operator_AST_Node>("+"), prev_stack_top);
build_match(std::make_shared<eval::Addition_AST_Node>(), prev_stack_top);
} else {
m_match_stack.push_back(std::make_shared<eval::Quoted_String_AST_Node>(match, m_filename, prev_line, prev_col, m_line, m_col));
}
@@ -835,7 +813,7 @@ namespace chaiscript
build_match(std::make_shared<eval::Inplace_Fun_Call_AST_Node>(), ev_stack_top);
build_match(std::make_shared<eval::Arg_List_AST_Node>(), ev_stack_top);
build_match(std::make_shared<eval::Fun_Call_AST_Node>(), tostr_stack_top);
build_match(std::make_shared<eval::Binary_Operator_AST_Node>("+"), prev_stack_top);
build_match(std::make_shared<eval::Addition_AST_Node>(), prev_stack_top);
} else {
throw exception::eval_error("Unclosed in-string eval", File_Position(prev_line, prev_col), *m_filename);
}
@@ -878,7 +856,7 @@ namespace chaiscript
if (is_interpolated) {
m_match_stack.push_back(std::make_shared<eval::Quoted_String_AST_Node>(match, m_filename, prev_line, prev_col, m_line, m_col));
build_match(std::make_shared<eval::Binary_Operator_AST_Node>("+"), prev_stack_top);
build_match(std::make_shared<eval::Addition_AST_Node>(), prev_stack_top);
} else {
m_match_stack.push_back(std::make_shared<eval::Quoted_String_AST_Node>(match, m_filename, prev_line, prev_col, m_line, m_col));
}
@@ -1120,33 +1098,6 @@ namespace chaiscript
}
}
/// Reads a comma-separated list of values from input, for function declarations
bool Decl_Arg_List() {
SkipWS(true);
bool retval = false;
const auto prev_stack_top = m_match_stack.size();
if (Arg()) {
retval = true;
while (Eol()) {}
if (Char(',')) {
do {
while (Eol()) {}
if (!Arg()) {
throw exception::eval_error("Unexpected value in parameter list", File_Position(m_line, m_col), *m_filename);
}
} while (Char(','));
}
build_match(std::make_shared<eval::Arg_List_AST_Node>(), prev_stack_top);
}
SkipWS(true);
return retval;
}
/// Reads a comma-separated list of values from input
bool Arg_List() {
SkipWS(true);
@@ -1224,7 +1175,7 @@ namespace chaiscript
retval = true;
if (Char('(')) {
Decl_Arg_List();
Arg_List();
if (!Char(')')) {
throw exception::eval_error("Incomplete anonymous function", File_Position(m_line, m_col), *m_filename);
}
@@ -1274,7 +1225,7 @@ namespace chaiscript
}
if (Char('(')) {
Decl_Arg_List();
Arg_List();
if (!Char(')')) {
throw exception::eval_error("Incomplete function definition", File_Position(m_line, m_col), *m_filename);
}
@@ -1329,7 +1280,7 @@ namespace chaiscript
if (Keyword("catch", false)) {
const auto catch_stack_top = m_match_stack.size();
if (Char('(')) {
if (!(Arg() && Char(')'))) {
if (!(Id(true) && Char(')'))) {
throw exception::eval_error("Incomplete 'catch' expression", File_Position(m_line, m_col), *m_filename);
}
if (Char(':')) {
@@ -1873,24 +1824,72 @@ namespace chaiscript
/// Reads a unary prefixed expression from input
bool Prefix() {
bool retval = false;
const auto prev_stack_top = m_match_stack.size();
const std::vector<std::string> prefix_opers{"++", "--", "-", "+", "!", "~", "&"};
for (const auto &oper : prefix_opers)
{
bool is_char = oper.size() == 1;
if ((is_char && Char(oper[0], true)) || (!is_char && Symbol(oper.c_str(), true)))
{
if (!Operator(m_operators.size()-1)) {
throw exception::eval_error("Incomplete prefix '" + oper + "' expression", File_Position(m_line, m_col), *m_filename);
}
if (Symbol("++", true)) {
retval = true;
build_match(std::make_shared<eval::Prefix_AST_Node>(Operators::to_operator(oper, true)), prev_stack_top);
return true;
if (!Operator(m_operators.size()-1)) {
throw exception::eval_error("Incomplete '++' expression", File_Position(m_line, m_col), *m_filename);
}
build_match(std::make_shared<eval::Prefix_AST_Node>(), prev_stack_top);
} else if (Symbol("--", true)) {
retval = true;
if (!Operator(m_operators.size()-1)) {
throw exception::eval_error("Incomplete '--' expression", File_Position(m_line, m_col), *m_filename);
}
build_match(std::make_shared<eval::Prefix_AST_Node>(), prev_stack_top);
} else if (Char('-', true)) {
retval = true;
if (!Operator(m_operators.size()-1)) {
throw exception::eval_error("Incomplete unary '-' expression", File_Position(m_line, m_col), *m_filename);
}
build_match(std::make_shared<eval::Prefix_AST_Node>(), prev_stack_top);
} else if (Char('+', true)) {
retval = true;
if (!Operator(m_operators.size()-1)) {
throw exception::eval_error("Incomplete unary '+' expression", File_Position(m_line, m_col), *m_filename);
}
build_match(std::make_shared<eval::Prefix_AST_Node>(), prev_stack_top);
}
else if (Char('!', true)) {
retval = true;
if (!Operator(m_operators.size()-1)) {
throw exception::eval_error("Incomplete '!' expression", File_Position(m_line, m_col), *m_filename);
}
build_match(std::make_shared<eval::Prefix_AST_Node>(), prev_stack_top);
}
else if (Char('~', true)) {
retval = true;
if (!Operator(m_operators.size()-1)) {
throw exception::eval_error("Incomplete '~' expression", File_Position(m_line, m_col), *m_filename);
}
build_match(std::make_shared<eval::Prefix_AST_Node>(), prev_stack_top);
}
else if (Char('&', true)) {
retval = true;
if (!Operator(m_operators.size()-1)) {
throw exception::eval_error("Incomplete '~' expression", File_Position(m_line, m_col), *m_filename);
}
build_match(std::make_shared<eval::Prefix_AST_Node>(), prev_stack_top);
}
return false;
return retval;
}
/// Parses any of a group of 'value' style ast_node groups from input
@@ -1913,6 +1912,7 @@ namespace chaiscript
bool Operator(const size_t t_precedence = 0) {
bool retval = false;
AST_NodePtr oper;
const auto prev_stack_top = m_match_stack.size();
if (t_precedence < m_operators.size()) {
@@ -1927,9 +1927,10 @@ namespace chaiscript
File_Position(m_line, m_col), *m_filename);
}
AST_NodePtr oper = m_match_stack.at(m_match_stack.size()-2);
switch (m_operators[t_precedence]) {
case(AST_Node_Type::Comparison) :
build_match(std::make_shared<eval::Comparison_AST_Node>(), prev_stack_top);
break;
case(AST_Node_Type::Ternary_Cond) :
m_match_stack.erase(m_match_stack.begin() + m_match_stack.size() - 2,
m_match_stack.begin() + m_match_stack.size() - 1);
@@ -1947,27 +1948,52 @@ namespace chaiscript
File_Position(m_line, m_col), *m_filename);
}
break;
case(AST_Node_Type::Addition) :
case(AST_Node_Type::Multiplication) :
case(AST_Node_Type::Shift) :
case(AST_Node_Type::Equality) :
case(AST_Node_Type::Bitwise_And) :
case(AST_Node_Type::Bitwise_Xor) :
case(AST_Node_Type::Bitwise_Or) :
case(AST_Node_Type::Comparison) :
assert(m_match_stack.size() > 1);
m_match_stack.erase(m_match_stack.begin() + m_match_stack.size() - 2, m_match_stack.begin() + m_match_stack.size() - 1);
build_match(std::make_shared<eval::Binary_Operator_AST_Node>(oper->text), prev_stack_top);
oper = m_match_stack.at(m_match_stack.size()-2);
m_match_stack.erase(m_match_stack.begin() + m_match_stack.size() - 2,
m_match_stack.begin() + m_match_stack.size() - 1);
if (oper->text == "+") {
build_match(std::make_shared<eval::Addition_AST_Node>(), prev_stack_top);
}
else if (oper->text == "-") {
build_match(std::make_shared<eval::Subtraction_AST_Node>(), prev_stack_top);
}
break;
case(AST_Node_Type::Multiplication) :
oper = m_match_stack.at(m_match_stack.size()-2);
m_match_stack.erase(m_match_stack.begin() + m_match_stack.size() - 2,
m_match_stack.begin() + m_match_stack.size() - 1);
if (oper->text == "*") {
build_match(std::make_shared<eval::Multiplication_AST_Node>(), prev_stack_top);
}
else if (oper->text == "/") {
build_match(std::make_shared<eval::Division_AST_Node>(), prev_stack_top);
}
else if (oper->text == "%") {
build_match(std::make_shared<eval::Modulus_AST_Node>(), prev_stack_top);
}
break;
case(AST_Node_Type::Shift) :
build_match(std::make_shared<eval::Shift_AST_Node>(), prev_stack_top);
break;
case(AST_Node_Type::Equality) :
build_match(std::make_shared<eval::Equality_AST_Node>(), prev_stack_top);
break;
case(AST_Node_Type::Bitwise_And) :
build_match(std::make_shared<eval::Bitwise_And_AST_Node>(), prev_stack_top);
break;
case(AST_Node_Type::Bitwise_Xor) :
build_match(std::make_shared<eval::Bitwise_Xor_AST_Node>(), prev_stack_top);
break;
case(AST_Node_Type::Bitwise_Or) :
build_match(std::make_shared<eval::Bitwise_Or_AST_Node>(), prev_stack_top);
break;
case(AST_Node_Type::Logical_And) :
build_match(std::make_shared<eval::Logical_And_AST_Node>(), prev_stack_top);
break;
case(AST_Node_Type::Logical_Or) :
build_match(std::make_shared<eval::Logical_Or_AST_Node>(), prev_stack_top);
break;
default:
throw exception::eval_error("Internal error: unhandled ast_node", File_Position(m_line, m_col), *m_filename);
}
@@ -2074,7 +2100,14 @@ namespace chaiscript
while (has_more) {
const auto prev_line = m_line;
const auto prev_col = m_col;
if (Def(true) || Var_Decl(true)) {
if (Def(true)) {
if (!saw_eol) {
throw exception::eval_error("Two function definitions missing line separator", File_Position(prev_line, prev_col), *m_filename);
}
has_more = true;
retval = true;
saw_eol = true;
} else if (Var_Decl(true)) {
if (!saw_eol) {
throw exception::eval_error("Two function definitions missing line separator", File_Position(prev_line, prev_col), *m_filename);
}
@@ -2103,7 +2136,7 @@ namespace chaiscript
while (has_more) {
int prev_line = m_line;
int prev_col = m_col;
if (Def() || Try() || If() || While() || Class() || For() || Switch()) {
if (Def()) {
if (!saw_eol) {
throw exception::eval_error("Two function definitions missing line separator", File_Position(prev_line, prev_col), *m_filename);
}
@@ -2111,7 +2144,55 @@ namespace chaiscript
retval = true;
saw_eol = true;
}
else if (Return() || Break() || Continue() || Equation()) {
else if (Try()) {
if (!saw_eol) {
throw exception::eval_error("Two function definitions missing line separator", File_Position(prev_line, prev_col), *m_filename);
}
has_more = true;
retval = true;
saw_eol = true;
}
else if (If()) {
if (!saw_eol) {
throw exception::eval_error("Two function definitions missing line separator", File_Position(prev_line, prev_col), *m_filename);
}
has_more = true;
retval = true;
saw_eol = true;
}
else if (While()) {
if (!saw_eol) {
throw exception::eval_error("Two function definitions missing line separator", File_Position(prev_line, prev_col), *m_filename);
}
has_more = true;
retval = true;
saw_eol = true;
}
else if (Class()) {
if (!saw_eol) {
throw exception::eval_error("Two function definitions missing line separator", File_Position(prev_line, prev_col), *m_filename);
}
has_more = true;
retval = true;
saw_eol = true;
}
else if (For()) {
if (!saw_eol) {
throw exception::eval_error("Two function definitions missing line separator", File_Position(prev_line, prev_col), *m_filename);
}
has_more = true;
retval = true;
saw_eol = true;
}
else if (Switch()) {
if (!saw_eol) {
throw exception::eval_error("Two function definitions missing line separator", File_Position(prev_line, prev_col), *m_filename);
}
has_more = true;
retval = true;
saw_eol = true;
}
else if (Return()) {
if (!saw_eol) {
throw exception::eval_error("Two expressions missing line separator", File_Position(prev_line, prev_col), *m_filename);
}
@@ -2119,7 +2200,36 @@ namespace chaiscript
retval = true;
saw_eol = false;
}
else if (Block() || Eol()) {
else if (Break()) {
if (!saw_eol) {
throw exception::eval_error("Two expressions missing line separator", File_Position(prev_line, prev_col), *m_filename);
}
has_more = true;
retval = true;
saw_eol = false;
}
else if (Continue()) {
if (!saw_eol) {
throw exception::eval_error("Two expressions missing line separator", File_Position(prev_line, prev_col), *m_filename);
}
has_more = true;
retval = true;
saw_eol = false;
}
else if (Block()) {
has_more = true;
retval = true;
saw_eol = true;
}
else if (Equation()) {
if (!saw_eol) {
throw exception::eval_error("Two expressions missing line separator", File_Position(prev_line, prev_col), *m_filename);
}
has_more = true;
retval = true;
saw_eol = false;
}
else if (Eol()) {
has_more = true;
retval = true;
saw_eol = true;

View File

@@ -455,37 +455,37 @@ def zip(x, y) {
# Returns the position of the second value string in the first value string
def string::find(string substr) {
def string::find(substr) : is_type(substr, "string") {
find(this, substr, size_t(0));
}
# Returns the position of last match of the second value string in the first value string
def string::rfind(string substr) {
def string::rfind(substr) : is_type(substr, "string") {
rfind(this, substr, size_t(-1));
}
# Returns the position of the first match of elements in the second value string in the first value string
def string::find_first_of(string list) {
def string::find_first_of(list) : is_type(list, "string") {
find_first_of(this, list, size_t(0));
}
# Returns the position of the last match of elements in the second value string in the first value string
def string::find_last_of(string list) {
def string::find_last_of(list) : is_type(list, "string") {
find_last_of(this, list, size_t(-1));
}
# Returns the position of the first non-matching element in the second value string in the first value string
def string::find_first_not_of(string list) {
def string::find_first_not_of(list) : is_type(list, "string") {
find_first_not_of(this, list, size_t(0));
}
# Returns the position of the last non-matching element in the second value string in the first value string
def string::find_last_not_of(string list) {
def string::find_last_not_of(list) : is_type(list, "string") {
find_last_not_of(this, list, size_t(-1));
}
@@ -505,7 +505,7 @@ def string::trim() {
}
def find(container, value, Function compare_func) : call_exists(range, container) {
def find(container, value, compare_func) : call_exists(range, container) && is_type(compare_func, "Function") {
auto range := range(container);
while (!range.empty()) {
if (compare_func(range.front(), value)) {

View File

@@ -1,7 +1,7 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#ifndef CHAISCRIPT_UTILITY_UTILITY_HPP_

View File

@@ -1,4 +1,4 @@
Copyright 2009-2015 Jason Turner
Copyright 2009-2014 Jason Turner
Copyright 2009-2012 Jonathan Turner.
All Rights Reserved.

View File

@@ -8,7 +8,7 @@ ChaiScript
http://www.chaiscript.com
(c) 2009-2012 Jonathan Turner
(c) 2009-2015 Jason Turner
(c) 2009-2014 Jason Turner
Release under the BSD license, see "license.txt" for details.
@@ -16,8 +16,6 @@ Release under the BSD license, see "license.txt" for details.
Introduction
============
[![Gitter](https://badges.gitter.im/Join Chat.svg)](https://gitter.im/ChaiScript/ChaiScript?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
ChaiScript is one of the only embedded scripting language designed from the
ground up to directly target C++ and take advantage of modern C++ development
techniques, working with the developer like he expects it to work. Being a
@@ -35,10 +33,9 @@ Requirements
============
ChaiScript requires a C++11 compiler to build with support for variadic
templates. It has been tested with gcc 4.6 and clang 3.1 (with libcxx). MacOS
templates. It has been tested with gcc 4.7 and clang 3.1 (with libcxx). MacOS
10.8 (Mountain Lion) is also known to support the C++11 build with Apple's
clang 4.0. MSVC 2013 or newer is supports also. For more information see the build
[dashboard](http://chaiscript.com/ChaiScript-BuildResults/index.html).
clang 4.0.
Usage
=====

View File

@@ -1,45 +1,6 @@
Notes:
=======
Current Version: 5.6.0
### Changes since 5.5.1
* Throw exception on integer divide by 0
* Add optional type specification to function declarations
```
def func(int i, j, double k) {
// i must be an int.
// j can be anything
// k must be a double
// normal conversion rules still apply
}
```
* Many minor fixes for compiler warnings
* Add support for `std::future` and `std::async`
```
var f := async(someFunction);
var f2 := async(someFunction2);
// someFunction and someFunction2 are running in parallel now
f.get();
f2.get();
```
* Fully support r-value returns, supporting move-only objects and reducing object copies
### Changes since 5.5.0
* 30% performance increase
* Fix handling of object stack, resulting in greatly reduced memory usage
* Code cleanups
### Changes since 5.4.0
* 2x performance increase
* Significant code cleanups
* Throw exception if user attempts to call function on null object
* Allow user defined type conversions
* Fix object lifetime for nested function calls made at the global scope
* Fix returning of boolean values from function calls
Current Version: 5.4.0
### Changes since 5.3.1
* Decreased compile time and build size

View File

@@ -13,12 +13,12 @@
void log(const std::string &msg)
{
std::cout << "[" << time(nullptr) << "] " << msg << '\n';
std::cout << "[" << time(nullptr) << "] " << msg << std::endl;
}
void log(const std::string &module, const std::string &msg)
{
std::cout << "[" << time(nullptr) << "] <" << module << "> " << msg << '\n';
std::cout << "[" << time(nullptr) << "] <" << module << "> " << msg << std::endl;
}
void bound_log(const std::string &msg)
@@ -28,12 +28,12 @@ void bound_log(const std::string &msg)
void hello_world(const chaiscript::Boxed_Value & /*o*/)
{
std::cout << "Hello World\n";
std::cout << "Hello World" << std::endl;
}
void hello_constructor(const chaiscript::Boxed_Value & /*o*/)
{
std::cout << "Hello Constructor\n";
std::cout << "Hello Constructor" << std::endl;
}
@@ -62,7 +62,7 @@ struct System
void take_shared_ptr(const std::shared_ptr<const std::string> &p)
{
std::cout << *p << '\n';
std::cout << *p << std::endl;
}
int main(int /*argc*/, char * /*argv*/[]) {
@@ -122,7 +122,7 @@ int main(int /*argc*/, char * /*argv*/[]) {
//the templated version of eval:
int i = chai.eval<int>("5+5");
std::cout << "5+5: " << i << '\n';
std::cout << "5+5: " << i << std::endl;
//Add a new variable
chai("var scripti = 15");
@@ -130,9 +130,9 @@ int main(int /*argc*/, char * /*argv*/[]) {
//We can even get a handle to the variables in the system
int &scripti = chai.eval<int &>("scripti");
std::cout << "scripti: " << scripti << '\n';
std::cout << "scripti: " << scripti << std::endl;
scripti *= 2;
std::cout << "scripti (updated): " << scripti << '\n';
std::cout << "scripti (updated): " << scripti << std::endl;
chai("print(\"Scripti from chai: \" + to_string(scripti))");
//To do: Add examples of handling Boxed_Values directly when needed

View File

@@ -1,4 +0,0 @@
for (var i = 0; i < 1000; ++i) {
puts(helloWorld("Bob12345"))
}

View File

@@ -1,405 +0,0 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#include <iostream>
#include <list>
#include <regex>
#ifdef _MSC_VER
#define _CRT_SECURE_NO_WARNINGS
#endif
#include <chaiscript/chaiscript.hpp>
#include <chaiscript/chaiscript_stdlib.hpp>
#ifdef READLINE_AVAILABLE
#include <readline/readline.h>
#include <readline/history.h>
#else
char *mystrdup(const char *s) {
size_t len = strlen(s); // Space for length plus nul
char *d = static_cast<char*>(malloc(len + 1));
if (d == nullptr) return nullptr; // No memory
#ifdef CHAISCRIPT_MSVC
strcpy_s(d, len + 1, s); // Copy the characters
#else
strncpy(d, s, len); // Copy the characters
#endif
d[len] = '\0';
return d; // Return the new string
}
char* readline(const char* p)
{
std::string retval;
std::cout << p;
std::getline(std::cin, retval);
return std::cin.eof() ? nullptr : mystrdup(retval.c_str());
}
void add_history(const char*){}
void using_history(){}
#endif
void *cast_module_symbol(std::vector<std::string>(*t_path)())
{
union cast_union
{
std::vector<std::string>(*in_ptr)();
void *out_ptr;
};
cast_union c;
c.in_ptr = t_path;
return c.out_ptr;
}
std::vector<std::string> default_search_paths()
{
std::vector<std::string> paths;
#ifdef CHAISCRIPT_WINDOWS // force no unicode
CHAR path[4096];
int size = GetModuleFileNameA(0, path, sizeof(path) - 1);
std::string exepath(path, size);
size_t lastslash = exepath.rfind('\\');
size_t secondtolastslash = exepath.rfind('\\', lastslash - 1);
if (lastslash != std::string::npos)
{
paths.push_back(exepath.substr(0, lastslash));
}
if (secondtolastslash != std::string::npos)
{
return{ exepath.substr(0, secondtolastslash) + "\\lib\\chaiscript\\" };
}
#else
std::string exepath;
std::vector<char> buf(2048);
ssize_t size = -1;
if ((size = readlink("/proc/self/exe", &buf.front(), buf.size())) != -1)
{
exepath = std::string(&buf.front(), size);
}
if (exepath.empty())
{
if ((size = readlink("/proc/curproc/file", &buf.front(), buf.size())) != -1)
{
exepath = std::string(&buf.front(), size);
}
}
if (exepath.empty())
{
if ((size = readlink("/proc/self/path/a.out", &buf.front(), buf.size())) != -1)
{
exepath = std::string(&buf.front(), size);
}
}
if (exepath.empty())
{
Dl_info rInfo;
memset(&rInfo, 0, sizeof(rInfo));
if (!dladdr(cast_module_symbol(&default_search_paths), &rInfo) || !rInfo.dli_fname) {
return paths;
}
exepath = std::string(rInfo.dli_fname);
}
size_t lastslash = exepath.rfind('/');
size_t secondtolastslash = exepath.rfind('/', lastslash - 1);
if (lastslash != std::string::npos)
{
paths.push_back(exepath.substr(0, lastslash));
}
if (secondtolastslash != std::string::npos)
{
paths.push_back(exepath.substr(0, secondtolastslash) + "/lib/chaiscript/");
}
#endif
return paths;
}
void help(int n) {
if (n >= 0) {
std::cout << "ChaiScript evaluator. To evaluate an expression, type it and press <enter>." << std::endl;
std::cout << "Additionally, you can inspect the runtime system using:" << std::endl;
std::cout << " dump_system() - outputs all functions registered to the system" << std::endl;
std::cout << " dump_object(x) - dumps information about the given symbol" << std::endl;
}
else {
std::cout << "usage : chai [option]+" << std::endl;
std::cout << "option:" << std::endl;
std::cout << " -h | --help" << std::endl;
std::cout << " -i | --interactive" << std::endl;
std::cout << " -c | --command cmd" << std::endl;
std::cout << " -v | --version" << std::endl;
std::cout << " - --stdin" << std::endl;
std::cout << " filepath" << std::endl;
}
}
std::string helloWorld(const std::string &t_name)
{
return "Hello " + t_name + "!";
}
bool throws_exception(const std::function<void()> &f)
{
try {
f();
}
catch (...) {
return true;
}
return false;
}
chaiscript::exception::eval_error get_eval_error(const std::function<void()> &f)
{
try {
f();
}
catch (const chaiscript::exception::eval_error &e) {
return e;
}
throw std::runtime_error("no exception throw");
}
std::string get_next_command() {
std::string retval("quit");
if (!std::cin.eof()) {
char *input_raw = readline("eval> ");
if (input_raw) {
add_history(input_raw);
std::string val(input_raw);
size_t pos = val.find_first_not_of("\t \n");
if (pos != std::string::npos)
{
val.erase(0, pos);
}
pos = val.find_last_not_of("\t \n");
if (pos != std::string::npos)
{
val.erase(pos + 1, std::string::npos);
}
retval = val;
::free(input_raw);
}
}
if (retval == "quit"
|| retval == "exit"
|| retval == "help"
|| retval == "version")
{
retval += "(0)";
}
return retval;
}
// We have to wrap exit with our own because Clang has a hard time with
// function pointers to functions with special attributes (system exit being marked NORETURN)
void myexit(int return_val) {
exit(return_val);
}
void interactive(chaiscript::ChaiScript& chai)
{
using_history();
for (;;) {
std::string input = get_next_command();
try {
// evaluate input
chaiscript::Boxed_Value val = chai.eval(input);
//Then, we try to print the result of the evaluation to the user
if (!val.get_type_info().bare_equal(chaiscript::user_type<void>())) {
try {
std::cout << chai.eval<std::function<std::string(const chaiscript::Boxed_Value &bv)> >("to_string")(val) << std::endl;
}
catch (...) {} //If we can't, do nothing
}
}
catch (const chaiscript::exception::eval_error &ee) {
std::cout << ee.what();
if (ee.call_stack.size() > 0) {
std::cout << "during evaluation at (" << ee.call_stack[0]->start.line << ", " << ee.call_stack[0]->start.column << ")";
}
std::cout << std::endl;
}
catch (const std::exception &e) {
std::cout << e.what();
std::cout << std::endl;
}
}
}
int main(int argc, char *argv[])
{
// Disable deprecation warning for getenv call.
#ifdef CHAISCRIPT_MSVC
#pragma warning(push)
#pragma warning(disable : 4996)
#endif
const char *usepath = getenv("CHAI_USE_PATH");
const char *modulepath = getenv("CHAI_MODULE_PATH");
#ifdef CHAISCRIPT_MSVC
#pragma warning(pop)
#endif
std::vector<std::string> usepaths;
usepaths.push_back("");
if (usepath)
{
usepaths.push_back(usepath);
}
std::vector<std::string> modulepaths;
std::vector<std::string> searchpaths = default_search_paths();
modulepaths.insert(modulepaths.end(), searchpaths.begin(), searchpaths.end());
modulepaths.push_back("");
if (modulepath)
{
modulepaths.push_back(modulepath);
}
//chaiscript::ChaiScript chai(modulepaths, usepaths);
chaiscript::ChaiScript chai(chaiscript::Std_Lib::library(), usepaths);
chai.add(chaiscript::fun(&myexit), "exit");
chai.add(chaiscript::fun(&myexit), "quit");
chai.add(chaiscript::fun(&help), "help");
chai.add(chaiscript::fun(&throws_exception), "throws_exception");
chai.add(chaiscript::fun(&get_eval_error), "get_eval_error");
chai.add(chaiscript::fun(&helloWorld), "helloWorld");
clock_t begin = clock();
for (int i = 0; i < 1000; i++)
{
std::string str = helloWorld("Bob12345");
fwrite(str.c_str(), 1, str.size(), stdout);
}
clock_t end = clock();
double elapsed_secs = double(end - begin) / CLOCKS_PER_SEC;
//begin = clock();
////for (int i = 0; i < 1000; i++)
////{
//// chai.eval("puts(helloWorld(\"Bob12345\"));");
////}
//chai.eval_file("E:\\C++\\ChaiScript - 5.4.0\\samples\forx.chai");
//end = clock();
//elapsed_secs = double(end - begin) / CLOCKS_PER_SEC;
//printf("**MyProgram::time= %lf\n", elapsed_secs);
for (int i = 0; i < argc; ++i) {
if (i == 0 && argc > 1) {
++i;
}
std::string arg(i ? argv[i] : "--interactive");
enum {
eInteractive
, eCommand
, eFile
} mode = eCommand;
if (arg == "-c" || arg == "--command") {
if ((i + 1) >= argc) {
std::cout << "insufficient input following " << arg << std::endl;
return EXIT_FAILURE;
}
else {
arg = argv[++i];
}
}
else if (arg == "-" || arg == "--stdin") {
arg = "";
std::string line;
while (std::getline(std::cin, line)) {
arg += line + '\n';
}
}
else if (arg == "-v" || arg == "--version") {
arg = "version()";
}
else if (arg == "-h" || arg == "--help") {
arg = "help(-1)";
}
else if (arg == "-i" || arg == "--interactive") {
mode = eInteractive;
}
else if (arg.find('-') == 0) {
std::cout << "unrecognised argument " << arg << std::endl;
return EXIT_FAILURE;
}
else {
mode = eFile;
}
chaiscript::Boxed_Value val;
try {
switch (mode) {
case eInteractive: interactive(chai); break;
case eCommand: val = chai.eval(arg); break;
case eFile: {
begin = clock();
val = chai.eval_file(arg);
end = clock();
double elapsed_secs1 = double(end - begin) / CLOCKS_PER_SEC;
printf("**C++::time= %.10f\n", elapsed_secs);
printf("**ChaiScript::time= %.10f\n", elapsed_secs1);
break;
}
}
}
catch (const chaiscript::exception::eval_error &ee) {
std::cout << ee.pretty_print();
std::cout << std::endl;
return EXIT_FAILURE;
}
catch (std::exception &e) {
std::cout << e.what() << std::endl;
return EXIT_FAILURE;
}
}
return EXIT_SUCCESS;
}

View File

@@ -8,9 +8,7 @@ class BaseClass
{
}
BaseClass(const BaseClass &) = default;
virtual ~BaseClass() {}
virtual ~BaseClass() = default;
virtual std::string doSomething(float, double) const = 0;
@@ -44,14 +42,14 @@ class ChaiScriptDerived : public BaseClass
tie(t_funcs.at(1), m_validateValueImpl);
}
std::string doSomething(float f, double d) const CHAISCRIPT_OVERRIDE
std::string doSomething(float f, double d) const override
{
assert(m_doSomethingImpl);
return m_doSomethingImpl(*this, f, d);
}
protected:
bool validateValue(const std::string &t_val) CHAISCRIPT_OVERRIDE
bool validateValue(const std::string &t_val) override
{
assert(m_validateValueImpl);
return m_validateValueImpl(*this, t_val);

View File

@@ -54,7 +54,7 @@ class test
chaiscript::Boxed_Value val = chai.eval_file(sFile);
}
catch (std::exception &e) {
std::cout << e.what() << '\n';
std::cout << e.what() << std::endl;
}
}

View File

@@ -1,17 +1,14 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#include <iostream>
#include <list>
#include <regex>
#ifdef _MSC_VER
#define _CRT_SECURE_NO_WARNINGS
#endif
#include <chaiscript/chaiscript.hpp>
#ifdef READLINE_AVAILABLE
@@ -21,7 +18,7 @@
char *mystrdup (const char *s) {
size_t len = strlen(s); // Space for length plus nul
char *d = static_cast<char*>(malloc (len+1));
char *d = static_cast<char*>(malloc (len+1));
if (d == nullptr) return nullptr; // No memory
#ifdef CHAISCRIPT_MSVC
strcpy_s(d, len, s); // Copy the characters
@@ -139,22 +136,26 @@ std::vector<std::string> default_search_paths()
void help(int n) {
if ( n >= 0 ) {
std::cout << "ChaiScript evaluator. To evaluate an expression, type it and press <enter>.\n";
std::cout << "Additionally, you can inspect the runtime system using:\n";
std::cout << " dump_system() - outputs all functions registered to the system\n";
std::cout << " dump_object(x) - dumps information about the given symbol\n";
std::cout << "ChaiScript evaluator. To evaluate an expression, type it and press <enter>." << std::endl;
std::cout << "Additionally, you can inspect the runtime system using:" << std::endl;
std::cout << " dump_system() - outputs all functions registered to the system" << std::endl;
std::cout << " dump_object(x) - dumps information about the given symbol" << std::endl;
} else {
std::cout << "usage : chai [option]+\n";
std::cout << "option:" << '\n';
std::cout << " -h | --help" << '\n';
std::cout << " -i | --interactive" << '\n';
std::cout << " -c | --command cmd" << '\n';
std::cout << " -v | --version" << '\n';
std::cout << " - --stdin" << '\n';
std::cout << " filepath" << '\n';
std::cout << "usage : chai [option]+" << std::endl;
std::cout << "option:" << std::endl;
std::cout << " -h | --help" << std::endl;
std::cout << " -i | --interactive" << std::endl;
std::cout << " -c | --command cmd" << std::endl;
std::cout << " -v | --version" << std::endl;
std::cout << " - --stdin" << std::endl;
std::cout << " filepath" << std::endl;
}
}
void version(int){
std::cout << "chai: compiled " << __TIME__ << " " << __DATE__ << std::endl;
}
bool throws_exception(const std::function<void ()> &f)
{
try {
@@ -230,7 +231,7 @@ void interactive(chaiscript::ChaiScript& chai)
//Then, we try to print the result of the evaluation to the user
if (!val.get_type_info().bare_equal(chaiscript::user_type<void>())) {
try {
std::cout << chai.eval<std::function<std::string (const chaiscript::Boxed_Value &bv)> >("to_string")(val) << '\n';
std::cout << chai.eval<std::function<std::string (const chaiscript::Boxed_Value &bv)> >("to_string")(val) << std::endl;
}
catch (...) {} //If we can't, do nothing
}
@@ -240,11 +241,11 @@ void interactive(chaiscript::ChaiScript& chai)
if (ee.call_stack.size() > 0) {
std::cout << "during evaluation at (" << ee.call_stack[0]->start.line << ", " << ee.call_stack[0]->start.column << ")";
}
std::cout << '\n';
std::cout << std::endl;
}
catch (const std::exception &e) {
std::cout << e.what();
std::cout << '\n';
std::cout << std::endl;
}
}
}
@@ -286,6 +287,7 @@ int main(int argc, char *argv[])
chai.add(chaiscript::fun(&myexit), "exit");
chai.add(chaiscript::fun(&myexit), "quit");
chai.add(chaiscript::fun(&help), "help");
chai.add(chaiscript::fun(&version), "version");
chai.add(chaiscript::fun(&throws_exception), "throws_exception");
chai.add(chaiscript::fun(&get_eval_error), "get_eval_error");
@@ -303,7 +305,7 @@ int main(int argc, char *argv[])
if ( arg == "-c" || arg == "--command" ) {
if ( (i+1) >= argc ) {
std::cout << "insufficient input following " << arg << '\n';
std::cout << "insufficient input following " << arg << std::endl;
return EXIT_FAILURE;
} else {
arg = argv[++i];
@@ -315,13 +317,13 @@ int main(int argc, char *argv[])
arg += line + '\n' ;
}
} else if ( arg == "-v" || arg == "--version" ) {
arg = "version()" ;
arg = "version(0)" ;
} else if ( arg == "-h" || arg == "--help" ) {
arg = "help(-1)";
} else if ( arg == "-i" || arg == "--interactive" ) {
mode = eInteractive ;
} else if ( arg.find('-') == 0 ) {
std::cout << "unrecognised argument " << arg << '\n';
std::cout << "unrecognised argument " << arg << std::endl;
return EXIT_FAILURE;
} else {
mode = eFile;
@@ -330,23 +332,19 @@ int main(int argc, char *argv[])
chaiscript::Boxed_Value val ;
try {
switch ( mode ) {
case eInteractive:
interactive(chai);
break;
case eCommand:
val = chai.eval(arg);
break;
case eFile:
val = chai.eval_file(arg);
case eInteractive : interactive(chai); break;
case eCommand : val = chai.eval(arg); break;
case eFile : val = chai.eval_file(arg); break;
default : std::cout << "Unrecognized execution mode" << std::endl; return EXIT_FAILURE;
}
}
catch (const chaiscript::exception::eval_error &ee) {
std::cout << ee.pretty_print();
std::cout << '\n';
std::cout << std::endl;
return EXIT_FAILURE;
}
catch (std::exception &e) {
std::cout << e.what() << '\n';
std::cout << e.what() << std::endl;
return EXIT_FAILURE;
}
}

View File

@@ -1,7 +1,7 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com
#include <chaiscript/chaiscript.hpp>

View File

@@ -2,15 +2,12 @@
#include <chaiscript/chaiscript.hpp>
#include <string>
class TestBaseType
{
public:
TestBaseType() : val(10), const_val(15) { }
TestBaseType(int) : val(10), const_val(15) {}
TestBaseType(int *) : val(10), const_val(15) { }
TestBaseType(const TestBaseType &) = default;
TestBaseType(int *) : val(10), const_val(15) {}
virtual ~TestBaseType() {}
virtual int func() { return 0; }
@@ -25,30 +22,6 @@ class TestBaseType
TestBaseType &operator=(const TestBaseType &);
};
class Type2
{
public:
Type2(TestBaseType t_bt)
: m_bt(std::move(t_bt)),
m_str("Hello World")
{
}
int get_val() const
{
return m_bt.val;
}
const char *get_str() const
{
return m_str.c_str();
}
private:
TestBaseType m_bt;
std::string m_str;
};
enum TestEnum
{
TestValue1 = 1
@@ -63,8 +36,6 @@ class TestDerivedType : public TestBaseType
{
public:
virtual ~TestDerivedType() {}
TestDerivedType(const TestDerivedType &) = default;
TestDerivedType() = default;
virtual int func() CHAISCRIPT_OVERRIDE { return 1; }
int derived_only_func() { return 19; }
@@ -75,8 +46,6 @@ class TestDerivedType : public TestBaseType
class TestMoreDerivedType : public TestDerivedType
{
public:
TestMoreDerivedType(const TestMoreDerivedType &) = default;
TestMoreDerivedType() = default;
virtual ~TestMoreDerivedType() {}
};
@@ -100,11 +69,9 @@ std::string hello_world()
return "Hello World";
}
static int global_i = 1;
int *get_new_int()
{
return &global_i;
return new int(1);
}
// MSVC doesn't like that we are using C++ return types from our C declared module
@@ -128,7 +95,6 @@ CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_test_mo
m->add(chaiscript::user_type<TestBaseType>(), "TestBaseType");
m->add(chaiscript::user_type<TestDerivedType>(), "TestDerivedType");
m->add(chaiscript::user_type<TestMoreDerivedType>(), "TestMoreDerivedType");
m->add(chaiscript::user_type<Type2>(), "Type2");
m->add(chaiscript::constructor<TestBaseType ()>(), "TestBaseType");
// m->add(chaiscript::constructor<TestBaseType (int)>(), "TestBaseType");
@@ -169,12 +135,6 @@ CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_test_mo
m->add(chaiscript::fun(&to_int), "to_int");
m->add(chaiscript::fun(&TestBaseType::constMe), "constMe");
m->add(chaiscript::type_conversion<TestBaseType, Type2>([](const TestBaseType &t_bt) { return Type2(t_bt); }));
m->add(chaiscript::fun(&Type2::get_val), "get_val");
m->add(chaiscript::fun(&Type2::get_str), "get_str");
m->add(chaiscript::type_conversion<const char *, std::string>());
m->add(chaiscript::constructor<Type2 (const TestBaseType &)>(), "Type2");
return m;
}

View File

@@ -15,16 +15,16 @@ bool run_test_type_conversion(const Boxed_Value &bv, bool expectedpass)
use(ret);
} catch (const chaiscript::exception::bad_boxed_cast &/*e*/) {
if (expectedpass) {
// std::cerr << "Failure in run_test_type_conversion: " << e.what() << '\n';
// std::cerr << "Failure in run_test_type_conversion: " << e.what() << std::endl;
return false;
} else {
return true;
}
} catch (const std::exception &e) {
std::cerr << "Unexpected standard exception when attempting cast_conversion: " << e.what() << '\n';
std::cerr << "Unexpected standard exception when attempting cast_conversion: " << e.what() << std::endl;
return false;
} catch (...) {
std::cerr << "Unexpected unknown exception when attempting cast_conversion.\n";
std::cerr << "Unexpected unknown exception when attempting cast_conversion." << std::endl;
return false;
}
@@ -47,7 +47,7 @@ bool test_type_conversion(const Boxed_Value &bv, bool expectedpass)
<< (bv.is_const()?(std::string("const ")):(std::string())) << bv.get_type_info().name()
<< " To: "
<< (std::is_const<To>::value?(std::string("const ")):(std::string())) << typeid(To).name()
<< " test was expected to " << ((expectedpass)?(std::string("succeed")):(std::string("fail"))) << " but did not\n";
<< " test was expected to " << ((expectedpass)?(std::string("succeed")):(std::string("fail"))) << " but did not" << std::endl;
}
return ret;
@@ -264,26 +264,21 @@ bool pointer_test(const T& default_value, const T& new_value)
if (p != (*result) ) {
std::cerr << "Pointer passed in different than one returned\n";
delete p;
std::cerr << "Pointer passed in different than one returned" << std::endl;
return false;
}
if (*p != *(*result) ) {
std::cerr << "Somehow dereferenced pointer values are not the same?\n";
delete p;
std::cerr << "Somehow dereferenced pointer values are not the same?" << std::endl;
return false;
}
delete p;
return true;
} catch (const exception::bad_boxed_cast &) {
std::cerr << "Bad boxed cast performing ** to ** test\n";
delete p;
std::cerr << "Bad boxed cast performing ** to ** test" << std::endl;
return false;
} catch (...) {
std::cerr << "Unknown exception performing ** to ** test\n";
delete p;
std::cerr << "Unknown exception performing ** to ** test" << std::endl;
return false;
}

View File

@@ -1,9 +0,0 @@
try {
3/0
assert_true(false); // should never get here
} catch (e) {
assert_equal("Arithmetic error: divide by zero", e.what())
}
assert_equal(3/0.0, Infinity)

View File

@@ -8,7 +8,7 @@ void assert_equal(const LHS &lhs, const RHS &rhs)
{
return;
} else {
std::cout << "Got: " << lhs << " expected " << rhs << '\n';
std::cout << "Got: " << lhs << " expected " << rhs << std::endl;
exit(EXIT_FAILURE);
}
}

View File

@@ -16,7 +16,7 @@ int test_generic()
}
}
std::cout << "test_generic failed\n";
std::cout << "test_generic failed" << std::endl;
return EXIT_FAILURE;
}
@@ -33,7 +33,7 @@ int test_1()
}
}
std::cout << "test_1 failed\n";
std::cout << "test_1 failed" << std::endl;
return EXIT_FAILURE;
}
@@ -50,7 +50,7 @@ int test_2()
}
}
std::cout << "test_2 failed\n";
std::cout << "test_2 failed" << std::endl;
return EXIT_FAILURE;
}
@@ -61,22 +61,22 @@ int test_5()
try {
chai.eval("throw(runtime_error(\"error\"))", chaiscript::exception_specification<int, double, float, const std::string &, const std::exception &>());
} catch (const double) {
std::cout << "test_5 failed with double\n";
std::cout << "test_5 failed with double" << std::endl;
return EXIT_FAILURE;
} catch (int) {
std::cout << "test_5 failed with int\n";
std::cout << "test_5 failed with int" << std::endl;
return EXIT_FAILURE;
} catch (float) {
std::cout << "test_5 failed with float\n";
std::cout << "test_5 failed with float" << std::endl;
return EXIT_FAILURE;
} catch (const std::string &) {
std::cout << "test_5 failed with string\n";
std::cout << "test_5 failed with string" << std::endl;
return EXIT_FAILURE;
} catch (const std::exception &) {
return EXIT_SUCCESS;
}
std::cout << "test_5 failed\n";
std::cout << "test_5 failed" << std::endl;
return EXIT_FAILURE;
}
@@ -87,22 +87,22 @@ int test_unhandled()
try {
chai.eval("throw(\"error\")", chaiscript::exception_specification<int, double, float, const std::exception &>());
} catch (double) {
std::cout << "test_unhandled failed with double\n";
std::cout << "test_unhandled failed with double" << std::endl;
return EXIT_FAILURE;
} catch (int) {
std::cout << "test_unhandled failed with int\n";
std::cout << "test_unhandled failed with int" << std::endl;
return EXIT_FAILURE;
} catch (float) {
std::cout << "test_unhandled failed with float\n";
std::cout << "test_unhandled failed with float" << std::endl;
return EXIT_FAILURE;
} catch (const std::exception &) {
std::cout << "test_unhandled failed with std::exception\n";
std::cout << "test_unhandled failed with std::exception" << std::endl;
return EXIT_FAILURE;
} catch (const chaiscript::Boxed_Value &) {
return EXIT_SUCCESS;
}
std::cout << "test_unhandled failed\n";
std::cout << "test_unhandled failed" << std::endl;
return EXIT_FAILURE;
}

View File

@@ -1,21 +0,0 @@
auto x = 1
try {
throw(x)
x = 2
}
catch(int e) {
x = e + 3
}
assert_equal(4, x);
x = 1
try {
throw(x)
x = 2
}
catch(string e) {
}
catch(e) {
x = e + 4
}
assert_equal(5, x);

View File

@@ -1,34 +0,0 @@
auto results = [];
for (auto i = 2; i < 6; ++i) {
try {
throw(i)
}
catch(int e) : e < 2 {
results.push_back("c1: " + e.to_string());
}
catch(int e) : e < 4 {
results.push_back("c2: " + e.to_string());
}
catch(e) {
results.push_back("c3: " + e.to_string());
}
catch {
// Should never get called
assert_equal(false, true)
}
}
try {
throw(3)
}
catch(int e) : e < 3
{
// Should never get called
assert_equal(false, true);
}
catch {
results.push_back("defaultcatch");
}
assert_equal(["c2: 2", "c2: 3", "c3: 4", "c3: 5", "defaultcatch"], results);

View File

@@ -1,6 +1,6 @@
#include <chaiscript/utility/utility.hpp>
int test_call(const std::function<int (int)> &f, int val)
double test_call(const std::function<double (int)> &f, int val)
{
return f(val);
}
@@ -9,15 +9,15 @@ int main()
{
chaiscript::ChaiScript chai;
chai.add(chaiscript::fun(&test_call), "test_call");
chai.eval("def func(i) { return i * 6; };");
int d = chai.eval<int>("test_call(func, 3)");
if (d == 3 * 6)
chai.eval("def func(i) { return i * 3.5; };");
double d = chai.eval<double>("test_call(func, 3)");
if (d == 3 * 3.5)
{
return EXIT_SUCCESS;
return EXIT_SUCCESS;
} else {
return EXIT_FAILURE;
}

View File

@@ -1,15 +0,0 @@
var func = fun(){
var ret = 0;
for (var i = 0; i < 50000; ++i) {
ret += i;
}
return ret;
}
var fut1 := async(func);
var fut2 := async(func);
// simply executing without crashing is good enough for this test
print(" ${fut1.get()} ${fut2.get()} ")

View File

@@ -7,7 +7,7 @@ bool test_literal(T val, const std::string &str)
{
chaiscript::ChaiScript chai;
T val2 = chai.eval<T>(str);
std::cout << "Comparing : " << val << " " << val2 << '\n';
std::cout << "Comparing : " << val << " " << val2 << std::endl;
return val == val2;
}

View File

@@ -1,70 +0,0 @@
#include <chaiscript/chaiscript.hpp>
#include <chaiscript/chaiscript_stdlib.hpp>
template<typename T>
struct Vector2
{
Vector2() : x(0), y(0) {}
Vector2(T px, T py) : x(px), y(py) {}
Vector2(const Vector2& cp) : x(cp.x), y(cp.y) {}
Vector2& operator+=(const Vector2& vec_r)
{
x += vec_r.x;
y += vec_r.y;
return *this;
}
Vector2 operator+(const Vector2& vec_r)
{
return Vector2(*this += vec_r);
}
Vector2 &operator=(const Vector2& ver_r)
{
x = ver_r.x;
y = ver_r.y;
return *this;
}
T x;
T y;
};
Vector2<float> GetValue()
{
return Vector2<float>(10,15);
}
int main()
{
chaiscript::ChaiScript _script(chaiscript::Std_Lib::library());
//Registering stuff
_script.add(chaiscript::user_type<Vector2<float>>(), "Vector2f");
_script.add(chaiscript::constructor<Vector2<float> ()>(), "Vector2f");
_script.add(chaiscript::constructor<Vector2<float> (float, float)>(), "Vector2f");
_script.add(chaiscript::constructor<Vector2<float> (const Vector2<float>&)>(), "Vector2f");
_script.add(chaiscript::fun(&Vector2<float>::x), "x");
_script.add(chaiscript::fun(&Vector2<float>::y), "y");
_script.add(chaiscript::fun(&Vector2<float>::operator +), "+");
_script.add(chaiscript::fun(&Vector2<float>::operator +=), "+=");
_script.add(chaiscript::fun(&Vector2<float>::operator =), "=");
_script.add(chaiscript::fun(&GetValue), "getValue");
_script.eval(R"(
var test = 0.0
var test2 = Vector2f(10,10)
test = getValue().x
print(test)
print(test2.x)
)");
if (_script.eval<std::string>("to_string(test)") != "10") { return EXIT_FAILURE; }
if (_script.eval<std::string>("to_string(test2.x)") != "10") { return EXIT_FAILURE; }
//_script.eval_file("object_lifetime_test2.inc");
}

View File

@@ -31,7 +31,7 @@ int main()
test_type(chaiscript::user_type<const int *>(), true, true, false, false, false);
test_type(chaiscript::Type_Info(), false, false, false, false, true);
std::cout << "Size of Type_Info " << sizeof(chaiscript::Type_Info) << '\n';
std::cout << "Size of Type_Info " << sizeof(chaiscript::Type_Info) << std::endl;
return EXIT_SUCCESS;
}

View File

@@ -1,11 +0,0 @@
add_type_conversion(type("string"), type("Type_Info"), fun(s) { return type(s); });
// This looks simple, but it takes the string "string" and using the registered
// conversion above, automatically converts that into a Type_Info object, which then
// allows the Type_Info.name() function to be called
assert_equal("string".name(), "string");

View File

@@ -1,27 +0,0 @@
load_module("test_module")
auto t := TestBaseType();
// This uses the TestBaseType to Type2 user type
// conversion which was added in the module and then calls
// "get_val()" which exists on the Type2 type
//assert_equal(t.get_val(), 10);
//print("Made it past test 1");
var t2 := Type2(t);
var str = string(get_str(t2));
assert_equal("Hello World", str);
print("Made it past test 2");
assert_equal(11, size(get_str(t2)));
print("Made it past test 3");
assert_equal(11, t2.get_str().size());
print("Made it past test 4");
assert_equal(11, t.get_str().size());
print("Made it past test 5");