diff --git a/.decent_ci-Linux.yaml b/.decent_ci-Linux.yaml index 45fdd6fb..31c7b52c 100644 --- a/.decent_ci-Linux.yaml +++ b/.decent_ci-Linux.yaml @@ -21,5 +21,5 @@ compilers: 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 + compiler_extra_flags: --enable=all -I include --inline-suppr -Umax --suppress="*:cmake*" diff --git a/.decent_ci-MacOS.yaml b/.decent_ci-MacOS.yaml index f8a07ca6..f297a14f 100644 --- a/.decent_ci-MacOS.yaml +++ b/.decent_ci-MacOS.yaml @@ -1,6 +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 diff --git a/.decent_ci-Windows.yaml b/.decent_ci-Windows.yaml index 69fee144..f1d48659 100644 --- a/.decent_ci-Windows.yaml +++ b/.decent_ci-Windows.yaml @@ -2,21 +2,21 @@ 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 + compiler_extra_flags: /analyze skip_packaging: true - 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 + compiler_extra_flags: /analyze skip_packaging: true - 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 diff --git a/CMakeLists.txt b/CMakeLists.txt index a692ee6e..36b56982 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -81,8 +81,8 @@ 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 5) -set(CPACK_PACKAGE_VERSION_PATCH 1) +set(CPACK_PACKAGE_VERSION_MINOR 6) +set(CPACK_PACKAGE_VERSION_PATCH 0) set(CPACK_PACKAGE_EXECUTABLES "chai;ChaiScript Eval") set(CPACK_PACKAGE_VENDOR "ChaiScript.com") @@ -152,7 +152,13 @@ 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 -pedantic ${CPP11_FLAG}) + 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() if(APPLE) add_definitions(-Wno-sign-compare) diff --git a/Doxyfile.in b/Doxyfile.in index 7f3402e3..5c068934 100644 --- a/Doxyfile.in +++ b/Doxyfile.in @@ -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 = ${CMAKE_BINARY_DIR}/docs +PROJECT_BRIEF = "An easy to use embedded scripting language for C++." # 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 diff --git a/include/chaiscript/chaiscript.hpp b/include/chaiscript/chaiscript.hpp index d4b80c47..1f4cac73 100644 --- a/include/chaiscript/chaiscript.hpp +++ b/include/chaiscript/chaiscript.hpp @@ -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-2014, Jason Turner (jason@emptycrate.com) +// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) // http://www.chaiscript.com #ifndef CHAISCRIPT_HPP_ diff --git a/include/chaiscript/chaiscript_defines.hpp b/include/chaiscript/chaiscript_defines.hpp index 2b056036..5fbc4755 100644 --- a/include/chaiscript/chaiscript_defines.hpp +++ b/include/chaiscript/chaiscript_defines.hpp @@ -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-2014, Jason Turner (jason@emptycrate.com) +// Copyright 2009-2015, 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.8supports this natively +/// Currently only g++>=4.8 supports this natively /// \todo Make this support other compilers when possible #define CHAISCRIPT_HAS_THREAD_LOCAL #endif @@ -45,8 +45,8 @@ namespace chaiscript { static const int version_major = 5; - static const int version_minor = 5; - static const int version_patch = 1; + static const int version_minor = 6; + static const int version_patch = 0; } #endif diff --git a/include/chaiscript/chaiscript_stdlib.hpp b/include/chaiscript/chaiscript_stdlib.hpp index 8d4986a4..92483fd4 100644 --- a/include/chaiscript/chaiscript_stdlib.hpp +++ b/include/chaiscript/chaiscript_stdlib.hpp @@ -19,6 +19,11 @@ #include "dispatchkit/bootstrap_stl.hpp" #include "dispatchkit/boxed_value.hpp" +#ifndef CHAISCRIPT_NO_THREADS +#include +#endif + + /// @file /// /// This file generates the standard library that normal ChaiScript usage requires. @@ -40,6 +45,11 @@ namespace chaiscript lib->add(standard_library::map_type >("Map")); lib->add(standard_library::pair_type >("Pair")); +#ifndef CHAISCRIPT_NO_THREADS + lib->add(standard_library::future_type>("future")); + lib->add(chaiscript::fun (const std::function &)>([](const std::function &t_func){ return std::async(std::launch::async, t_func);}), "async"); +#endif + return lib; } diff --git a/include/chaiscript/chaiscript_threading.hpp b/include/chaiscript/chaiscript_threading.hpp index 485f7eed..45681163 100644 --- a/include/chaiscript/chaiscript_threading.hpp +++ b/include/chaiscript/chaiscript_threading.hpp @@ -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-2014, Jason Turner (jason@emptycrate.com) +// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) // http://www.chaiscript.com #ifndef CHAISCRIPT_THREADING_HPP_ @@ -82,16 +82,27 @@ namespace chaiscript t().erase(m_key); } - inline T *operator->() const + inline const T *operator->() const { return &(t()[m_key]); } - inline T &operator*() const + inline const 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: @@ -117,12 +128,22 @@ namespace chaiscript { } - inline T *operator->() const + inline const T *operator->() const { return get_tls().get(); } - inline T &operator*() const + inline const T &operator*() const + { + return *get_tls(); + } + + inline T *operator->() + { + return get_tls().get(); + } + + inline T &operator*() { return *get_tls(); } diff --git a/include/chaiscript/dispatchkit/any.hpp b/include/chaiscript/dispatchkit/any.hpp index 7c403b76..8a624b1e 100644 --- a/include/chaiscript/dispatchkit/any.hpp +++ b/include/chaiscript/dispatchkit/any.hpp @@ -26,6 +26,8 @@ namespace chaiscript { { } + bad_any_cast(const bad_any_cast &) = default; + virtual ~bad_any_cast() CHAISCRIPT_NOEXCEPT {} /// \brief Description of what error occurred @@ -105,7 +107,7 @@ namespace chaiscript { } } -#if _MSC_VER != 1800 +#if !defined(_MSC_VER) || _MSC_VER != 1800 Any(Any &&) = default; Any &operator=(Any &&t_any) = default; #endif diff --git a/include/chaiscript/dispatchkit/bad_boxed_cast.hpp b/include/chaiscript/dispatchkit/bad_boxed_cast.hpp index 648eb417..31344d45 100644 --- a/include/chaiscript/dispatchkit/bad_boxed_cast.hpp +++ b/include/chaiscript/dispatchkit/bad_boxed_cast.hpp @@ -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-2014, Jason Turner (jason@emptycrate.com) +// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) // http://www.chaiscript.com #ifndef CHAISCRIPT_BAD_BOXED_CAST_HPP_ @@ -45,7 +45,8 @@ namespace chaiscript { } - virtual ~bad_boxed_cast() CHAISCRIPT_NOEXCEPT {} + bad_boxed_cast(const bad_boxed_cast &) = default; + virtual ~bad_boxed_cast() CHAISCRIPT_NOEXCEPT {} /// \brief Description of what error occurred virtual const char * what() const CHAISCRIPT_NOEXCEPT CHAISCRIPT_OVERRIDE diff --git a/include/chaiscript/dispatchkit/bind_first.hpp b/include/chaiscript/dispatchkit/bind_first.hpp index 6a3adda9..92675e13 100644 --- a/include/chaiscript/dispatchkit/bind_first.hpp +++ b/include/chaiscript/dispatchkit/bind_first.hpp @@ -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-2014, Jason Turner (jason@emptycrate.com) +// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) // http://www.chaiscript.com #ifndef CHAISCRIPT_BIND_FIRST_HPP_ diff --git a/include/chaiscript/dispatchkit/bootstrap.hpp b/include/chaiscript/dispatchkit/bootstrap.hpp index 3e88daf3..6537ffd4 100644 --- a/include/chaiscript/dispatchkit/bootstrap.hpp +++ b/include/chaiscript/dispatchkit/bootstrap.hpp @@ -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-2014, Jason Turner (jason@emptycrate.com) +// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) // http://www.chaiscript.com #ifndef CHAISCRIPT_BOOTSTRAP_HPP_ @@ -396,10 +396,9 @@ namespace chaiscript m->add(user_type(), "runtime_error"); m->add(chaiscript::base_class()); - m->add(constructor(), "runtime_error"); - m->add(fun(std::function(&what)), "what"); + m->add(fun(std::function(&what)), "what"); m->add(user_type(), "Dynamic_Object"); m->add(constructor(), "Dynamic_Object"); @@ -487,7 +486,12 @@ 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::base_class()); + m->add(chaiscript::user_type(), "eval_error"); + m->add(chaiscript::base_class()); + + m->add(chaiscript::user_type(), "arithmetic_error"); + m->add(chaiscript::base_class()); + // chaiscript::bootstrap::standard_library::vector_type > >("AST_NodeVector", m); diff --git a/include/chaiscript/dispatchkit/bootstrap_stl.hpp b/include/chaiscript/dispatchkit/bootstrap_stl.hpp index acb8344c..da3aacf4 100644 --- a/include/chaiscript/dispatchkit/bootstrap_stl.hpp +++ b/include/chaiscript/dispatchkit/bootstrap_stl.hpp @@ -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-2014, Jason Turner (jason@emptycrate.com) +// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) // http://www.chaiscript.com /// \file @@ -246,6 +246,7 @@ namespace chaiscript template 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; @@ -564,6 +565,25 @@ namespace chaiscript return m; } + + + + /// Add a MapType container + /// http://www.sgi.com/tech/stl/Map.html + template + ModulePtr future_type(const std::string &type, ModulePtr m = ModulePtr(new Module())) + { + m->add(user_type(), type); + + m->add(fun([](const FutureType &t) { return t.valid(); }), "valid"); + m->add(fun(&FutureType::get), "get"); + m->add(fun(&FutureType::wait), "wait"); + + return m; + } + + + } } } diff --git a/include/chaiscript/dispatchkit/boxed_cast.hpp b/include/chaiscript/dispatchkit/boxed_cast.hpp index 1d11d6e1..40b78577 100644 --- a/include/chaiscript/dispatchkit/boxed_cast.hpp +++ b/include/chaiscript/dispatchkit/boxed_cast.hpp @@ -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-2014, Jason Turner (jason@emptycrate.com) +// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) // http://www.chaiscript.com #ifndef CHAISCRIPT_BOXED_CAST_HPP_ diff --git a/include/chaiscript/dispatchkit/boxed_cast_helper.hpp b/include/chaiscript/dispatchkit/boxed_cast_helper.hpp index 3222fd19..a71c7cde 100644 --- a/include/chaiscript/dispatchkit/boxed_cast_helper.hpp +++ b/include/chaiscript/dispatchkit/boxed_cast_helper.hpp @@ -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-2014, Jason Turner (jason@emptycrate.com) +// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) // http://www.chaiscript.com #ifndef CHAISCRIPT_BOXED_CAST_HELPER_HPP_ diff --git a/include/chaiscript/dispatchkit/boxed_number.hpp b/include/chaiscript/dispatchkit/boxed_number.hpp index 557a20a7..00427513 100644 --- a/include/chaiscript/dispatchkit/boxed_number.hpp +++ b/include/chaiscript/dispatchkit/boxed_number.hpp @@ -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-2014, Jason Turner (jason@emptycrate.com) +// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) // http://www.chaiscript.com #ifndef CHAISCRIPT_BOXED_NUMERIC_HPP_ @@ -22,6 +22,19 @@ namespace chaiscript { class Type_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 { @@ -33,16 +46,37 @@ 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 + static void check_divide_by_zero(T t, typename std::enable_if::value>::type* = 0) + { +#ifndef CHAISCRIPT_NO_PROTECT_DIVIDEBYZERO + if (t == 0) { + throw chaiscript::exception::arithmetic_error("divide by zero"); + } +#endif + } + + template + static void check_divide_by_zero(T, typename std::enable_if::value>::type* = 0) + { + } + struct boolean { -#ifdef __GNUC__ -#pragma GCC diagnostic ignored "-Wsign-compare" -#endif template static Boxed_Value go(Operators::Opers t_oper, const T &t, const U &u, const Boxed_Value &) { @@ -61,7 +95,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(); } } }; @@ -89,13 +123,14 @@ 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; @@ -122,13 +157,14 @@ 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; } @@ -146,6 +182,7 @@ 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); @@ -156,7 +193,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(); } } }; @@ -171,6 +208,7 @@ 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); @@ -181,7 +219,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(); } } }; @@ -327,7 +365,6 @@ namespace chaiscript return oss.str(); } - public: Boxed_Number() : bv(Boxed_Value(0)) @@ -340,6 +377,13 @@ 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 explicit Boxed_Number(T t) : bv(Boxed_Value(t)) { @@ -547,6 +591,7 @@ namespace chaiscript } } + // cppcheck-suppress operatorEq Boxed_Number operator=(const Boxed_Value &v) { validate_boxed_number(v); @@ -554,6 +599,7 @@ 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); @@ -843,14 +889,18 @@ namespace chaiscript struct Cast_Helper : Cast_Helper { }; - + /// Cast_Helper for converting from Boxed_Value to Boxed_Number template<> struct Cast_Helper : Cast_Helper { - }; + }; } +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif + #ifdef CHAISCRIPT_MSVC #pragma warning(pop) #endif diff --git a/include/chaiscript/dispatchkit/boxed_value.hpp b/include/chaiscript/dispatchkit/boxed_value.hpp index c73358c5..94825a51 100644 --- a/include/chaiscript/dispatchkit/boxed_value.hpp +++ b/include/chaiscript/dispatchkit/boxed_value.hpp @@ -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-2014, Jason Turner (jason@emptycrate.com) +// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) // http://www.chaiscript.com #ifndef CHAISCRIPT_BOXED_VALUE_HPP_ @@ -72,8 +72,8 @@ namespace chaiscript chaiscript::detail::Any m_obj; void *m_data_ptr; const void *m_const_data_ptr; - bool m_is_ref; std::unique_ptr> m_attrs; + bool m_is_ref; }; struct Object_Data diff --git a/include/chaiscript/dispatchkit/dispatchkit.hpp b/include/chaiscript/dispatchkit/dispatchkit.hpp index dfa167d1..f882b0db 100644 --- a/include/chaiscript/dispatchkit/dispatchkit.hpp +++ b/include/chaiscript/dispatchkit/dispatchkit.hpp @@ -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-2014, Jason Turner (jason@emptycrate.com) +// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) // http://www.chaiscript.com #ifndef CHAISCRIPT_DISPATCHKIT_HPP_ @@ -62,6 +62,8 @@ namespace chaiscript { } + reserved_word_error(const reserved_word_error &) = default; + virtual ~reserved_word_error() CHAISCRIPT_NOEXCEPT {} std::string word() const @@ -82,6 +84,8 @@ namespace chaiscript { } + illegal_name_error(const illegal_name_error &) = default; + virtual ~illegal_name_error() CHAISCRIPT_NOEXCEPT {} std::string name() const @@ -103,6 +107,8 @@ namespace chaiscript { } + name_conflict_error(const name_conflict_error &) = default; + virtual ~name_conflict_error() CHAISCRIPT_NOEXCEPT {} std::string name() const @@ -125,6 +131,7 @@ namespace chaiscript { } + global_non_const(const global_non_const &) = default; virtual ~global_non_const() CHAISCRIPT_NOEXCEPT {} }; } @@ -389,6 +396,8 @@ namespace chaiscript std::set m_reserved_words; State &operator=(const State &) = default; + State() = default; + State(const State &) = default; }; Dispatch_Engine() @@ -445,7 +454,7 @@ 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) const + void add_object(const std::string &name, const Boxed_Value &obj) { if (!get_stack_data().back().insert(std::make_pair(name, obj)).second) { @@ -695,10 +704,10 @@ namespace chaiscript /// std::map get_scripting_objects() const { - Stack_Holder &s = *m_stack_holder; + const Stack_Holder &s = *m_stack_holder; // We don't want the current context, but one up if it exists - StackData &stack = (s.stacks.size()==1)?(s.stacks.back()):(s.stacks[s.stacks.size()-2]); + const StackData &stack = (s.stacks.size()==1)?(s.stacks.back()):(s.stacks[s.stacks.size()-2]); std::map retval; @@ -965,7 +974,12 @@ namespace chaiscript private: /// Returns the current stack /// make const/non const versions - StackData &get_stack_data() const + const StackData &get_stack_data() const + { + return m_stack_holder->stacks.back(); + } + + StackData &get_stack_data() { return m_stack_holder->stacks.back(); } diff --git a/include/chaiscript/dispatchkit/dynamic_object.hpp b/include/chaiscript/dispatchkit/dynamic_object.hpp index 69c24d51..c300a8de 100644 --- a/include/chaiscript/dispatchkit/dynamic_object.hpp +++ b/include/chaiscript/dispatchkit/dynamic_object.hpp @@ -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-2014, Jason Turner (jason@emptycrate.com) +// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) // http://www.chaiscript.com #ifndef CHAISCRIPT_DYNAMIC_OBJECT_HPP_ @@ -19,7 +19,6 @@ #include "boxed_cast.hpp" #include "boxed_cast_helper.hpp" #include "boxed_value.hpp" -#include "proxy_functions.hpp" #include "type_info.hpp" namespace chaiscript { @@ -62,217 +61,6 @@ namespace chaiscript std::map 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(), t_func->get_arity()), - m_type_name(std::move(t_type_name)), m_func(t_func), m_doti(user_type()) - { - 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()) - { - 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(&f)) - { - return df->m_type_name == m_type_name && (*df->m_func) == (*m_func); - } else { - return false; - } - } - - virtual bool call_match(const std::vector &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 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 ¶ms, 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 build_param_types( - const std::vector &t_inner_types, const Type_Info& t_objectti) - { - std::vector types(t_inner_types); - - assert(types.size() > 1); - assert(types[1].bare_equal(user_type())); - types[1] = t_objectti; - return types; - } - - bool dynamic_object_typename_match(const Boxed_Value &bv, const std::string &name, - const std::unique_ptr &ti, const Type_Conversions &t_conversions) const - { - if (bv.get_type_info().bare_equal(m_doti)) - { - try { - const Dynamic_Object &d = boxed_cast(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 &bvs, const std::string &name, - const std::unique_ptr &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 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 build_type_list(const std::vector &tl) - { - auto begin = tl.begin(); - auto end = tl.end(); - - if (begin != end) - { - ++begin; - } - - return std::vector(begin, end); - } - - virtual ~Dynamic_Object_Constructor() {} - - virtual bool operator==(const Proxy_Function_Base &f) const CHAISCRIPT_OVERRIDE - { - const Dynamic_Object_Constructor *dc = dynamic_cast(&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 &vals, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE - { - std::vector 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 ¶ms, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE - { - auto bv = var(Dynamic_Object(m_type_name)); - std::vector 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 diff --git a/include/chaiscript/dispatchkit/dynamic_object_detail.hpp b/include/chaiscript/dispatchkit/dynamic_object_detail.hpp new file mode 100644 index 00000000..36e8dffd --- /dev/null +++ b/include/chaiscript/dispatchkit/dynamic_object_detail.hpp @@ -0,0 +1,251 @@ +// 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 +#include +#include +#include +#include +#include +#include + +#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()) + { + 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()) + { + 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(&f)) + { + return df->m_type_name == m_type_name && (*df->m_func) == (*m_func); + } else { + return false; + } + } + + virtual bool call_match(const std::vector &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 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 ¶ms, 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 build_param_types( + const std::vector &t_inner_types, const Type_Info& t_objectti) + { + std::vector types(t_inner_types); + + assert(types.size() > 1); + //assert(types[1].bare_equal(user_type())); + types[1] = t_objectti; + return types; + } + + bool dynamic_object_typename_match(const Boxed_Value &bv, const std::string &name, + const std::unique_ptr &ti, const Type_Conversions &t_conversions) const + { + if (bv.get_type_info().bare_equal(m_doti)) + { + try { + const Dynamic_Object &d = boxed_cast(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 &bvs, const std::string &name, + const std::unique_ptr &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 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 build_type_list(const std::vector &tl) + { + auto begin = tl.begin(); + auto end = tl.end(); + + if (begin != end) + { + ++begin; + } + + return std::vector(begin, end); + } + + virtual ~Dynamic_Object_Constructor() {} + + virtual bool operator==(const Proxy_Function_Base &f) const CHAISCRIPT_OVERRIDE + { + const Dynamic_Object_Constructor *dc = dynamic_cast(&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 &vals, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE + { + std::vector 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 ¶ms, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE + { + auto bv = var(Dynamic_Object(m_type_name)); + std::vector 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 + diff --git a/include/chaiscript/dispatchkit/exception_specification.hpp b/include/chaiscript/dispatchkit/exception_specification.hpp index e323484d..54f19c4d 100644 --- a/include/chaiscript/dispatchkit/exception_specification.hpp +++ b/include/chaiscript/dispatchkit/exception_specification.hpp @@ -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-2014, Jason Turner (jason@emptycrate.com) +// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) // http://www.chaiscript.com #ifndef CHAISCRIPT_EXCEPTION_SPECIFICATION_HPP_ diff --git a/include/chaiscript/dispatchkit/function_call.hpp b/include/chaiscript/dispatchkit/function_call.hpp index a434f07c..0a90ca22 100644 --- a/include/chaiscript/dispatchkit/function_call.hpp +++ b/include/chaiscript/dispatchkit/function_call.hpp @@ -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-2014, Jason Turner (jason@emptycrate.com) +// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) // http://www.chaiscript.com #ifndef CHAISCRIPT_FUNCTION_CALL_HPP_ diff --git a/include/chaiscript/dispatchkit/function_call_detail.hpp b/include/chaiscript/dispatchkit/function_call_detail.hpp index ee1d1bd6..798053d2 100644 --- a/include/chaiscript/dispatchkit/function_call_detail.hpp +++ b/include/chaiscript/dispatchkit/function_call_detail.hpp @@ -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-2014, Jason Turner (jason@emptycrate.com) +// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) // http://www.chaiscript.com #ifndef CHAISCRIPT_FUNCTION_CALL_DETAIL_HPP_ diff --git a/include/chaiscript/dispatchkit/handle_return.hpp b/include/chaiscript/dispatchkit/handle_return.hpp index 8f2ebfec..a9e11645 100644 --- a/include/chaiscript/dispatchkit/handle_return.hpp +++ b/include/chaiscript/dispatchkit/handle_return.hpp @@ -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-2014, Jason Turner (jason@emptycrate.com) +// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) // http://www.chaiscript.com #ifndef CHAISCRIPT_HANDLE_RETURN_HPP_ @@ -37,6 +37,11 @@ namespace chaiscript { return const_var(r); } + + static Boxed_Value handle(Ret &&r) + { + return Boxed_Value(std::move(r)); + } }; template diff --git a/include/chaiscript/dispatchkit/operators.hpp b/include/chaiscript/dispatchkit/operators.hpp index 353035e8..ce1bd977 100644 --- a/include/chaiscript/dispatchkit/operators.hpp +++ b/include/chaiscript/dispatchkit/operators.hpp @@ -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-2014, Jason Turner (jason@emptycrate.com) +// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) // http://www.chaiscript.com #ifndef CHAISCRIPT_OPERATORS_HPP_ diff --git a/include/chaiscript/dispatchkit/proxy_constructors.hpp b/include/chaiscript/dispatchkit/proxy_constructors.hpp index 64d2a930..f354ae58 100644 --- a/include/chaiscript/dispatchkit/proxy_constructors.hpp +++ b/include/chaiscript/dispatchkit/proxy_constructors.hpp @@ -1,13 +1,15 @@ // 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) +// Copyright 2009-2015, 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 diff --git a/include/chaiscript/dispatchkit/proxy_functions.hpp b/include/chaiscript/dispatchkit/proxy_functions.hpp index fba9b4ff..639c9813 100644 --- a/include/chaiscript/dispatchkit/proxy_functions.hpp +++ b/include/chaiscript/dispatchkit/proxy_functions.hpp @@ -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-2014, Jason Turner (jason@emptycrate.com) +// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) // http://www.chaiscript.com @@ -24,6 +24,7 @@ #include "boxed_value.hpp" #include "proxy_functions_detail.hpp" #include "type_info.hpp" +#include "dynamic_object.hpp" namespace chaiscript { class Type_Conversions; @@ -42,6 +43,95 @@ namespace chaiscript namespace dispatch { + class Param_Types + { + public: + Param_Types() + : m_has_types(false), + m_doti(user_type()) + {} + + Param_Types(std::vector> t_types) + : m_types(std::move(t_types)), + m_has_types(false), + m_doti(user_type()) + { + 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 &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(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> &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> 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++ @@ -129,7 +219,7 @@ namespace chaiscript virtual Boxed_Value do_call(const std::vector ¶ms, const Type_Conversions &t_conversions) const = 0; Proxy_Function_Base(std::vector t_types, int t_arity) - : m_types(std::move(t_types)), m_has_arithmetic_param(false), m_arity(t_arity) + : m_types(std::move(t_types)), m_arity(t_arity), m_has_arithmetic_param(false) { for (size_t i = 1; i < m_types.size(); ++i) { @@ -175,8 +265,8 @@ namespace chaiscript } std::vector m_types; - bool m_has_arithmetic_param; int m_arity; + bool m_has_arithmetic_param; }; } @@ -197,6 +287,8 @@ namespace chaiscript : std::runtime_error("Guard evaluation failed") { } + guard_error(const guard_error &) = default; + virtual ~guard_error() CHAISCRIPT_NOEXCEPT { } }; @@ -215,10 +307,13 @@ namespace chaiscript std::function &)> 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_arity), 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)) + : 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)) { } @@ -231,14 +326,15 @@ namespace chaiscript return this == &rhs || (prhs && this->m_arity == prhs->m_arity - && !this->m_guard && !prhs->m_guard); + && !this->m_guard && !prhs->m_guard + && this->m_param_types == prhs->m_param_types); } virtual bool call_match(const std::vector &vals, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE { - return (m_arity < 0 || vals.size() == size_t(m_arity)) + return (m_arity < 0 || (vals.size() == size_t(m_arity) && m_param_types.match(vals, t_conversions))) && test_guard(vals, t_conversions); - } + } Proxy_Function get_guard() const @@ -261,8 +357,7 @@ namespace chaiscript { if (m_arity < 0 || params.size() == size_t(m_arity)) { - - if (test_guard(params, t_conversions)) + if (call_match(params, t_conversions) && test_guard(params, t_conversions)) { return m_f(params); } else { @@ -291,29 +386,30 @@ namespace chaiscript } } - static std::vector build_param_type_list(int arity) + static std::vector build_param_type_list(const Param_Types &t_types) { std::vector types; // For the return type types.push_back(chaiscript::detail::Get_Type_Info::get()); - if (arity > 0) + for (const auto &t : t_types.types()) { - for (int i = 0; i < arity; ++i) - { + if (t.second.is_undef()) { types.push_back(chaiscript::detail::Get_Type_Info::get()); + } else { + types.push_back(t.second); } } return types; } - std::function &)> m_f; - int m_arity; - std::string m_description; + Param_Types m_param_types; Proxy_Function m_guard; AST_NodePtr m_parsenode; + std::string m_description; + std::function &)> m_f; }; /** @@ -560,7 +656,7 @@ namespace chaiscript } } else { throw exception::arity_error(static_cast(params.size()), 1); - } + } } private: @@ -589,6 +685,7 @@ namespace chaiscript { } + dispatch_error(const dispatch_error &) = default; virtual ~dispatch_error() CHAISCRIPT_NOEXCEPT {} std::vector parameters; diff --git a/include/chaiscript/dispatchkit/proxy_functions_detail.hpp b/include/chaiscript/dispatchkit/proxy_functions_detail.hpp index 744d40b4..5cb1d82a 100644 --- a/include/chaiscript/dispatchkit/proxy_functions_detail.hpp +++ b/include/chaiscript/dispatchkit/proxy_functions_detail.hpp @@ -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-2014, Jason Turner (jason@emptycrate.com) +// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) // http://www.chaiscript.com #ifndef CHAISCRIPT_PROXY_FUNCTIONS_DETAIL_HPP_ @@ -42,6 +42,8 @@ namespace chaiscript { } + arity_error(const arity_error &) = default; + virtual ~arity_error() CHAISCRIPT_NOEXCEPT {} int got; @@ -72,7 +74,7 @@ namespace chaiscript template struct Try_Cast { - static void do_try(const std::vector ¶ms, int generation, const Type_Conversions &t_conversions) + static void do_try(const std::vector ¶ms, size_t generation, const Type_Conversions &t_conversions) { boxed_cast(params[generation], &t_conversions); Try_Cast::do_try(params, generation+1, t_conversions); @@ -83,7 +85,7 @@ namespace chaiscript template<> struct Try_Cast<> { - static void do_try(const std::vector &, int, const Type_Conversions &) + static void do_try(const std::vector &, size_t, const Type_Conversions &) { } }; diff --git a/include/chaiscript/dispatchkit/register_function.hpp b/include/chaiscript/dispatchkit/register_function.hpp index a664922c..678f0a8d 100644 --- a/include/chaiscript/dispatchkit/register_function.hpp +++ b/include/chaiscript/dispatchkit/register_function.hpp @@ -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-2014, Jason Turner (jason@emptycrate.com) +// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) // http://www.chaiscript.com #ifndef CHAISCRIPT_REGISTER_FUNCTION_HPP_ diff --git a/include/chaiscript/dispatchkit/type_conversions.hpp b/include/chaiscript/dispatchkit/type_conversions.hpp index 59ad5e36..13eb6808 100644 --- a/include/chaiscript/dispatchkit/type_conversions.hpp +++ b/include/chaiscript/dispatchkit/type_conversions.hpp @@ -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-2014, Jason Turner (jason@emptycrate.com) +// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) // http://www.chaiscript.com #ifndef CHAISCRIPT_DYNAMIC_CAST_CONVERSION_HPP_ @@ -44,6 +44,8 @@ namespace chaiscript { } + bad_boxed_dynamic_cast(const bad_boxed_dynamic_cast &) = default; + virtual ~bad_boxed_dynamic_cast() CHAISCRIPT_NOEXCEPT {} }; @@ -66,6 +68,8 @@ namespace chaiscript { } + bad_boxed_type_cast(const bad_boxed_type_cast &) = default; + virtual ~bad_boxed_type_cast() CHAISCRIPT_NOEXCEPT {} }; } @@ -213,14 +217,20 @@ namespace chaiscript }; Type_Conversions() - : m_num_types(0), + : 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_conversions(t_other.get_conversions()), m_num_types(m_conversions.size()), + : m_mutex(), + m_conversions(t_other.get_conversions()), + m_convertableTypes(), + m_num_types(m_conversions.size()), m_thread_cache(this), m_conversion_saves(this) @@ -366,8 +376,8 @@ namespace chaiscript std::set> m_conversions; std::set m_convertableTypes; std::atomic_size_t m_num_types; - chaiscript::detail::threading::Thread_Storage> m_thread_cache; - chaiscript::detail::threading::Thread_Storage m_conversion_saves; + mutable chaiscript::detail::threading::Thread_Storage> m_thread_cache; + mutable chaiscript::detail::threading::Thread_Storage m_conversion_saves; }; typedef std::shared_ptr Type_Conversion; diff --git a/include/chaiscript/dispatchkit/type_info.hpp b/include/chaiscript/dispatchkit/type_info.hpp index 2cf64559..eaa791d6 100644 --- a/include/chaiscript/dispatchkit/type_info.hpp +++ b/include/chaiscript/dispatchkit/type_info.hpp @@ -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-2014, Jason Turner (jason@emptycrate.com) +// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) // http://www.chaiscript.com #ifndef CHAISCRIPT_TYPE_INFO_HPP_ diff --git a/include/chaiscript/language/chaiscript_algebraic.hpp b/include/chaiscript/language/chaiscript_algebraic.hpp index b5d1b315..aab4af74 100644 --- a/include/chaiscript/language/chaiscript_algebraic.hpp +++ b/include/chaiscript/language/chaiscript_algebraic.hpp @@ -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-2014, Jason Turner (jason@emptycrate.com) +// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) // http://www.chaiscript.com #ifndef CHAISCRIPT_ALGEBRAIC_HPP_ diff --git a/include/chaiscript/language/chaiscript_common.hpp b/include/chaiscript/language/chaiscript_common.hpp index 288b0cca..e383d16e 100644 --- a/include/chaiscript/language/chaiscript_common.hpp +++ b/include/chaiscript/language/chaiscript_common.hpp @@ -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-2014, Jason Turner (jason@emptycrate.com) +// Copyright 2009-2015, 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 + Logical_And, Logical_Or, Reference, Switch, Case, Default, Ternary_Cond, Noop, Class, Binary, Arg }; }; @@ -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"}; + "Logical_And", "Logical_Or", "Reference", "Switch", "Case", "Default", "Ternary Condition", "Noop", "Class", "Binary", "Arg"}; return ast_node_types[ast_node_type]; } @@ -112,6 +112,8 @@ namespace chaiscript reason(t_why) {} + eval_error(const eval_error &) = default; + std::string pretty_print() const { std::ostringstream ss; @@ -395,6 +397,7 @@ 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 {} }; diff --git a/include/chaiscript/language/chaiscript_engine.hpp b/include/chaiscript/language/chaiscript_engine.hpp index 523f49f3..89b555ee 100644 --- a/include/chaiscript/language/chaiscript_engine.hpp +++ b/include/chaiscript/language/chaiscript_engine.hpp @@ -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-2014, Jason Turner (jason@emptycrate.com) +// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) // http://www.chaiscript.com #ifndef CHAISCRIPT_ENGINE_HPP_ @@ -61,9 +61,8 @@ namespace chaiscript { } - virtual ~load_module_error() CHAISCRIPT_NOEXCEPT - { - } + load_module_error(const load_module_error &) = default; + virtual ~load_module_error() CHAISCRIPT_NOEXCEPT {} }; } @@ -371,10 +370,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, 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::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::add_global_const, this), "add_global_const"); m_engine.add(fun(&ChaiScript::add_global, this), "add_global"); @@ -464,7 +463,7 @@ namespace chaiscript memset( &rInfo, 0, sizeof(rInfo) ); cast_union u; u.in_ptr = &ChaiScript::use; - if ( dladdr((void*)(u.out_ptr), &rInfo) && rInfo.dli_fname ) { + if ( dladdr(static_cast(u.out_ptr), &rInfo) && rInfo.dli_fname ) { std::string dllpath(rInfo.dli_fname); const size_t lastslash = dllpath.rfind('/'); if (lastslash != std::string::npos) @@ -491,22 +490,22 @@ namespace chaiscript build_eval_system(ModulePtr()); } - int version_major() const + static int version_major() { return chaiscript::version_major; } - int version_minor() const + static int version_minor() { return chaiscript::version_minor; } - int version_patch() const + static int version_patch() { return chaiscript::version_patch; } - std::string version() const + static std::string version() { std::stringstream ss; ss << version_major() << "." << version_minor() << "." << version_patch(); @@ -581,6 +580,8 @@ 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 @@ -603,7 +604,7 @@ namespace chaiscript /// chaiscript::ChaiScript chai; /// chaiscript::ChaiScript::State s = chai.get_state(); // represents bootstrapped initial state /// \endcode - State get_state() + State get_state() const { chaiscript::detail::threading::lock_guard l(m_use_mutex); chaiscript::detail::threading::shared_lock l2(m_mutex); @@ -706,7 +707,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"|"")\(".dll"|".so"|""). + /// and with standard prefixes and postfixes: ("lib"|"")\(".dll"|".so"|".bundle"|""). /// /// Once the file is located, the system looks for the symbol "create_chaiscript_module_\". /// If no file can be found matching the search criteria and containing the appropriate entry point @@ -725,7 +726,7 @@ namespace chaiscript std::vector prefixes{"lib", "cyg", ""}; - std::vector postfixes{".dll", ".so", ""}; + std::vector postfixes{".dll", ".so", ".bundle", ""}; for (auto & elem : m_modulepaths) { diff --git a/include/chaiscript/language/chaiscript_eval.hpp b/include/chaiscript/language/chaiscript_eval.hpp index be9aabcc..33477d89 100644 --- a/include/chaiscript/language/chaiscript_eval.hpp +++ b/include/chaiscript/language/chaiscript_eval.hpp @@ -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-2014, Jason Turner (jason@emptycrate.com) +// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) // http://www.chaiscript.com #ifndef CHAISCRIPT_EVAL_HPP_ @@ -25,6 +25,7 @@ #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" @@ -93,6 +94,8 @@ 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); } @@ -349,6 +352,28 @@ namespace chaiscript }; + struct Arg_AST_Node : public AST_Node { + public: + Arg_AST_Node(std::string t_ast_node_text = "", const std::shared_ptr &t_fname=std::shared_ptr(), 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 &t_fname=std::shared_ptr(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) : @@ -369,6 +394,53 @@ 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 get_arg_names(const AST_NodePtr &t_node) { + std::vector retval; + + for (const auto &node : t_node->children) + { + retval.push_back(get_arg_name(node)); + } + + return retval; + } + + static std::pair get_arg_type(const AST_NodePtr &t_node, chaiscript::detail::Dispatch_Engine &t_ss) + { + if (t_node->children.size() < 2) + { + return std::pair(); + } else { + try { + return std::pair(t_node->children[0]->text, t_ss.get_type(t_node->children[0]->text)); + } catch (const std::range_error &) { + return std::pair(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> 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 { @@ -636,13 +708,12 @@ 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(); - - for (const auto &child : this->children[0]->children) - { - t_param_names.push_back(child->text); - } + 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); } const auto &lambda_node = this->children.back(); @@ -652,7 +723,7 @@ namespace chaiscript { return detail::eval_function(t_ss, lambda_node, t_param_names, t_params); }, - static_cast(numparams), lambda_node))); + static_cast(numparams), lambda_node, param_types))); } }; @@ -696,13 +767,12 @@ 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(); - - for (const auto &child : this->children[1]->children) - { - t_param_names.push_back(child->text); - } + 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); if (this->children.size() > 3) { guardnode = this->children[2]; @@ -735,7 +805,7 @@ namespace chaiscript { return detail::eval_function(t_ss, func_node, t_param_names, t_params); }, static_cast(numparams), this->children.back(), - l_annotation, guard)), l_function_name); + param_types, 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() + "'"); @@ -1186,11 +1256,74 @@ namespace chaiscript Try_AST_Node(const std::string &t_ast_node_text = "", const std::shared_ptr &t_fname=std::shared_ptr(), 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>{Arg_List_AST_Node::get_arg_type(catch_block->children[0], t_ss)} + ).match(std::vector{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(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); } @@ -1201,98 +1334,11 @@ namespace chaiscript throw; } catch (const std::exception &e) { - Boxed_Value except(std::ref(e)); + retval = handle_exception(t_ss, Boxed_Value(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(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 &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(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 (...) { if (this->children.back()->identifier == AST_Node_Type::Finally) { @@ -1301,6 +1347,7 @@ namespace chaiscript throw; } + if (this->children.back()->identifier == AST_Node_Type::Finally) { retval = this->children.back()->children[0]->eval(t_ss); } @@ -1333,29 +1380,29 @@ namespace chaiscript AST_NodePtr guardnode; - 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 auto d = t_ss.get_parent_locals(); + const auto itr = d.find("_current_class_name"); + const auto class_offset = (itr != d.end())?-1:0; const std::string & class_name = (itr != d.end())?std::string(boxed_cast(itr->second)):this->children[0]->text; //The first param of a method is always the implied this ptr. std::vector t_param_names{"this"}; + dispatch::Param_Types param_types; - if ((this->children.size() > static_cast(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(3 + class_offset)) && (this->children[static_cast(2 + class_offset)]->identifier == AST_Node_Type::Arg_List)) { + auto args = Arg_List_AST_Node::get_arg_names(this->children[static_cast(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(2 + class_offset)], t_ss); if (this->children.size() > static_cast(4 + class_offset)) { - guardnode = this->children[(3 + class_offset)]; + guardnode = this->children[static_cast(3 + class_offset)]; } } else { //no parameters if (this->children.size() > static_cast(3 + class_offset)) { - guardnode = this->children[(2 + class_offset)]; + guardnode = this->children[static_cast(2 + class_offset)]; } } @@ -1372,32 +1419,38 @@ namespace chaiscript try { const std::string & l_annotation = this->annotation?this->annotation->text:""; - const std::string & function_name = this->children[(1 + class_offset)]->text; + const std::string & function_name = this->children[static_cast(1 + class_offset)]->text; if (function_name == class_name) { + param_types.push_front(class_name, Type_Info()); t_ss.add(std::make_shared(class_name, std::make_shared(std::bind(chaiscript::eval::detail::eval_function, std::ref(t_ss), this->children.back(), t_param_names, std::placeholders::_1), - static_cast(numparams), this->children.back(), l_annotation, guard)), + static_cast(numparams), this->children.back(), param_types, l_annotation, guard)), function_name); } else { try { - // Do know type name + // 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); + t_ss.add( std::make_shared(class_name, std::make_shared(std::bind(chaiscript::eval::detail::eval_function, std::ref(t_ss), this->children.back(), t_param_names, std::placeholders::_1), static_cast(numparams), this->children.back(), - l_annotation, guard), t_ss.get_type(class_name)), function_name); + param_types, l_annotation, guard), type), 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(class_name, std::make_shared(std::bind(chaiscript::eval::detail::eval_function, std::ref(t_ss), this->children.back(), t_param_names, std::placeholders::_1), static_cast(numparams), this->children.back(), - l_annotation, guard)), function_name); + param_types, l_annotation, guard)), function_name); } } } @@ -1420,24 +1473,23 @@ namespace chaiscript { const auto &d = t_ss.get_parent_locals(); const auto itr = d.find("_current_class_name"); - int class_offset = 0; - if (itr != d.end()) class_offset = -1; + const auto class_offset = (itr != d.end())?-1:0; std::string class_name = (itr != d.end())?std::string(boxed_cast(itr->second)):this->children[0]->text; try { t_ss.add( std::make_shared( - class_name, + std::move(class_name), fun(std::function(std::bind(&dispatch::Dynamic_Object::get_attr, std::placeholders::_1, - this->children[(1 + class_offset)]->text + this->children[static_cast(1 + class_offset)]->text )) ) - ), this->children[(1 + class_offset)]->text); + ), this->children[static_cast(1 + class_offset)]->text); } catch (const exception::reserved_word_error &) { - throw exception::eval_error("Reserved word used as attribute '" + this->children[(1 + class_offset)]->text + "'"); + throw exception::eval_error("Reserved word used as attribute '" + this->children[static_cast(1 + class_offset)]->text + "'"); } catch (const exception::name_conflict_error &e) { throw exception::eval_error("Attribute redefined '" + e.name() + "'"); } diff --git a/include/chaiscript/language/chaiscript_parser.hpp b/include/chaiscript/language/chaiscript_parser.hpp index e9c40aa9..117f5d69 100644 --- a/include/chaiscript/language/chaiscript_parser.hpp +++ b/include/chaiscript/language/chaiscript_parser.hpp @@ -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-2014, Jason Turner (jason@emptycrate.com) +// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) // http://www.chaiscript.com #ifndef CHAISCRIPT_PARSER_HPP_ @@ -223,8 +223,8 @@ namespace chaiscript t_t->end.column = pos_col_stop; if (is_deep) { - 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()); + t_t->children.assign(m_match_stack.begin() + static_cast(t_match_start), m_match_stack.end()); + m_match_stack.erase(m_match_stack.begin() + static_cast(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 @@ -431,21 +431,13 @@ namespace chaiscript } } - std::stringstream ss(t_val.substr(0, i)); - if (float_) { - float f; - ss >> f; - return const_var(f); + return const_var(std::stof(t_val.substr(0,i))); } else if (long_) { - long double f; - ss >> f; - return const_var(f); + return const_var(std::stold(t_val.substr(0,i))); } else { - double f; - ss >> f; - return const_var(f); + return const_var(std::stod(t_val.substr(0,i))); } } @@ -699,6 +691,25 @@ 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(), prev_stack_top); + + return true; + } + + + /// Checks for a node annotation of the form "#" bool Annotation() { SkipWS(); @@ -1109,6 +1120,33 @@ 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(), prev_stack_top); + } + + SkipWS(true); + + return retval; + } + + /// Reads a comma-separated list of values from input bool Arg_List() { SkipWS(true); @@ -1186,7 +1224,7 @@ namespace chaiscript retval = true; if (Char('(')) { - Arg_List(); + Decl_Arg_List(); if (!Char(')')) { throw exception::eval_error("Incomplete anonymous function", File_Position(m_line, m_col), *m_filename); } @@ -1236,7 +1274,7 @@ namespace chaiscript } if (Char('(')) { - Arg_List(); + Decl_Arg_List(); if (!Char(')')) { throw exception::eval_error("Incomplete function definition", File_Position(m_line, m_col), *m_filename); } @@ -1291,7 +1329,7 @@ namespace chaiscript if (Keyword("catch", false)) { const auto catch_stack_top = m_match_stack.size(); if (Char('(')) { - if (!(Id(true) && Char(')'))) { + if (!(Arg() && Char(')'))) { throw exception::eval_error("Incomplete 'catch' expression", File_Position(m_line, m_col), *m_filename); } if (Char(':')) { @@ -1918,6 +1956,7 @@ namespace chaiscript 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(oper->text), prev_stack_top); break; diff --git a/include/chaiscript/language/chaiscript_prelude.chai b/include/chaiscript/language/chaiscript_prelude.chai index b4c0bc41..1db87027 100644 --- a/include/chaiscript/language/chaiscript_prelude.chai +++ b/include/chaiscript/language/chaiscript_prelude.chai @@ -455,37 +455,37 @@ def zip(x, y) { # Returns the position of the second value string in the first value string -def string::find(substr) : is_type(substr, "string") { +def string::find(string substr) { 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(substr) : is_type(substr, "string") { +def string::rfind(string substr) { 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(list) : is_type(list, "string") { +def string::find_first_of(string list) { 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(list) : is_type(list, "string") { +def string::find_last_of(string list) { 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(list) : is_type(list, "string") { +def string::find_first_not_of(string list) { 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(list) : is_type(list, "string") { +def string::find_last_not_of(string list) { find_last_not_of(this, list, size_t(-1)); } @@ -505,7 +505,7 @@ def string::trim() { } -def find(container, value, compare_func) : call_exists(range, container) && is_type(compare_func, "Function") { +def find(container, value, Function compare_func) : call_exists(range, container) { auto range := range(container); while (!range.empty()) { if (compare_func(range.front(), value)) { diff --git a/include/chaiscript/utility/utility.hpp b/include/chaiscript/utility/utility.hpp index 07fdff44..9c36b132 100644 --- a/include/chaiscript/utility/utility.hpp +++ b/include/chaiscript/utility/utility.hpp @@ -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-2014, Jason Turner (jason@emptycrate.com) +// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) // http://www.chaiscript.com #ifndef CHAISCRIPT_UTILITY_UTILITY_HPP_ diff --git a/license.txt b/license.txt index 3416309d..48f52923 100644 --- a/license.txt +++ b/license.txt @@ -1,4 +1,4 @@ -Copyright 2009-2014 Jason Turner +Copyright 2009-2015 Jason Turner Copyright 2009-2012 Jonathan Turner. All Rights Reserved. diff --git a/readme.md b/readme.md index 026ea091..f4446e7e 100644 --- a/readme.md +++ b/readme.md @@ -8,7 +8,7 @@ ChaiScript http://www.chaiscript.com (c) 2009-2012 Jonathan Turner -(c) 2009-2014 Jason Turner +(c) 2009-2015 Jason Turner Release under the BSD license, see "license.txt" for details. @@ -35,9 +35,10 @@ Requirements ============ ChaiScript requires a C++11 compiler to build with support for variadic -templates. It has been tested with gcc 4.7 and clang 3.1 (with libcxx). MacOS +templates. It has been tested with gcc 4.6 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. +clang 4.0. MSVC 2013 or newer is supports also. For more information see the build +[dashboard](http://chaiscript.com/ChaiScript-BuildResults/index.html). Usage ===== diff --git a/releasenotes.md b/releasenotes.md index d71c5b3d..e88dd36d 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -1,6 +1,31 @@ Notes: ======= -Current Version: 5.5.1 +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 diff --git a/samples/fun_call_performance.cpp b/samples/fun_call_performance.cpp index a689b5a4..c9830d02 100644 --- a/samples/fun_call_performance.cpp +++ b/samples/fun_call_performance.cpp @@ -1,14 +1,17 @@ // 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) +// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) // http://www.chaiscript.com #include #include #include +#ifdef _MSC_VER #define _CRT_SECURE_NO_WARNINGS +#endif + #include #include @@ -154,10 +157,6 @@ void help(int n) { } } -void version(int){ - std::cout << "chai: compiled " << __TIME__ << " " << __DATE__ << std::endl; -} - std::string helloWorld(const std::string &t_name) { return "Hello " + t_name + "!"; @@ -297,7 +296,6 @@ 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"); @@ -356,7 +354,7 @@ int main(int argc, char *argv[]) } } else if (arg == "-v" || arg == "--version") { - arg = "version(0)"; + arg = "version()"; } else if (arg == "-h" || arg == "--help") { arg = "help(-1)"; @@ -388,7 +386,7 @@ int main(int argc, char *argv[]) printf("**ChaiScript::time= %.10f\n", elapsed_secs1); break; } - default: std::cout << "Unrecognized execution mode" << std::endl; return EXIT_FAILURE; + } } catch (const chaiscript::exception::eval_error &ee) { diff --git a/samples/inheritance.cpp b/samples/inheritance.cpp index 5bd8c866..e8ef1921 100644 --- a/samples/inheritance.cpp +++ b/samples/inheritance.cpp @@ -8,6 +8,8 @@ class BaseClass { } + BaseClass(const BaseClass &) = default; + virtual ~BaseClass() {} virtual std::string doSomething(float, double) const = 0; diff --git a/src/main.cpp b/src/main.cpp index dead2219..109a5383 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,14 +1,17 @@ // 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) +// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) // http://www.chaiscript.com #include #include #include +#ifdef _MSC_VER #define _CRT_SECURE_NO_WARNINGS +#endif + #include #ifdef READLINE_AVAILABLE @@ -18,7 +21,7 @@ char *mystrdup (const char *s) { size_t len = strlen(s); // Space for length plus nul - char *d = static_cast(malloc (len+1)); + char *d = static_cast(malloc (len+1)); if (d == nullptr) return nullptr; // No memory #ifdef CHAISCRIPT_MSVC strcpy_s(d, len, s); // Copy the characters @@ -152,10 +155,6 @@ void help(int n) { } } -void version(int){ - std::cout << "chai: compiled " << __TIME__ << " " << __DATE__ << '\n'; -} - bool throws_exception(const std::function &f) { try { @@ -287,7 +286,6 @@ 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"); @@ -317,7 +315,7 @@ int main(int argc, char *argv[]) arg += line + '\n' ; } } else if ( arg == "-v" || arg == "--version" ) { - arg = "version(0)" ; + arg = "version()" ; } else if ( arg == "-h" || arg == "--help" ) { arg = "help(-1)"; } else if ( arg == "-i" || arg == "--interactive" ) { @@ -332,10 +330,14 @@ 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); break; - default : std::cout << "Unrecognized execution mode\n"; return EXIT_FAILURE; + case eInteractive: + interactive(chai); + break; + case eCommand: + val = chai.eval(arg); + break; + case eFile: + val = chai.eval_file(arg); } } catch (const chaiscript::exception::eval_error &ee) { diff --git a/src/stl_extra.cpp b/src/stl_extra.cpp index eb6bb8c5..6f0c5e48 100644 --- a/src/stl_extra.cpp +++ b/src/stl_extra.cpp @@ -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-2014, Jason Turner (jason@emptycrate.com) +// Copyright 2009-2015, Jason Turner (jason@emptycrate.com) // http://www.chaiscript.com #include diff --git a/src/test_module.cpp b/src/test_module.cpp index cb95326a..b1618175 100644 --- a/src/test_module.cpp +++ b/src/test_module.cpp @@ -9,7 +9,8 @@ class TestBaseType public: TestBaseType() : val(10), const_val(15) { } TestBaseType(int) : val(10), const_val(15) {} - TestBaseType(int *) : val(10), const_val(15) {} + TestBaseType(int *) : val(10), const_val(15) { } + TestBaseType(const TestBaseType &) = default; virtual ~TestBaseType() {} virtual int func() { return 0; } @@ -62,6 +63,8 @@ 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; } @@ -72,6 +75,8 @@ class TestDerivedType : public TestBaseType class TestMoreDerivedType : public TestDerivedType { public: + TestMoreDerivedType(const TestMoreDerivedType &) = default; + TestMoreDerivedType() = default; virtual ~TestMoreDerivedType() {} }; @@ -95,9 +100,11 @@ std::string hello_world() return "Hello World"; } +static int global_i = 1; + int *get_new_int() { - return new int(1); + return &global_i; } // MSVC doesn't like that we are using C++ return types from our C declared module diff --git a/unittests/boxed_cast_test.cpp b/unittests/boxed_cast_test.cpp index 4e94471c..46358417 100644 --- a/unittests/boxed_cast_test.cpp +++ b/unittests/boxed_cast_test.cpp @@ -265,20 +265,25 @@ 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; return false; } if (*p != *(*result) ) { std::cerr << "Somehow dereferenced pointer values are not the same?\n"; + delete p; return false; } + delete p; return true; } catch (const exception::bad_boxed_cast &) { std::cerr << "Bad boxed cast performing ** to ** test\n"; + delete p; return false; } catch (...) { std::cerr << "Unknown exception performing ** to ** test\n"; + delete p; return false; } diff --git a/unittests/divide_by_zero_protection.chai b/unittests/divide_by_zero_protection.chai new file mode 100644 index 00000000..db648fc1 --- /dev/null +++ b/unittests/divide_by_zero_protection.chai @@ -0,0 +1,9 @@ +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) + diff --git a/unittests/exception_typed.chai b/unittests/exception_typed.chai new file mode 100644 index 00000000..e7951c1e --- /dev/null +++ b/unittests/exception_typed.chai @@ -0,0 +1,21 @@ +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); diff --git a/unittests/exception_typed_2.chai b/unittests/exception_typed_2.chai new file mode 100644 index 00000000..cb294c78 --- /dev/null +++ b/unittests/exception_typed_2.chai @@ -0,0 +1,34 @@ +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); diff --git a/unittests/functor_cast_test.cpp b/unittests/functor_cast_test.cpp index 7c76ca20..5fa388f3 100644 --- a/unittests/functor_cast_test.cpp +++ b/unittests/functor_cast_test.cpp @@ -1,6 +1,6 @@ #include -double test_call(const std::function &f, int val) +int test_call(const std::function &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 * 3.5; };"); - double d = chai.eval("test_call(func, 3)"); - - if (d == 3 * 3.5) + chai.eval("def func(i) { return i * 6; };"); + int d = chai.eval("test_call(func, 3)"); + + if (d == 3 * 6) { - return EXIT_SUCCESS; + return EXIT_SUCCESS; } else { return EXIT_FAILURE; } diff --git a/unittests/future.chai b/unittests/future.chai new file mode 100644 index 00000000..750c27d4 --- /dev/null +++ b/unittests/future.chai @@ -0,0 +1,15 @@ +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()} ") diff --git a/unittests/object_lifetime_test2.cpp b/unittests/object_lifetime_test2.cpp index c99b1913..9716fef0 100644 --- a/unittests/object_lifetime_test2.cpp +++ b/unittests/object_lifetime_test2.cpp @@ -4,9 +4,9 @@ template 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() : 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) { @@ -20,10 +20,11 @@ struct Vector2 return Vector2(*this += vec_r); } - void operator=(const Vector2& ver_r) + Vector2 &operator=(const Vector2& ver_r) { x = ver_r.x; y = ver_r.y; + return *this; }