Merge pull request #557 from BerndAmend/develop

change .clang-format and reformat code with clang-format 11
This commit is contained in:
Rob Loach 2021-05-24 09:20:36 -04:00 committed by GitHub
commit 3aa1fa8278
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
82 changed files with 23373 additions and 25450 deletions

View File

@ -1,98 +1,33 @@
# clang-format: 11
AccessModifierOffset: -2 AccessModifierOffset: -2
AlignAfterOpenBracket: DontAlign AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: false AlignConsecutiveBitFields: false
AlignConsecutiveDeclarations: false AllowShortBlocksOnASingleLine: false
AlignEscapedNewlines: Left AllowShortFunctionsOnASingleLine: Inline
AlignOperands: true AllowShortLambdasOnASingleLine: All
AlignTrailingComments: false AlwaysBreakTemplateDeclarations: true
AllowAllParametersOfDeclarationOnNextLine: false BasedOnStyle: WebKit
AllowShortBlocksOnASingleLine: true BinPackArguments: true
AllowShortCaseLabelsOnASingleLine: false BinPackParameters: true
AllowShortFunctionsOnASingleLine: All BreakBeforeBraces: Attach
AllowShortIfStatementsOnASingleLine: true
AllowShortLoopsOnASingleLine: true
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: true
AlwaysBreakTemplateDeclarations: false
BinPackArguments: false
BinPackParameters: false
BraceWrapping:
AfterClass: true
AfterControlStatement: false
AfterEnum: false
AfterFunction: true
AfterNamespace: false
AfterObjCDeclaration: false
AfterStruct: true
AfterUnion: false
BeforeCatch: false
BeforeElse: false
IndentBraces: false
SplitEmptyFunction: false
SplitEmptyNamespace: true
SplitEmptyRecord: true
BreakAfterJavaFieldAnnotations: true
BreakBeforeBinaryOperators: NonAssignment
BreakBeforeBraces: Custom
BreakBeforeInheritanceComma: true
BreakBeforeTernaryOperators: true
BreakConstructorInitializers: BeforeColon
BreakConstructorInitializersBeforeComma: false
BreakStringLiterals: true
ColumnLimit: 0 ColumnLimit: 0
CommentPragmas: '^ IWYU pragma:' Cpp11BracedListStyle: true
CompactNamespaces: false
ConstructorInitializerAllOnOneLineOrOnePerLine: false
ConstructorInitializerIndentWidth: 2
ContinuationIndentWidth: 2
Cpp11BracedListStyle: false
DerivePointerAlignment: true
DisableFormat: false
ExperimentalAutoDetectBinPacking: true
FixNamespaceComments: true FixNamespaceComments: true
ForEachMacros: IncludeBlocks: Preserve
- foreach IndentCaseLabels: true
- Q_FOREACH IndentPPDirectives: None
- BOOST_FOREACH
IncludeCategories:
- Priority: 2
Regex: ^"(llvm|llvm-c|clang|clang-c)/
- Priority: 3
Regex: ^(<|"(gtest|gmock|isl|json)/)
- Priority: 1
Regex: .*
IncludeIsMainRegex: (Test)?$
IndentCaseLabels: false
IndentWidth: 2 IndentWidth: 2
IndentWrappedFunctionNames: true KeepEmptyLinesAtTheStartOfBlocks: false
JavaScriptQuotes: Leave NamespaceIndentation: All
JavaScriptWrapImports: true PenaltyBreakBeforeFirstCallParameter: 200
KeepEmptyLinesAtTheStartOfBlocks: true PenaltyBreakComment: 5
Language: Cpp PenaltyBreakFirstLessLess: 50
MacroBlockBegin: '' PenaltyExcessCharacter: 4
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 2
NamespaceIndentation: Inner
ObjCBlockIndentWidth: 7
ObjCSpaceAfterProperty: true
ObjCSpaceBeforeProtocolList: false
PointerAlignment: Right PointerAlignment: Right
ReflowComments: true SortIncludes: true
SortIncludes: false
SortUsingDeclarations: false
SpaceAfterCStyleCast: false
SpaceAfterTemplateKeyword: false SpaceAfterTemplateKeyword: false
SpaceBeforeAssignmentOperators: true SpaceBeforeCpp11BracedList: false
SpaceBeforeParens: ControlStatements SpaceInEmptyBlock: false
SpaceInEmptyParentheses: false Standard: Latest
SpacesBeforeTrailingComments: 0 TabWidth: 2
SpacesInAngles: false
SpacesInCStyleCastParentheses: false
SpacesInContainerLiterals: true
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: Cpp11
TabWidth: 8
UseTab: Never UseTab: Never

View File

@ -7,12 +7,9 @@
// This is an open source non-commercial project. Dear PVS-Studio, please check it. // This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com // PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_HPP_ #ifndef CHAISCRIPT_HPP_
#define CHAISCRIPT_HPP_ #define CHAISCRIPT_HPP_
/// @mainpage /// @mainpage
/// [ChaiScript](http://www.chaiscript.com") is a scripting language designed specifically for integration with C++. It provides /// [ChaiScript](http://www.chaiscript.com") is a scripting language designed specifically for integration with C++. It provides
/// seamless integration with C++ on all levels, including shared_ptr objects, functors and exceptions. /// seamless integration with C++ on all levels, including shared_ptr objects, functors and exceptions.
@ -22,7 +19,8 @@
/// ///
/// The end user parts of the API are extremely simple both in size and ease of use. /// The end user parts of the API are extremely simple both in size and ease of use.
/// ///
/// Currently, all source control and project management aspects of ChaiScript occur on [github](http://www.github.com/ChaiScript/ChaiScript"). /// Currently, all source control and project management aspects of ChaiScript occur on
/// [github](http://www.github.com/ChaiScript/ChaiScript").
/// ///
/// ------------------------------------------------------------ /// ------------------------------------------------------------
/// ///
@ -315,8 +313,8 @@
/// As much as possible, ChaiScript attempts to convert between &, *, const &, const *, std::shared_ptr<T>, /// As much as possible, ChaiScript attempts to convert between &, *, const &, const *, std::shared_ptr<T>,
/// std::shared_ptr<const T>, std::reference_wrapper<T>, std::reference_wrapper<const T> and value types automatically. /// std::shared_ptr<const T>, std::reference_wrapper<T>, std::reference_wrapper<const T> and value types automatically.
/// ///
/// If a chaiscript::var object was created in C++ from a pointer, it cannot be converted to a shared_ptr (this would add invalid reference counting). /// If a chaiscript::var object was created in C++ from a pointer, it cannot be converted to a shared_ptr (this would add invalid reference
/// Const may be added, but never removed. /// counting). Const may be added, but never removed.
/// ///
/// The take away is that you can pretty much expect function calls to Just Work when you need them to. /// The take away is that you can pretty much expect function calls to Just Work when you need them to.
/// ///
@ -470,7 +468,8 @@
/// chaiscript::ChaiScript chai; /// chaiscript::ChaiScript chai;
/// ///
/// try { /// try {
/// chai.eval("throw(runtime_error(@"error@"))", chaiscript::exception_specification<int, double, float, const std::string &, const std::exception &>()); /// chai.eval("throw(runtime_error(@"error@"))", chaiscript::exception_specification<int, double, float, const std::string &, const
/// std::exception &>());
/// } catch (const double e) { /// } catch (const double e) {
/// } catch (int) { /// } catch (int) {
/// } catch (float) { /// } catch (float) {
@ -483,8 +482,6 @@
/// @sa chaiscript::Exception_Handler for details on automatic exception unboxing /// @sa chaiscript::Exception_Handler for details on automatic exception unboxing
/// @sa chaiscript::exception_specification /// @sa chaiscript::exception_specification
/// @page LangObjectSystemRef ChaiScript Language Object Model Reference /// @page LangObjectSystemRef ChaiScript Language Object Model Reference
/// ///
/// ///
@ -652,7 +649,6 @@
/// @sa @ref LangKeywordRef /// @sa @ref LangKeywordRef
/// @sa ChaiScript_Language for Built in Functions /// @sa ChaiScript_Language for Built in Functions
/// @page LangKeywordRef ChaiScript Language Keyword Reference /// @page LangKeywordRef ChaiScript Language Keyword Reference
/// ///
/// ///
@ -813,7 +809,6 @@
/// ///
/// Synonym for @ref keywordauto /// Synonym for @ref keywordauto
/// @namespace chaiscript /// @namespace chaiscript
/// @brief Namespace chaiscript contains every API call that the average user will be concerned with. /// @brief Namespace chaiscript contains every API call that the average user will be concerned with.
@ -821,25 +816,22 @@
/// @brief Classes and functions reserved for internal use. Items in this namespace are not supported. /// @brief Classes and functions reserved for internal use. Items in this namespace are not supported.
#include "chaiscript_basic.hpp" #include "chaiscript_basic.hpp"
#include "language/chaiscript_parser.hpp"
#include "chaiscript_stdlib.hpp" #include "chaiscript_stdlib.hpp"
#include "language/chaiscript_parser.hpp"
namespace chaiscript {
namespace chaiscript class ChaiScript : public ChaiScript_Basic {
{
class ChaiScript : public ChaiScript_Basic
{
public: public:
ChaiScript(std::vector<std::string> t_modulepaths = {}, ChaiScript(std::vector<std::string> t_modulepaths = {},
std::vector<std::string> t_usepaths = {}, std::vector<std::string> t_usepaths = {},
std::vector<Options> t_opts = chaiscript::default_options()) std::vector<Options> t_opts = chaiscript::default_options())
: ChaiScript_Basic( : ChaiScript_Basic(chaiscript::Std_Lib::library(),
chaiscript::Std_Lib::library(),
std::make_unique<parser::ChaiScript_Parser<eval::Noop_Tracer, optimizer::Optimizer_Default>>(), std::make_unique<parser::ChaiScript_Parser<eval::Noop_Tracer, optimizer::Optimizer_Default>>(),
std::move(t_modulepaths), std::move(t_usepaths), std::move(t_opts)) std::move(t_modulepaths),
{ std::move(t_usepaths),
std::move(t_opts)) {
} }
}; };
} } // namespace chaiscript
#endif /* CHAISCRIPT_HPP_ */ #endif /* CHAISCRIPT_HPP_ */

View File

@ -9,13 +9,13 @@
#include "chaiscript_defines.hpp" #include "chaiscript_defines.hpp"
#include "dispatchkit/dispatchkit.hpp"
#include "dispatchkit/function_call.hpp"
#include "dispatchkit/dynamic_object.hpp"
#include "dispatchkit/boxed_number.hpp" #include "dispatchkit/boxed_number.hpp"
#include "dispatchkit/dispatchkit.hpp"
#include "dispatchkit/dynamic_object.hpp"
#include "dispatchkit/function_call.hpp"
#include "language/chaiscript_eval.hpp"
#include "language/chaiscript_engine.hpp" #include "language/chaiscript_engine.hpp"
#include "language/chaiscript_eval.hpp"
// This file includes all of the basic requirements for ChaiScript, // This file includes all of the basic requirements for ChaiScript,
// to use, you might do something like: // to use, you might do something like:
@ -34,6 +34,4 @@ ChaiScript_Basic chai(
// If you want a fully packaged ready to go ChaiScript, use chaiscript.hpp // If you want a fully packaged ready to go ChaiScript, use chaiscript.hpp
#endif /* CHAISCRIPT_BASIC_HPP_ */ #endif /* CHAISCRIPT_BASIC_HPP_ */

View File

@ -20,10 +20,10 @@ static_assert(_MSC_FULL_VER >= 190024210, "Visual C++ 2015 Update 3 or later req
#define CHAISCRIPT_COMPILER_VERSION __VERSION__ #define CHAISCRIPT_COMPILER_VERSION __VERSION__
#endif #endif
#include <vector>
#include <string_view> #include <string_view>
#include <vector>
#if defined( _LIBCPP_VERSION ) #if defined(_LIBCPP_VERSION)
#define CHAISCRIPT_LIBCPP #define CHAISCRIPT_LIBCPP
#endif #endif
@ -49,12 +49,10 @@ static_assert(_MSC_FULL_VER >= 190024210, "Visual C++ 2015 Update 3 or later req
#endif #endif
#endif #endif
#if defined(__llvm__) #if defined(__llvm__)
#define CHAISCRIPT_CLANG #define CHAISCRIPT_CLANG
#endif #endif
#ifdef CHAISCRIPT_HAS_DECLSPEC #ifdef CHAISCRIPT_HAS_DECLSPEC
#define CHAISCRIPT_MODULE_EXPORT extern "C" __declspec(dllexport) #define CHAISCRIPT_MODULE_EXPORT extern "C" __declspec(dllexport)
#else #else
@ -71,9 +69,9 @@ static_assert(_MSC_FULL_VER >= 190024210, "Visual C++ 2015 Update 3 or later req
#define CHAISCRIPT_DEBUG false #define CHAISCRIPT_DEBUG false
#endif #endif
#include <cmath>
#include <memory> #include <memory>
#include <string> #include <string>
#include <cmath>
namespace chaiscript { namespace chaiscript {
constexpr static const int version_major = 7; constexpr static const int version_major = 7;
@ -84,77 +82,48 @@ namespace chaiscript {
constexpr static const char *compiler_name = CHAISCRIPT_COMPILER_NAME; constexpr static const char *compiler_name = CHAISCRIPT_COMPILER_NAME;
constexpr static const bool debug_build = CHAISCRIPT_DEBUG; constexpr static const bool debug_build = CHAISCRIPT_DEBUG;
template<typename B, typename D, typename ...Arg> template<typename B, typename D, typename... Arg>
inline std::shared_ptr<B> make_shared(Arg && ... arg) inline std::shared_ptr<B> make_shared(Arg &&...arg) {
{
#ifdef CHAISCRIPT_USE_STD_MAKE_SHARED #ifdef CHAISCRIPT_USE_STD_MAKE_SHARED
return std::make_shared<D>(std::forward<Arg>(arg)...); return std::make_shared<D>(std::forward<Arg>(arg)...);
#else #else
return std::shared_ptr<B>(static_cast<B*>(new D(std::forward<Arg>(arg)...))); return std::shared_ptr<B>(static_cast<B *>(new D(std::forward<Arg>(arg)...)));
#endif #endif
} }
template<typename B, typename D, typename ...Arg> template<typename B, typename D, typename... Arg>
inline std::unique_ptr<B> make_unique(Arg && ... arg) inline std::unique_ptr<B> make_unique(Arg &&...arg) {
{
#ifdef CHAISCRIPT_USE_STD_MAKE_SHARED #ifdef CHAISCRIPT_USE_STD_MAKE_SHARED
return std::make_unique<D>(std::forward<Arg>(arg)...); return std::make_unique<D>(std::forward<Arg>(arg)...);
#else #else
return std::unique_ptr<B>(static_cast<B*>(new D(std::forward<Arg>(arg)...))); return std::unique_ptr<B>(static_cast<B *>(new D(std::forward<Arg>(arg)...)));
#endif #endif
} }
struct Build_Info { struct Build_Info {
[[nodiscard]] constexpr static int version_major() noexcept [[nodiscard]] constexpr static int version_major() noexcept { return chaiscript::version_major; }
{
return chaiscript::version_major;
}
[[nodiscard]] constexpr static int version_minor() noexcept [[nodiscard]] constexpr static int version_minor() noexcept { return chaiscript::version_minor; }
{
return chaiscript::version_minor;
}
[[nodiscard]] constexpr static int version_patch() noexcept [[nodiscard]] constexpr static int version_patch() noexcept { return chaiscript::version_patch; }
{
return chaiscript::version_patch;
}
[[nodiscard]] static std::string version() [[nodiscard]] static std::string version() {
{
return std::to_string(version_major()) + '.' + std::to_string(version_minor()) + '.' + std::to_string(version_patch()); return std::to_string(version_major()) + '.' + std::to_string(version_minor()) + '.' + std::to_string(version_patch());
} }
[[nodiscard]] static std::string compiler_id() [[nodiscard]] static std::string compiler_id() { return compiler_name() + '-' + compiler_version(); }
{
return compiler_name() + '-' + compiler_version();
}
[[nodiscard]] static std::string build_id() [[nodiscard]] static std::string build_id() { return compiler_id() + (debug_build() ? "-Debug" : "-Release"); }
{
return compiler_id() + (debug_build()?"-Debug":"-Release");
}
[[nodiscard]] static std::string compiler_version() [[nodiscard]] static std::string compiler_version() { return chaiscript::compiler_version; }
{
return chaiscript::compiler_version;
}
[[nodiscard]] static std::string compiler_name() [[nodiscard]] static std::string compiler_name() { return chaiscript::compiler_name; }
{
return chaiscript::compiler_name;
}
[[nodiscard]] constexpr static bool debug_build() noexcept [[nodiscard]] constexpr static bool debug_build() noexcept { return chaiscript::debug_build; }
{
return chaiscript::debug_build;
}
}; };
template<typename T> template<typename T>
[[nodiscard]] constexpr auto parse_num(const std::string_view t_str) noexcept -> typename std::enable_if<std::is_integral<T>::value, T>::type [[nodiscard]] constexpr auto parse_num(const std::string_view t_str) noexcept -> typename std::enable_if<std::is_integral<T>::value, T>::type {
{
T t = 0; T t = 0;
for (const auto c : t_str) { for (const auto c : t_str) {
if (c < '0' || c > '9') { if (c < '0' || c > '9') {
@ -166,18 +135,15 @@ namespace chaiscript {
return t; return t;
} }
template<typename T> template<typename T>
[[nodiscard]] auto parse_num(const std::string_view t_str) -> typename std::enable_if<!std::is_integral<T>::value, T>::type [[nodiscard]] auto parse_num(const std::string_view t_str) -> typename std::enable_if<!std::is_integral<T>::value, T>::type {
{
T t = 0; T t = 0;
T base{}; T base{};
T decimal_place = 0; T decimal_place = 0;
int exponent = 0; int exponent = 0;
for (const auto c : t_str) { for (const auto c : t_str) {
switch (c) switch (c) {
{
case '.': case '.':
decimal_place = 10; decimal_place = 10;
break; break;
@ -206,8 +172,7 @@ namespace chaiscript {
if (decimal_place < 10) { if (decimal_place < 10) {
t *= 10; t *= 10;
t += static_cast<T>(c - '0'); t += static_cast<T>(c - '0');
} } else {
else {
t += static_cast<T>(c - '0') / decimal_place; t += static_cast<T>(c - '0') / decimal_place;
decimal_place *= 10; decimal_place *= 10;
} }
@ -220,30 +185,26 @@ namespace chaiscript {
} }
struct str_equal { struct str_equal {
[[nodiscard]] bool operator()(const std::string &t_lhs, const std::string &t_rhs) const noexcept { [[nodiscard]] bool operator()(const std::string &t_lhs, const std::string &t_rhs) const noexcept { return t_lhs == t_rhs; }
return t_lhs == t_rhs;
}
template<typename LHS, typename RHS> template<typename LHS, typename RHS>
[[nodiscard]] constexpr bool operator()(const LHS &t_lhs, const RHS &t_rhs) const noexcept { [[nodiscard]] constexpr bool operator()(const LHS &t_lhs, const RHS &t_rhs) const noexcept {
return std::equal(t_lhs.begin(), t_lhs.end(), t_rhs.begin(), t_rhs.end()); return std::equal(t_lhs.begin(), t_lhs.end(), t_rhs.begin(), t_rhs.end());
} }
struct is_transparent{}; struct is_transparent {
};
}; };
struct str_less { struct str_less {
[[nodiscard]] bool operator()(const std::string &t_lhs, const std::string &t_rhs) const noexcept { [[nodiscard]] bool operator()(const std::string &t_lhs, const std::string &t_rhs) const noexcept { return t_lhs < t_rhs; }
return t_lhs < t_rhs;
}
template<typename LHS, typename RHS> template<typename LHS, typename RHS>
[[nodiscard]] constexpr bool operator()(const LHS &t_lhs, const RHS &t_rhs) const noexcept { [[nodiscard]] constexpr bool operator()(const LHS &t_lhs, const RHS &t_rhs) const noexcept {
return std::lexicographical_compare(t_lhs.begin(), t_lhs.end(), t_rhs.begin(), t_rhs.end()); return std::lexicographical_compare(t_lhs.begin(), t_lhs.end(), t_rhs.begin(), t_rhs.end());
} }
struct is_transparent{}; struct is_transparent {
};
}; };
enum class Options enum class Options {
{
No_Load_Modules, No_Load_Modules,
Load_Modules, Load_Modules,
No_External_Scripts, No_External_Scripts,
@ -251,44 +212,33 @@ namespace chaiscript {
}; };
template<typename From, typename To> template<typename From, typename To>
struct is_nothrow_forward_constructible struct is_nothrow_forward_constructible : std::bool_constant<noexcept(To{std::declval<From>()})> {
: std::bool_constant<noexcept(To{std::declval<From>()})>
{
}; };
template< class From, class To > template<class From, class To>
static inline constexpr bool is_nothrow_forward_constructible_v static inline constexpr bool is_nothrow_forward_constructible_v = is_nothrow_forward_constructible<From, To>::value;
= is_nothrow_forward_constructible<From, To>::value;
template<typename Container, typename ... T> template<typename Container, typename... T>
[[nodiscard]] constexpr auto make_container(T && ... t) [[nodiscard]] constexpr auto make_container(T &&...t) {
{
Container c; Container c;
c.reserve(sizeof...(t)); c.reserve(sizeof...(t));
(c.push_back(std::forward<T>(t)), ...); (c.push_back(std::forward<T>(t)), ...);
return c; return c;
} }
template<typename... T>
template<typename ... T> [[nodiscard]] auto make_vector(T &&...t) -> std::vector<std::common_type_t<std::decay_t<T>...>> {
[[nodiscard]] auto make_vector(T &&... t) -> std::vector<std::common_type_t<std::decay_t<T>...>> using container_type = std::vector<std::common_type_t<std::decay_t<T>...>>;
{
using container_type =
std::vector<std::common_type_t<std::decay_t<T>...>>;
return make_container<container_type>(std::forward<T>(t)...); return make_container<container_type>(std::forward<T>(t)...);
} }
[[nodiscard]] inline std::vector<Options> default_options() {
[[nodiscard]] inline std::vector<Options> default_options()
{
#ifdef CHAISCRIPT_NO_DYNLOAD #ifdef CHAISCRIPT_NO_DYNLOAD
return {Options::No_Load_Modules, Options::External_Scripts}; return {Options::No_Load_Modules, Options::External_Scripts};
#else #else
return {Options::Load_Modules, Options::External_Scripts}; return {Options::Load_Modules, Options::External_Scripts};
#endif #endif
} }
} } // namespace chaiscript
#endif #endif

View File

@ -19,53 +19,48 @@
#include "dispatchkit/function_call.hpp" #include "dispatchkit/function_call.hpp"
//#include "dispatchkit/dispatchkit.hpp" //#include "dispatchkit/dispatchkit.hpp"
#include "dispatchkit/operators.hpp"
#include "dispatchkit/bootstrap.hpp" #include "dispatchkit/bootstrap.hpp"
#include "dispatchkit/bootstrap_stl.hpp" #include "dispatchkit/bootstrap_stl.hpp"
#include "dispatchkit/operators.hpp"
//#include "dispatchkit/boxed_value.hpp" //#include "dispatchkit/boxed_value.hpp"
#include "language/chaiscript_prelude.hpp"
#include "dispatchkit/register_function.hpp" #include "dispatchkit/register_function.hpp"
#include "language/chaiscript_prelude.hpp"
#include "utility/json_wrap.hpp" #include "utility/json_wrap.hpp"
#ifndef CHAISCRIPT_NO_THREADS #ifndef CHAISCRIPT_NO_THREADS
#include <future> #include <future>
#endif #endif
/// @file /// @file
/// ///
/// This file generates the standard library that normal ChaiScript usage requires. /// This file generates the standard library that normal ChaiScript usage requires.
namespace chaiscript namespace chaiscript {
{ class Std_Lib {
class Std_Lib
{
public: public:
[[nodiscard]] static ModulePtr library() {
[[nodiscard]] static ModulePtr library()
{
auto lib = std::make_shared<Module>(); auto lib = std::make_shared<Module>();
bootstrap::Bootstrap::bootstrap(*lib); bootstrap::Bootstrap::bootstrap(*lib);
bootstrap::standard_library::vector_type<std::vector<Boxed_Value> >("Vector", *lib); bootstrap::standard_library::vector_type<std::vector<Boxed_Value>>("Vector", *lib);
bootstrap::standard_library::string_type<std::string>("string", *lib); bootstrap::standard_library::string_type<std::string>("string", *lib);
bootstrap::standard_library::map_type<std::map<std::string, Boxed_Value> >("Map", *lib); bootstrap::standard_library::map_type<std::map<std::string, Boxed_Value>>("Map", *lib);
bootstrap::standard_library::pair_type<std::pair<Boxed_Value, Boxed_Value > >("Pair", *lib); bootstrap::standard_library::pair_type<std::pair<Boxed_Value, Boxed_Value>>("Pair", *lib);
#ifndef CHAISCRIPT_NO_THREADS #ifndef CHAISCRIPT_NO_THREADS
bootstrap::standard_library::future_type<std::future<chaiscript::Boxed_Value>>("future", *lib); bootstrap::standard_library::future_type<std::future<chaiscript::Boxed_Value>>("future", *lib);
lib->add(chaiscript::fun([](const std::function<chaiscript::Boxed_Value ()> &t_func){ return std::async(std::launch::async, t_func);}), "async"); lib->add(chaiscript::fun(
[](const std::function<chaiscript::Boxed_Value()> &t_func) { return std::async(std::launch::async, t_func); }),
"async");
#endif #endif
json_wrap::library(*lib); json_wrap::library(*lib);
lib->eval(ChaiScript_Prelude::chaiscript_prelude() /*, "standard prelude"*/ ); lib->eval(ChaiScript_Prelude::chaiscript_prelude() /*, "standard prelude"*/);
return lib; return lib;
} }
}; };
} } // namespace chaiscript
#endif #endif

View File

@ -7,20 +7,18 @@
// This is an open source non-commercial project. Dear PVS-Studio, please check it. // This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com // PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_THREADING_HPP_ #ifndef CHAISCRIPT_THREADING_HPP_
#define CHAISCRIPT_THREADING_HPP_ #define CHAISCRIPT_THREADING_HPP_
#include <unordered_map> #include <unordered_map>
#ifndef CHAISCRIPT_NO_THREADS #ifndef CHAISCRIPT_NO_THREADS
#include <thread>
#include <mutex> #include <mutex>
#include <shared_mutex> #include <shared_mutex>
#include <thread>
#else #else
#ifndef CHAISCRIPT_NO_THREADS_WARNING #ifndef CHAISCRIPT_NO_THREADS_WARNING
#pragma message ("ChaiScript is compiling without thread safety.") #pragma message("ChaiScript is compiling without thread safety.")
#endif #endif
#endif #endif
@ -34,16 +32,10 @@
/// It also has the side effect that the chaiscript::ChaiScript object may not be accessed from more than /// It also has the side effect that the chaiscript::ChaiScript object may not be accessed from more than
/// one thread simultaneously. /// one thread simultaneously.
namespace chaiscript /// If threading is enabled, then this namespace contains std thread classes.
{ /// If threading is not enabled, then stubbed in wrappers that do nothing are provided.
namespace detail /// This allows us to avoid \#ifdef code in the sections that need thread safety.
{ namespace chaiscript::detail::threading {
/// If threading is enabled, then this namespace contains std thread classes.
/// If threading is not enabled, then stubbed in wrappers that do nothing are provided.
/// This allows us to avoid \#ifdef code in the sections that need thread safety.
namespace threading
{
#ifndef CHAISCRIPT_NO_THREADS #ifndef CHAISCRIPT_NO_THREADS
template<typename T> template<typename T>
@ -55,7 +47,6 @@ namespace chaiscript
template<typename T> template<typename T>
using lock_guard = std::lock_guard<T>; using lock_guard = std::lock_guard<T>;
using std::shared_mutex; using std::shared_mutex;
using std::mutex; using std::mutex;
@ -65,8 +56,7 @@ namespace chaiscript
/// Typesafe thread specific storage. If threading is enabled, this class uses a mutex protected map. If /// Typesafe thread specific storage. If threading is enabled, this class uses a mutex protected map. If
/// threading is not enabled, the class always returns the same data, regardless of which thread it is called from. /// threading is not enabled, the class always returns the same data, regardless of which thread it is called from.
template<typename T> template<typename T>
class Thread_Storage class Thread_Storage {
{
public: public:
Thread_Storage() = default; Thread_Storage() = default;
Thread_Storage(const Thread_Storage &) = delete; Thread_Storage(const Thread_Storage &) = delete;
@ -74,39 +64,22 @@ namespace chaiscript
Thread_Storage &operator=(const Thread_Storage &) = delete; Thread_Storage &operator=(const Thread_Storage &) = delete;
Thread_Storage &operator=(Thread_Storage &&) = delete; Thread_Storage &operator=(Thread_Storage &&) = delete;
~Thread_Storage() ~Thread_Storage() { t().erase(this); }
{
t().erase(this);
}
inline const T *operator->() const noexcept inline const T *operator->() const noexcept { return &(t()[this]); }
{
return &(t()[this]);
}
inline const T &operator*() const noexcept inline const T &operator*() const noexcept { return t()[this]; }
{
return t()[this];
}
inline T *operator->() noexcept inline T *operator->() noexcept { return &(t()[this]); }
{
return &(t()[this]);
}
inline T &operator*() noexcept
{
return t()[this];
}
inline T &operator*() noexcept { return t()[this]; }
void *m_key; void *m_key;
private: private:
/// todo: is it valid to make this noexcept? The allocation could fail, but if it /// todo: is it valid to make this noexcept? The allocation could fail, but if it
/// does there is no possible way to recover /// does there is no possible way to recover
static std::unordered_map<const void*, T> &t() noexcept static std::unordered_map<const void *, T> &t() noexcept {
{
static thread_local std::unordered_map<const void *, T> my_t; static thread_local std::unordered_map<const void *, T> my_t;
return my_t; return my_t;
} }
@ -114,8 +87,7 @@ namespace chaiscript
#else // threading disabled #else // threading disabled
template<typename T> template<typename T>
class unique_lock class unique_lock {
{
public: public:
constexpr explicit unique_lock(T &) noexcept {} constexpr explicit unique_lock(T &) noexcept {}
constexpr void lock() noexcept {} constexpr void lock() noexcept {}
@ -123,8 +95,7 @@ namespace chaiscript
}; };
template<typename T> template<typename T>
class shared_lock class shared_lock {
{
public: public:
constexpr explicit shared_lock(T &) noexcept {} constexpr explicit shared_lock(T &) noexcept {}
constexpr void lock() noexcept {} constexpr void lock() noexcept {}
@ -132,45 +103,31 @@ namespace chaiscript
}; };
template<typename T> template<typename T>
class lock_guard class lock_guard {
{
public: public:
constexpr explicit lock_guard(T &) noexcept {} constexpr explicit lock_guard(T &) noexcept {}
}; };
class shared_mutex { }; class shared_mutex {
};
class recursive_mutex {};
class recursive_mutex {
};
template<typename T> template<typename T>
class Thread_Storage class Thread_Storage {
{
public: public:
constexpr explicit Thread_Storage() noexcept constexpr explicit Thread_Storage() noexcept {}
{
}
constexpr inline T *operator->() const noexcept constexpr inline T *operator->() const noexcept { return &obj; }
{
return &obj;
}
constexpr inline T &operator*() const noexcept constexpr inline T &operator*() const noexcept { return obj; }
{
return obj;
}
private: private:
mutable T obj; mutable T obj;
}; };
#endif #endif
} } // namespace chaiscript::detail::threading
}
}
#endif #endif

View File

@ -11,32 +11,24 @@
namespace chaiscript { namespace chaiscript {
namespace detail { namespace detail {
namespace exception namespace exception {
{
/// \brief Thrown in the event that an Any cannot be cast to the desired type /// \brief Thrown in the event that an Any cannot be cast to the desired type
/// ///
/// It is used internally during function dispatch. /// It is used internally during function dispatch.
/// ///
/// \sa chaiscript::detail::Any /// \sa chaiscript::detail::Any
class bad_any_cast : public std::bad_cast class bad_any_cast : public std::bad_cast {
{
public: public:
/// \brief Description of what error occurred /// \brief Description of what error occurred
const char * what() const noexcept override const char *what() const noexcept override { return "bad any cast"; }
{
return "bad any cast";
}
}; };
} } // namespace exception
class Any { class Any {
private: private:
struct Data struct Data {
{
constexpr explicit Data(const std::type_info &t_type) noexcept constexpr explicit Data(const std::type_info &t_type) noexcept
: m_type(t_type) : m_type(t_type) {
{
} }
Data &operator=(const Data &) = delete; Data &operator=(const Data &) = delete;
@ -45,35 +37,24 @@ namespace chaiscript {
virtual void *data() noexcept = 0; virtual void *data() noexcept = 0;
const std::type_info &type() const noexcept const std::type_info &type() const noexcept { return m_type; }
{
return m_type;
}
virtual std::unique_ptr<Data> clone() const = 0; virtual std::unique_ptr<Data> clone() const = 0;
const std::type_info &m_type; const std::type_info &m_type;
}; };
template<typename T> template<typename T>
struct Data_Impl : Data struct Data_Impl : Data {
{
explicit Data_Impl(T t_type) explicit Data_Impl(T t_type)
: Data(typeid(T)), : Data(typeid(T))
m_data(std::move(t_type)) , m_data(std::move(t_type)) {
{
} }
void *data() noexcept override void *data() noexcept override { return &m_data; }
{
return &m_data;
}
std::unique_ptr<Data> clone() const override std::unique_ptr<Data> clone() const override { return std::make_unique<Data_Impl<T>>(m_data); }
{
return std::make_unique<Data_Impl<T>>(m_data);
}
Data_Impl &operator=(const Data_Impl&) = delete; Data_Impl &operator=(const Data_Impl &) = delete;
T m_data; T m_data;
}; };
@ -87,52 +68,39 @@ namespace chaiscript {
Any &operator=(Any &&t_any) = default; Any &operator=(Any &&t_any) = default;
Any(const Any &t_any) Any(const Any &t_any)
: m_data(t_any.empty() ? nullptr : t_any.m_data->clone()) : m_data(t_any.empty() ? nullptr : t_any.m_data->clone()) {
{
} }
template<typename ValueType, template<typename ValueType, typename = std::enable_if_t<!std::is_same_v<Any, std::decay_t<ValueType>>>>
typename = std::enable_if_t<!std::is_same_v<Any, std::decay_t<ValueType>>>>
explicit Any(ValueType &&t_value) explicit Any(ValueType &&t_value)
: m_data(std::make_unique<Data_Impl<std::decay_t<ValueType>>>(std::forward<ValueType>(t_value))) : m_data(std::make_unique<Data_Impl<std::decay_t<ValueType>>>(std::forward<ValueType>(t_value))) {
{
} }
Any &operator=(const Any &t_any) {
Any & operator=(const Any &t_any)
{
Any copy(t_any); Any copy(t_any);
swap(copy); swap(copy);
return *this; return *this;
} }
template<typename ToType> template<typename ToType>
ToType &cast() const ToType &cast() const {
{ if (m_data && typeid(ToType) == m_data->type()) {
if (m_data && typeid(ToType) == m_data->type())
{
return *static_cast<ToType *>(m_data->data()); return *static_cast<ToType *>(m_data->data());
} else { } else {
throw chaiscript::detail::exception::bad_any_cast(); throw chaiscript::detail::exception::bad_any_cast();
} }
} }
// modifiers // modifiers
Any & swap(Any &t_other) Any &swap(Any &t_other) {
{
std::swap(t_other.m_data, m_data); std::swap(t_other.m_data, m_data);
return *this; return *this;
} }
// queries // queries
bool empty() const noexcept bool empty() const noexcept { return !static_cast<bool>(m_data); }
{
return !static_cast<bool>(m_data);
}
const std::type_info & type() const noexcept const std::type_info &type() const noexcept {
{
if (m_data) { if (m_data) {
return m_data->type(); return m_data->type();
} else { } else {
@ -141,9 +109,7 @@ namespace chaiscript {
} }
}; };
} } // namespace detail
} } // namespace chaiscript
#endif #endif

View File

@ -7,7 +7,6 @@
// This is an open source non-commercial project. Dear PVS-Studio, please check it. // This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com // PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_BAD_BOXED_CAST_HPP_ #ifndef CHAISCRIPT_BAD_BOXED_CAST_HPP_
#define CHAISCRIPT_BAD_BOXED_CAST_HPP_ #define CHAISCRIPT_BAD_BOXED_CAST_HPP_
@ -19,45 +18,39 @@
#include "type_info.hpp" #include "type_info.hpp"
namespace chaiscript { namespace chaiscript {
class Type_Info; class Type_Info;
} // namespace chaiscript } // namespace chaiscript
namespace chaiscript namespace chaiscript {
{ namespace exception {
namespace exception
{
/// \brief Thrown in the event that a Boxed_Value cannot be cast to the desired type /// \brief Thrown in the event that a Boxed_Value cannot be cast to the desired type
/// ///
/// It is used internally during function dispatch and may be used by the end user. /// It is used internally during function dispatch and may be used by the end user.
/// ///
/// \sa chaiscript::boxed_cast /// \sa chaiscript::boxed_cast
class bad_boxed_cast : public std::bad_cast class bad_boxed_cast : public std::bad_cast {
{
public: public:
bad_boxed_cast(Type_Info t_from, const std::type_info &t_to, bad_boxed_cast(Type_Info t_from, const std::type_info &t_to, utility::Static_String t_what) noexcept
utility::Static_String t_what) noexcept : from(t_from)
: from(t_from), to(&t_to), m_what(std::move(t_what)) , to(&t_to)
{ , m_what(std::move(t_what)) {
} }
bad_boxed_cast(Type_Info t_from, const std::type_info &t_to) noexcept bad_boxed_cast(Type_Info t_from, const std::type_info &t_to) noexcept
: from(t_from), to(&t_to), m_what("Cannot perform boxed_cast") : from(t_from)
{ , to(&t_to)
, m_what("Cannot perform boxed_cast") {
} }
explicit bad_boxed_cast(utility::Static_String t_what) noexcept explicit bad_boxed_cast(utility::Static_String t_what) noexcept
: m_what(std::move(t_what)) : m_what(std::move(t_what)) {
{
} }
bad_boxed_cast(const bad_boxed_cast &) noexcept = default; bad_boxed_cast(const bad_boxed_cast &) noexcept = default;
~bad_boxed_cast() noexcept override = default; ~bad_boxed_cast() noexcept override = default;
/// \brief Description of what error occurred /// \brief Description of what error occurred
const char * what() const noexcept override const char *what() const noexcept override { return m_what.c_str(); }
{
return m_what.c_str();
}
Type_Info from; ///< Type_Info contained in the Boxed_Value Type_Info from; ///< Type_Info contained in the Boxed_Value
const std::type_info *to = nullptr; ///< std::type_info of the desired (but failed) result type const std::type_info *to = nullptr; ///< std::type_info of the desired (but failed) result type
@ -65,10 +58,7 @@ namespace chaiscript
private: private:
utility::Static_String m_what; utility::Static_String m_what;
}; };
} } // namespace exception
} } // namespace chaiscript
#endif #endif

View File

@ -7,79 +7,54 @@
// This is an open source non-commercial project. Dear PVS-Studio, please check it. // This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com // PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_BIND_FIRST_HPP_ #ifndef CHAISCRIPT_BIND_FIRST_HPP_
#define CHAISCRIPT_BIND_FIRST_HPP_ #define CHAISCRIPT_BIND_FIRST_HPP_
#include <functional> #include <functional>
namespace chaiscript namespace chaiscript {
{ namespace detail {
namespace detail
{
template<typename T> template<typename T>
constexpr T* get_pointer(T *t) noexcept constexpr T *get_pointer(T *t) noexcept {
{
return t; return t;
} }
template<typename T> template<typename T>
T* get_pointer(const std::reference_wrapper<T> &t) noexcept T *get_pointer(const std::reference_wrapper<T> &t) noexcept {
{
return &t.get(); return &t.get();
} }
template<typename O, typename Ret, typename P1, typename ... Param> template<typename O, typename Ret, typename P1, typename... Param>
constexpr auto bind_first(Ret (*f)(P1, Param...), O&& o) constexpr auto bind_first(Ret (*f)(P1, Param...), O &&o) {
{ return [f, o = std::forward<O>(o)](Param... param) -> Ret { return f(o, std::forward<Param>(param)...); };
return [f, o = std::forward<O>(o)](Param...param) -> Ret {
return f(o, std::forward<Param>(param)...);
};
} }
template<typename O, typename Ret, typename Class, typename ... Param> template<typename O, typename Ret, typename Class, typename... Param>
constexpr auto bind_first(Ret (Class::*f)(Param...), O&& o) constexpr auto bind_first(Ret (Class::*f)(Param...), O &&o) {
{ return [f, o = std::forward<O>(o)](Param... param) -> Ret { return (get_pointer(o)->*f)(std::forward<Param>(param)...); };
return [f, o = std::forward<O>(o)](Param...param) -> Ret {
return (get_pointer(o)->*f)(std::forward<Param>(param)...);
};
} }
template<typename O, typename Ret, typename Class, typename ... Param> template<typename O, typename Ret, typename Class, typename... Param>
constexpr auto bind_first(Ret (Class::*f)(Param...) const, O&& o) constexpr auto bind_first(Ret (Class::*f)(Param...) const, O &&o) {
{ return [f, o = std::forward<O>(o)](Param... param) -> Ret { return (get_pointer(o)->*f)(std::forward<Param>(param)...); };
return [f, o = std::forward<O>(o)](Param...param) -> Ret {
return (get_pointer(o)->*f)(std::forward<Param>(param)...);
};
} }
template<typename O, typename Ret, typename P1, typename ... Param> template<typename O, typename Ret, typename P1, typename... Param>
auto bind_first(const std::function<Ret (P1, Param...)> &f, O&& o) auto bind_first(const std::function<Ret(P1, Param...)> &f, O &&o) {
{ return [f, o = std::forward<O>(o)](Param... param) -> Ret { return f(o, std::forward<Param>(param)...); };
return [f, o = std::forward<O>(o)](Param...param) -> Ret {
return f(o, std::forward<Param>(param)...);
};
} }
template<typename F, typename O, typename Ret, typename Class, typename P1, typename ... Param> template<typename F, typename O, typename Ret, typename Class, typename P1, typename... Param>
constexpr auto bind_first(const F &fo, O&& o, Ret (Class::*f)(P1, Param...) const) constexpr auto bind_first(const F &fo, O &&o, Ret (Class::*f)(P1, Param...) const) {
{ return [fo, o = std::forward<O>(o), f](Param... param) -> Ret { return (fo.*f)(o, std::forward<Param>(param)...); };
return [fo, o = std::forward<O>(o), f](Param ...param) -> Ret {
return (fo.*f)(o, std::forward<Param>(param)...);
};
} }
template<typename F, typename O> template<typename F, typename O>
constexpr auto bind_first(const F &f, O&& o) constexpr auto bind_first(const F &f, O &&o) {
{
return bind_first(f, std::forward<O>(o), &F::operator()); return bind_first(f, std::forward<O>(o), &F::operator());
} }
} } // namespace detail
} } // namespace chaiscript
#endif #endif

View File

@ -7,52 +7,42 @@
// This is an open source non-commercial project. Dear PVS-Studio, please check it. // This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com // PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_BOOTSTRAP_HPP_ #ifndef CHAISCRIPT_BOOTSTRAP_HPP_
#define CHAISCRIPT_BOOTSTRAP_HPP_ #define CHAISCRIPT_BOOTSTRAP_HPP_
#include "../utility/utility.hpp" #include "../utility/utility.hpp"
#include "register_function.hpp" #include "register_function.hpp"
namespace chaiscript /// \brief Classes and functions useful for bootstrapping of ChaiScript and adding of new types
{ namespace chaiscript::bootstrap {
/// \brief Classes and functions useful for bootstrapping of ChaiScript and adding of new types template<typename T, typename = typename std::enable_if<std::is_array<T>::value>::type>
namespace bootstrap void array(const std::string &type, Module &m) {
{
template<typename T, typename = typename std::enable_if<std::is_array<T>::value>::type >
void array(const std::string &type, Module& m)
{
using ReturnType = typename std::remove_extent<T>::type; using ReturnType = typename std::remove_extent<T>::type;
m.add(user_type<T>(), type); m.add(user_type<T>(), type);
m.add(fun( m.add(fun([](T &t, size_t index) -> ReturnType & {
[](T& t, size_t index)->ReturnType &{
constexpr const auto extent = std::extent<T>::value; constexpr const auto extent = std::extent<T>::value;
if (extent > 0 && index >= extent) { if (extent > 0 && index >= extent) {
throw std::range_error("Array index out of range. Received: " + std::to_string(index) + " expected < " + std::to_string(extent)); throw std::range_error("Array index out of range. Received: " + std::to_string(index) + " expected < "
+ std::to_string(extent));
} else { } else {
return t[index]; return t[index];
} }
} }),
), "[]" "[]");
);
m.add(fun( m.add(fun([](const T &t, size_t index) -> const ReturnType & {
[](const T &t, size_t index)->const ReturnType &{
constexpr const auto extent = std::extent<T>::value; constexpr const auto extent = std::extent<T>::value;
if (extent > 0 && index >= extent) { if (extent > 0 && index >= extent) {
throw std::range_error("Array index out of range. Received: " + std::to_string(index) + " expected < " + std::to_string(extent)); throw std::range_error("Array index out of range. Received: " + std::to_string(index) + " expected < "
+ std::to_string(extent));
} else { } else {
return t[index]; return t[index];
} }
} }),
), "[]" "[]");
);
m.add(fun( m.add(fun([](const T &) { return std::extent<T>::value; }), "size");
[](const T &) {
return std::extent<T>::value;
}), "size");
} }
/// \brief Adds a copy constructor for the given type to the given Model /// \brief Adds a copy constructor for the given type to the given Model
@ -61,9 +51,8 @@ namespace chaiscript
/// \tparam T The type to add a copy constructor for /// \tparam T The type to add a copy constructor for
/// \returns The passed in Module /// \returns The passed in Module
template<typename T> template<typename T>
void copy_constructor(const std::string &type, Module& m) void copy_constructor(const std::string &type, Module &m) {
{ m.add(constructor<T(const T &)>(), type);
m.add(constructor<T (const T &)>(), type);
} }
/// \brief Add all comparison operators for the templated type. Used during bootstrap, also available to users. /// \brief Add all comparison operators for the templated type. Used during bootstrap, also available to users.
@ -71,8 +60,7 @@ namespace chaiscript
/// \param[in,out] m module to add comparison operators to /// \param[in,out] m module to add comparison operators to
/// \returns the passed in Module. /// \returns the passed in Module.
template<typename T> template<typename T>
void opers_comparison(Module& m) void opers_comparison(Module &m) {
{
operators::equal<T>(m); operators::equal<T>(m);
operators::greater_than<T>(m); operators::greater_than<T>(m);
operators::greater_than_equal<T>(m); operators::greater_than_equal<T>(m);
@ -81,8 +69,6 @@ namespace chaiscript
operators::not_equal<T>(m); operators::not_equal<T>(m);
} }
/// \brief Adds default and copy constructors for the given type /// \brief Adds default and copy constructors for the given type
/// \param[in] type The name of the type to add the constructors for. /// \param[in] type The name of the type to add the constructors for.
/// \param[in,out] m The Module to add the basic constructors to /// \param[in,out] m The Module to add the basic constructors to
@ -91,9 +77,8 @@ namespace chaiscript
/// \sa copy_constructor /// \sa copy_constructor
/// \sa constructor /// \sa constructor
template<typename T> template<typename T>
void basic_constructors(const std::string &type, Module& m) void basic_constructors(const std::string &type, Module &m) {
{ m.add(constructor<T()>(), type);
m.add(constructor<T ()>(), type);
copy_constructor<T>(type, m); copy_constructor<T>(type, m);
} }
@ -102,20 +87,15 @@ namespace chaiscript
/// \param[in] type The name of the type /// \param[in] type The name of the type
/// \param[in,out] m The Module to add the constructor to /// \param[in,out] m The Module to add the constructor to
template<typename T> template<typename T>
void construct_pod(const std::string &type, Module& m) void construct_pod(const std::string &type, Module &m) {
{ m.add(fun([](const Boxed_Number &bn) { return bn.get_as<T>(); }), type);
m.add(fun([](const Boxed_Number &bn){ return bn.get_as<T>(); }), type);
} }
/// Internal function for converting from a string to a value /// Internal function for converting from a string to a value
/// uses ostream operator >> to perform the conversion /// uses ostream operator >> to perform the conversion
template<typename Input> template<typename Input>
Input parse_string(const std::string &i) Input parse_string(const std::string &i) {
{ if constexpr (!std::is_same<Input, wchar_t>::value && !std::is_same<Input, char16_t>::value && !std::is_same<Input, char32_t>::value) {
if constexpr (!std::is_same<Input, wchar_t>::value
&& !std::is_same<Input, char16_t>::value
&& !std::is_same<Input, char32_t>::value) {
std::stringstream ss(i); std::stringstream ss(i);
Input t; Input t;
ss >> t; ss >> t;
@ -128,46 +108,37 @@ namespace chaiscript
/// Add all common functions for a POD type. All operators, and /// Add all common functions for a POD type. All operators, and
/// common conversions /// common conversions
template<typename T> template<typename T>
void bootstrap_pod_type(const std::string &name, Module& m) void bootstrap_pod_type(const std::string &name, Module &m) {
{
m.add(user_type<T>(), name); m.add(user_type<T>(), name);
m.add(constructor<T()>(), name); m.add(constructor<T()>(), name);
construct_pod<T>(name, m); construct_pod<T>(name, m);
m.add(fun(&parse_string<T>), "to_" + name); m.add(fun(&parse_string<T>), "to_" + name);
m.add(fun([](const T t){ return t; }), "to_" + name); m.add(fun([](const T t) { return t; }), "to_" + name);
} }
/// "clone" function for a shared_ptr type. This is used in the case /// "clone" function for a shared_ptr type. This is used in the case
/// where you do not want to make a deep copy of an object during cloning /// where you do not want to make a deep copy of an object during cloning
/// but want to instead maintain the shared_ptr. It is needed internally /// but want to instead maintain the shared_ptr. It is needed internally
/// for handling of Proxy_Function object (that is, /// for handling of Proxy_Function object (that is,
/// function variables. /// function variables.
template<typename Type> template<typename Type>
auto shared_ptr_clone(const std::shared_ptr<Type> &p) auto shared_ptr_clone(const std::shared_ptr<Type> &p) {
{
return p; 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> template<typename Type>
std::shared_ptr<std::remove_const_t<Type>> shared_ptr_unconst_clone(const std::shared_ptr<std::add_const_t<Type>> &p) std::shared_ptr<std::remove_const_t<Type>> shared_ptr_unconst_clone(const std::shared_ptr<std::add_const_t<Type>> &p) {
{
return std::const_pointer_cast<typename std::remove_const<Type>::type>(p); return std::const_pointer_cast<typename std::remove_const<Type>::type>(p);
} }
/// Assignment function for shared_ptr objects, does not perform a copy of the /// Assignment function for shared_ptr objects, does not perform a copy of the
/// object pointed to, instead maintains the shared_ptr concept. /// object pointed to, instead maintains the shared_ptr concept.
/// Similar to shared_ptr_clone. Used for Proxy_Function. /// Similar to shared_ptr_clone. Used for Proxy_Function.
template<typename Type> template<typename Type>
Boxed_Value ptr_assign(Boxed_Value lhs, const std::shared_ptr<Type> &rhs) Boxed_Value ptr_assign(Boxed_Value lhs, const std::shared_ptr<Type> &rhs) {
{ if (lhs.is_undef() || (!lhs.get_type_info().is_const() && lhs.get_type_info().bare_equal(chaiscript::detail::Get_Type_Info<Type>::get()))) {
if (lhs.is_undef()
|| (!lhs.get_type_info().is_const() && lhs.get_type_info().bare_equal(chaiscript::detail::Get_Type_Info<Type>::get())))
{
lhs.assign(Boxed_Value(rhs)); lhs.assign(Boxed_Value(rhs));
return lhs; return lhs;
} else { } else {
@ -177,34 +148,23 @@ namespace chaiscript
/// Class consisting of only static functions. All default bootstrapping occurs /// Class consisting of only static functions. All default bootstrapping occurs
/// from this class. /// from this class.
class Bootstrap class Bootstrap {
{
private: private:
/// Function allowing for assignment of an unknown type to any other value /// Function allowing for assignment of an unknown type to any other value
static Boxed_Value unknown_assign(Boxed_Value lhs, Boxed_Value rhs) static Boxed_Value unknown_assign(Boxed_Value lhs, Boxed_Value rhs) {
{ if (lhs.is_undef()) {
if (lhs.is_undef())
{
return (lhs.assign(rhs)); return (lhs.assign(rhs));
} else { } else {
throw exception::bad_boxed_cast("boxed_value has a set type already"); throw exception::bad_boxed_cast("boxed_value has a set type already");
} }
} }
static void print(const std::string &s) noexcept static void print(const std::string &s) noexcept { fwrite(s.c_str(), 1, s.size(), stdout); }
{
fwrite(s.c_str(), 1, s.size(), stdout);
}
static void println(const std::string &s) noexcept
{
puts(s.c_str());
}
static void println(const std::string &s) noexcept { puts(s.c_str()); }
/// Add all arithmetic operators for PODs /// Add all arithmetic operators for PODs
static void opers_arithmetic_pod(Module& m) static void opers_arithmetic_pod(Module &m) {
{
m.add(fun(&Boxed_Number::equals), "=="); m.add(fun(&Boxed_Number::equals), "==");
m.add(fun(&Boxed_Number::less_than), "<"); m.add(fun(&Boxed_Number::less_than), "<");
m.add(fun(&Boxed_Number::greater_than), ">"); m.add(fun(&Boxed_Number::greater_than), ">");
@ -242,35 +202,29 @@ namespace chaiscript
/// Create a bound function object. The first param is the function to bind /// Create a bound function object. The first param is the function to bind
/// the remaining parameters are the args to bind into the result /// the remaining parameters are the args to bind into the result
static Boxed_Value bind_function(const Function_Params &params) static Boxed_Value bind_function(const Function_Params &params) {
{
if (params.empty()) { if (params.empty()) {
throw exception::arity_error(0, 1); throw exception::arity_error(0, 1);
} }
Const_Proxy_Function f = boxed_cast<Const_Proxy_Function>(params[0]); Const_Proxy_Function f = boxed_cast<Const_Proxy_Function>(params[0]);
if (f->get_arity() != -1 && size_t(f->get_arity()) != params.size() - 1) if (f->get_arity() != -1 && size_t(f->get_arity()) != params.size() - 1) {
{
throw exception::arity_error(static_cast<int>(params.size()), f->get_arity()); throw exception::arity_error(static_cast<int>(params.size()), f->get_arity());
} }
return Boxed_Value(Const_Proxy_Function(std::make_shared<dispatch::Bound_Function>(std::move(f), return Boxed_Value(Const_Proxy_Function(
std::vector<Boxed_Value>(params.begin() + 1, params.end())))); std::make_shared<dispatch::Bound_Function>(std::move(f), std::vector<Boxed_Value>(params.begin() + 1, params.end()))));
} }
static bool has_guard(const Const_Proxy_Function &t_pf) noexcept {
static bool has_guard(const Const_Proxy_Function &t_pf) noexcept
{
auto pf = std::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(t_pf); auto pf = std::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(t_pf);
return pf && pf->has_guard(); return pf && pf->has_guard();
} }
static Const_Proxy_Function get_guard(const Const_Proxy_Function &t_pf) static Const_Proxy_Function get_guard(const Const_Proxy_Function &t_pf) {
{
const auto pf = std::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(t_pf); const auto pf = std::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(t_pf);
if (pf && pf->get_guard()) if (pf && pf->get_guard()) {
{
return pf->get_guard(); return pf->get_guard();
} else { } else {
throw std::runtime_error("Function does not have a guard"); throw std::runtime_error("Function does not have a guard");
@ -278,33 +232,26 @@ namespace chaiscript
} }
template<typename FunctionType> template<typename FunctionType>
static std::vector<Boxed_Value> do_return_boxed_value_vector(FunctionType f, static std::vector<Boxed_Value> do_return_boxed_value_vector(FunctionType f, const dispatch::Proxy_Function_Base *b) {
const dispatch::Proxy_Function_Base *b)
{
auto v = (b->*f)(); auto v = (b->*f)();
std::vector<Boxed_Value> vbv; std::vector<Boxed_Value> vbv;
for (const auto &o: v) for (const auto &o : v) {
{
vbv.push_back(const_var(o)); vbv.push_back(const_var(o));
} }
return vbv; return vbv;
} }
static bool has_parse_tree(const chaiscript::Const_Proxy_Function &t_pf) noexcept {
static bool has_parse_tree(const chaiscript::Const_Proxy_Function &t_pf) noexcept
{
const auto pf = std::dynamic_pointer_cast<const chaiscript::dispatch::Dynamic_Proxy_Function>(t_pf); const auto pf = std::dynamic_pointer_cast<const chaiscript::dispatch::Dynamic_Proxy_Function>(t_pf);
return bool(pf); return bool(pf);
} }
static const chaiscript::AST_Node &get_parse_tree(const chaiscript::Const_Proxy_Function &t_pf) static const chaiscript::AST_Node &get_parse_tree(const chaiscript::Const_Proxy_Function &t_pf) {
{
const auto pf = std::dynamic_pointer_cast<const chaiscript::dispatch::Dynamic_Proxy_Function>(t_pf); const auto pf = std::dynamic_pointer_cast<const chaiscript::dispatch::Dynamic_Proxy_Function>(t_pf);
if (pf) if (pf) {
{
return pf->get_parse_tree(); return pf->get_parse_tree();
} else { } else {
throw std::runtime_error("Function does not have a parse tree"); throw std::runtime_error("Function does not have a parse tree");
@ -312,20 +259,15 @@ namespace chaiscript
} }
template<typename Function> template<typename Function>
static auto return_boxed_value_vector(const Function &f) static auto return_boxed_value_vector(const Function &f) {
{ return [f](const dispatch::Proxy_Function_Base *b) { return do_return_boxed_value_vector(f, b); };
return [f](const dispatch::Proxy_Function_Base *b) {
return do_return_boxed_value_vector(f, b);
};
} }
public: public:
/// \brief perform all common bootstrap functions for std::string, void and POD types /// \brief perform all common bootstrap functions for std::string, void and POD types
/// \param[in,out] m Module to add bootstrapped functions to /// \param[in,out] m Module to add bootstrapped functions to
/// \returns passed in Module /// \returns passed in Module
static void bootstrap(Module& m) static void bootstrap(Module &m) {
{
m.add(user_type<void>(), "void"); m.add(user_type<void>(), "void");
m.add(user_type<bool>(), "bool"); m.add(user_type<bool>(), "bool");
m.add(user_type<Boxed_Value>(), "Object"); m.add(user_type<Boxed_Value>(), "Object");
@ -337,11 +279,10 @@ namespace chaiscript
m.add(fun(&dispatch::Proxy_Function_Base::get_arity), "get_arity"); m.add(fun(&dispatch::Proxy_Function_Base::get_arity), "get_arity");
m.add(fun(&dispatch::Proxy_Function_Base::operator==), "=="); m.add(fun(&dispatch::Proxy_Function_Base::operator==), "==");
m.add(fun(return_boxed_value_vector(&dispatch::Proxy_Function_Base::get_param_types)), "get_param_types"); m.add(fun(return_boxed_value_vector(&dispatch::Proxy_Function_Base::get_param_types)), "get_param_types");
m.add(fun(return_boxed_value_vector(&dispatch::Proxy_Function_Base::get_contained_functions)), "get_contained_functions"); m.add(fun(return_boxed_value_vector(&dispatch::Proxy_Function_Base::get_contained_functions)), "get_contained_functions");
m.add(fun([](const std::exception &e){ return std::string(e.what()); }), "what"); m.add(fun([](const std::exception &e) { return std::string(e.what()); }), "what");
m.add(user_type<std::out_of_range>(), "out_of_range"); m.add(user_type<std::out_of_range>(), "out_of_range");
m.add(user_type<std::logic_error>(), "logic_error"); m.add(user_type<std::logic_error>(), "logic_error");
@ -352,25 +293,30 @@ namespace chaiscript
m.add(user_type<std::runtime_error>(), "runtime_error"); m.add(user_type<std::runtime_error>(), "runtime_error");
m.add(chaiscript::base_class<std::exception, std::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(constructor<std::runtime_error(const std::string &)>(), "runtime_error");
m.add(user_type<dispatch::Dynamic_Object>(), "Dynamic_Object"); m.add(user_type<dispatch::Dynamic_Object>(), "Dynamic_Object");
m.add(constructor<dispatch::Dynamic_Object (const std::string &)>(), "Dynamic_Object"); m.add(constructor<dispatch::Dynamic_Object(const std::string &)>(), "Dynamic_Object");
m.add(constructor<dispatch::Dynamic_Object ()>(), "Dynamic_Object"); m.add(constructor<dispatch::Dynamic_Object()>(), "Dynamic_Object");
m.add(fun(&dispatch::Dynamic_Object::get_type_name), "get_type_name"); m.add(fun(&dispatch::Dynamic_Object::get_type_name), "get_type_name");
m.add(fun(&dispatch::Dynamic_Object::get_attrs), "get_attrs"); m.add(fun(&dispatch::Dynamic_Object::get_attrs), "get_attrs");
m.add(fun(&dispatch::Dynamic_Object::set_explicit), "set_explicit"); m.add(fun(&dispatch::Dynamic_Object::set_explicit), "set_explicit");
m.add(fun(&dispatch::Dynamic_Object::is_explicit), "is_explicit"); m.add(fun(&dispatch::Dynamic_Object::is_explicit), "is_explicit");
m.add(fun(&dispatch::Dynamic_Object::has_attr), "has_attr"); m.add(fun(&dispatch::Dynamic_Object::has_attr), "has_attr");
m.add(fun(static_cast<Boxed_Value & (dispatch::Dynamic_Object::*)(const std::string &)>(&dispatch::Dynamic_Object::get_attr)), "get_attr"); m.add(fun(static_cast<Boxed_Value &(dispatch::Dynamic_Object::*)(const std::string &)>(&dispatch::Dynamic_Object::get_attr)), "get_attr");
m.add(fun(static_cast<const Boxed_Value & (dispatch::Dynamic_Object::*)(const std::string &) const>(&dispatch::Dynamic_Object::get_attr)), "get_attr"); m.add(fun(static_cast<const Boxed_Value &(dispatch::Dynamic_Object::*)(const std::string &) const>(&dispatch::Dynamic_Object::get_attr)),
"get_attr");
m.add(fun(static_cast<Boxed_Value & (dispatch::Dynamic_Object::*)(const std::string &)>(&dispatch::Dynamic_Object::method_missing)), "method_missing"); m.add(fun(static_cast<Boxed_Value &(dispatch::Dynamic_Object::*)(const std::string &)>(&dispatch::Dynamic_Object::method_missing)),
m.add(fun(static_cast<const Boxed_Value & (dispatch::Dynamic_Object::*)(const std::string &) const>(&dispatch::Dynamic_Object::method_missing)), "method_missing"); "method_missing");
m.add(fun(static_cast<const Boxed_Value &(dispatch::Dynamic_Object::*)(const std::string &) const>(
&dispatch::Dynamic_Object::method_missing)),
"method_missing");
m.add(fun(static_cast<Boxed_Value & (dispatch::Dynamic_Object::*)(const std::string &)>(&dispatch::Dynamic_Object::get_attr)), "[]"); m.add(fun(static_cast<Boxed_Value &(dispatch::Dynamic_Object::*)(const std::string &)>(&dispatch::Dynamic_Object::get_attr)), "[]");
m.add(fun(static_cast<const Boxed_Value & (dispatch::Dynamic_Object::*)(const std::string &) const>(&dispatch::Dynamic_Object::get_attr)), "[]"); m.add(fun(static_cast<const Boxed_Value &(dispatch::Dynamic_Object::*)(const std::string &) const>(&dispatch::Dynamic_Object::get_attr)),
"[]");
m.eval(R"chaiscript( m.eval(R"chaiscript(
def Dynamic_Object::clone() { def Dynamic_Object::clone() {
@ -426,8 +372,7 @@ namespace chaiscript
m.add(fun(&Boxed_Value::get_type_info), "get_type_info"); m.add(fun(&Boxed_Value::get_type_info), "get_type_info");
m.add(user_type<Type_Info>(), "Type_Info"); m.add(user_type<Type_Info>(), "Type_Info");
m.add(constructor<Type_Info (const Type_Info &)>(), "Type_Info"); m.add(constructor<Type_Info(const Type_Info &)>(), "Type_Info");
operators::equal<Type_Info>(m); operators::equal<Type_Info>(m);
@ -441,21 +386,19 @@ namespace chaiscript
m.add(fun(&Type_Info::bare_name), "cpp_bare_name"); m.add(fun(&Type_Info::bare_name), "cpp_bare_name");
m.add(fun(&Type_Info::bare_equal), "bare_equal"); m.add(fun(&Type_Info::bare_equal), "bare_equal");
basic_constructors<bool>("bool", m); basic_constructors<bool>("bool", m);
operators::assign<bool>(m); operators::assign<bool>(m);
operators::equal<bool>(m); operators::equal<bool>(m);
operators::not_equal<bool>(m); operators::not_equal<bool>(m);
m.add(fun([](const std::string &s) { return s; }), "to_string"); m.add(fun([](const std::string &s) { return s; }), "to_string");
m.add(fun([](const bool b) { return std::string(b?"true":"false"); }), "to_string"); m.add(fun([](const bool b) { return std::string(b ? "true" : "false"); }), "to_string");
m.add(fun(&unknown_assign), "="); m.add(fun(&unknown_assign), "=");
m.add(fun([](const Boxed_Value &bv) { throw bv; }), "throw"); m.add(fun([](const Boxed_Value &bv) { throw bv; }), "throw");
m.add(fun([](const char c) { return std::string(1, c); }), "to_string"); m.add(fun([](const char c) { return std::string(1, c); }), "to_string");
m.add(fun(&Boxed_Number::to_string), "to_string"); m.add(fun(&Boxed_Number::to_string), "to_string");
bootstrap_pod_type<double>("double", m); bootstrap_pod_type<double>("double", m);
bootstrap_pod_type<long double>("long_double", m); bootstrap_pod_type<long double>("long_double", m);
bootstrap_pod_type<float>("float", m); bootstrap_pod_type<float>("float", m);
@ -479,12 +422,10 @@ namespace chaiscript
bootstrap_pod_type<std::uint32_t>("uint32_t", m); bootstrap_pod_type<std::uint32_t>("uint32_t", m);
bootstrap_pod_type<std::uint64_t>("uint64_t", m); bootstrap_pod_type<std::uint64_t>("uint64_t", m);
operators::logical_compliment<bool>(m); operators::logical_compliment<bool>(m);
opers_arithmetic_pod(m); opers_arithmetic_pod(m);
m.add(fun(&Build_Info::version_major), "version_major"); m.add(fun(&Build_Info::version_major), "version_major");
m.add(fun(&Build_Info::version_minor), "version_minor"); m.add(fun(&Build_Info::version_minor), "version_minor");
m.add(fun(&Build_Info::version_patch), "version_patch"); m.add(fun(&Build_Info::version_patch), "version_patch");
@ -494,7 +435,6 @@ namespace chaiscript
m.add(fun(&Build_Info::compiler_id), "compiler_id"); m.add(fun(&Build_Info::compiler_id), "compiler_id");
m.add(fun(&Build_Info::debug_build), "debug_build"); m.add(fun(&Build_Info::debug_build), "debug_build");
m.add(fun(&print), "print_string"); m.add(fun(&print), "print_string");
m.add(fun(&println), "println_string"); m.add(fun(&println), "println_string");
@ -504,16 +444,13 @@ namespace chaiscript
m.add(fun(&ptr_assign<std::remove_const<dispatch::Proxy_Function_Base>::type>), "="); m.add(fun(&ptr_assign<std::remove_const<dispatch::Proxy_Function_Base>::type>), "=");
m.add(fun(&ptr_assign<std::add_const<dispatch::Proxy_Function_Base>::type>), "="); m.add(fun(&ptr_assign<std::add_const<dispatch::Proxy_Function_Base>::type>), "=");
m.add(chaiscript::base_class<dispatch::Proxy_Function_Base, dispatch::Assignable_Proxy_Function>()); m.add(chaiscript::base_class<dispatch::Proxy_Function_Base, dispatch::Assignable_Proxy_Function>());
m.add(fun( m.add(fun([](dispatch::Assignable_Proxy_Function &t_lhs, const std::shared_ptr<const dispatch::Proxy_Function_Base> &t_rhs) {
[](dispatch::Assignable_Proxy_Function &t_lhs, const std::shared_ptr<const dispatch::Proxy_Function_Base> &t_rhs) {
t_lhs.assign(t_rhs); t_lhs.assign(t_rhs);
} }),
), "=" "=");
);
m.add(fun(&Boxed_Value::type_match), "type_match"); m.add(fun(&Boxed_Value::type_match), "type_match");
m.add(chaiscript::fun(&has_parse_tree), "has_parse_tree"); m.add(chaiscript::fun(&has_parse_tree), "has_parse_tree");
m.add(chaiscript::fun(&get_parse_tree), "get_parse_tree"); m.add(chaiscript::fun(&get_parse_tree), "get_parse_tree");
@ -524,38 +461,34 @@ namespace chaiscript
m.add(chaiscript::base_class<std::runtime_error, chaiscript::exception::arithmetic_error>()); m.add(chaiscript::base_class<std::runtime_error, chaiscript::exception::arithmetic_error>());
m.add(chaiscript::base_class<std::exception, chaiscript::exception::arithmetic_error>()); m.add(chaiscript::base_class<std::exception, chaiscript::exception::arithmetic_error>());
// chaiscript::bootstrap::standard_library::vector_type<std::vector<std::shared_ptr<chaiscript::AST_Node> >
// chaiscript::bootstrap::standard_library::vector_type<std::vector<std::shared_ptr<chaiscript::AST_Node> > >("AST_NodeVector", m); // >("AST_NodeVector", m);
chaiscript::utility::add_class<chaiscript::exception::eval_error>(m, chaiscript::utility::add_class<chaiscript::exception::eval_error>(m,
"eval_error", "eval_error",
{ }, {},
{ {fun(&chaiscript::exception::eval_error::reason), "reason"}, {{fun(&chaiscript::exception::eval_error::reason), "reason"},
{fun(&chaiscript::exception::eval_error::pretty_print), "pretty_print"}, {fun(&chaiscript::exception::eval_error::pretty_print), "pretty_print"},
{fun([](const chaiscript::exception::eval_error &t_eval_error) { {fun([](const chaiscript::exception::eval_error &t_eval_error) {
std::vector<Boxed_Value> retval; std::vector<Boxed_Value> retval;
std::transform(t_eval_error.call_stack.begin(), t_eval_error.call_stack.end(), std::transform(t_eval_error.call_stack.begin(),
t_eval_error.call_stack.end(),
std::back_inserter(retval), std::back_inserter(retval),
&chaiscript::var<const chaiscript::AST_Node_Trace &>); &chaiscript::var<const chaiscript::AST_Node_Trace &>);
return retval; return retval;
}), "call_stack"} } }),
); "call_stack"}});
chaiscript::utility::add_class<chaiscript::File_Position>(m, chaiscript::utility::add_class<chaiscript::File_Position>(m,
"File_Position", "File_Position",
{ constructor<File_Position()>(), {constructor<File_Position()>(), constructor<File_Position(int, int)>()},
constructor<File_Position(int, int)>() }, {{fun(&File_Position::line), "line"},
{ {fun(&File_Position::line), "line"}, {fun(&File_Position::column), "column"}});
{fun(&File_Position::column), "column"} }
);
chaiscript::utility::add_class<AST_Node>(m, chaiscript::utility::add_class<AST_Node>(m,
"AST_Node", "AST_Node",
{ }, {},
{ {fun(&AST_Node::text), "text"}, {{fun(&AST_Node::text), "text"},
{fun(&AST_Node::identifier), "identifier"}, {fun(&AST_Node::identifier), "identifier"},
{fun(&AST_Node::filename), "filename"}, {fun(&AST_Node::filename), "filename"},
{fun(&AST_Node::start), "start"}, {fun(&AST_Node::start), "start"},
@ -564,18 +497,15 @@ namespace chaiscript
{fun([](const chaiscript::AST_Node &t_node) -> std::vector<Boxed_Value> { {fun([](const chaiscript::AST_Node &t_node) -> std::vector<Boxed_Value> {
std::vector<Boxed_Value> retval; std::vector<Boxed_Value> retval;
const auto children = t_node.get_children(); const auto children = t_node.get_children();
std::transform(children.begin(), children.end(), std::transform(children.begin(),
children.end(),
std::back_inserter(retval), std::back_inserter(retval),
&chaiscript::var<const std::reference_wrapper<chaiscript::AST_Node> &>); &chaiscript::var<const std::reference_wrapper<chaiscript::AST_Node> &>);
return retval; return retval;
}), "children"} }),
} "children"}});
);
} }
}; };
} } // namespace chaiscript::bootstrap
}
#endif #endif

View File

@ -7,13 +7,11 @@
// This is an open source non-commercial project. Dear PVS-Studio, please check it. // This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com // PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
/// \file /// \file
/// This file contains utility functions for registration of STL container /// This file contains utility functions for registration of STL container
/// classes. The methodology used is based on the SGI STL concepts. /// classes. The methodology used is based on the SGI STL concepts.
/// http://www.sgi.com/tech/stl/table_of_contents.html /// http://www.sgi.com/tech/stl/table_of_contents.html
#ifndef CHAISCRIPT_BOOTSTRAP_STL_HPP_ #ifndef CHAISCRIPT_BOOTSTRAP_STL_HPP_
#define CHAISCRIPT_BOOTSTRAP_STL_HPP_ #define CHAISCRIPT_BOOTSTRAP_STL_HPP_
@ -31,62 +29,44 @@
#include "register_function.hpp" #include "register_function.hpp"
#include "type_info.hpp" #include "type_info.hpp"
namespace chaiscript namespace chaiscript::bootstrap::standard_library {
{
namespace bootstrap
{
namespace standard_library
{
/// Bidir_Range, based on the D concept of ranges. /// Bidir_Range, based on the D concept of ranges.
/// \todo Update the Range code to base its capabilities on /// \todo Update the Range code to base its capabilities on
/// the user_typetraits of the iterator passed in /// the user_typetraits of the iterator passed in
template<typename Container, typename IterType> template<typename Container, typename IterType>
struct Bidir_Range struct Bidir_Range {
{
using container_type = Container; using container_type = Container;
constexpr Bidir_Range(Container &c) constexpr Bidir_Range(Container &c)
: m_begin(c.begin()), m_end(c.end()) : m_begin(c.begin())
{ , m_end(c.end()) {
} }
constexpr bool empty() const noexcept constexpr bool empty() const noexcept { return m_begin == m_end; }
{
return m_begin == m_end;
}
constexpr void pop_front() constexpr void pop_front() {
{ if (empty()) {
if (empty())
{
throw std::range_error("Range empty"); throw std::range_error("Range empty");
} }
++m_begin; ++m_begin;
} }
constexpr void pop_back() constexpr void pop_back() {
{ if (empty()) {
if (empty())
{
throw std::range_error("Range empty"); throw std::range_error("Range empty");
} }
--m_end; --m_end;
} }
constexpr decltype(auto) front() const constexpr decltype(auto) front() const {
{ if (empty()) {
if (empty())
{
throw std::range_error("Range empty"); throw std::range_error("Range empty");
} }
return (*m_begin); return (*m_begin);
} }
constexpr decltype(auto) back() const constexpr decltype(auto) back() const {
{ if (empty()) {
if (empty())
{
throw std::range_error("Range empty"); throw std::range_error("Range empty");
} }
auto pos = m_end; auto pos = m_end;
@ -99,36 +79,29 @@ namespace chaiscript
}; };
namespace detail { namespace detail {
template<typename T> template<typename T>
size_t count(const T &t_target, const typename T::key_type &t_key) size_t count(const T &t_target, const typename T::key_type &t_key) {
{
return t_target.count(t_key); return t_target.count(t_key);
} }
template<typename T> template<typename T>
void insert(T &t_target, const T &t_other) void insert(T &t_target, const T &t_other) {
{
t_target.insert(t_other.begin(), t_other.end()); t_target.insert(t_other.begin(), t_other.end());
} }
template<typename T> template<typename T>
void insert_ref(T &t_target, const typename T::value_type &t_val) void insert_ref(T &t_target, const typename T::value_type &t_val) {
{
t_target.insert(t_val); t_target.insert(t_val);
} }
/// Add Bidir_Range support for the given ContainerType /// Add Bidir_Range support for the given ContainerType
template<typename Bidir_Type> template<typename Bidir_Type>
void input_range_type_impl(const std::string &type, Module& m) void input_range_type_impl(const std::string &type, Module &m) {
{
m.add(user_type<Bidir_Type>(), type + "_Range"); m.add(user_type<Bidir_Type>(), type + "_Range");
copy_constructor<Bidir_Type>(type + "_Range", m); copy_constructor<Bidir_Type>(type + "_Range", m);
m.add(constructor<Bidir_Type (typename Bidir_Type::container_type &)>(), "range_internal"); m.add(constructor<Bidir_Type(typename Bidir_Type::container_type &)>(), "range_internal");
m.add(fun(&Bidir_Type::empty), "empty"); m.add(fun(&Bidir_Type::empty), "empty");
m.add(fun(&Bidir_Type::pop_front), "pop_front"); m.add(fun(&Bidir_Type::pop_front), "pop_front");
@ -137,16 +110,13 @@ namespace chaiscript
m.add(fun(&Bidir_Type::back), "back"); m.add(fun(&Bidir_Type::back), "back");
} }
/// Algorithm for inserting at a specific position into a container /// Algorithm for inserting at a specific position into a container
template<typename Type> template<typename Type>
void insert_at(Type &container, int pos, const typename Type::value_type &v) void insert_at(Type &container, int pos, const typename Type::value_type &v) {
{
auto itr = container.begin(); auto itr = container.begin();
auto end = container.end(); auto end = container.end();
if (pos < 0 || std::distance(itr, end) < pos) if (pos < 0 || std::distance(itr, end) < pos) {
{
throw std::range_error("Cannot insert past end of range"); throw std::range_error("Cannot insert past end of range");
} }
@ -154,62 +124,52 @@ namespace chaiscript
container.insert(itr, v); container.insert(itr, v);
} }
/// Algorithm for erasing a specific position from a container /// Algorithm for erasing a specific position from a container
template<typename Type> template<typename Type>
void erase_at(Type &container, int pos) void erase_at(Type &container, int pos) {
{
auto itr = container.begin(); auto itr = container.begin();
auto end = container.end(); auto end = container.end();
if (pos < 0 || std::distance(itr, end) < (pos-1)) if (pos < 0 || std::distance(itr, end) < (pos - 1)) {
{
throw std::range_error("Cannot erase past end of range"); throw std::range_error("Cannot erase past end of range");
} }
std::advance(itr, pos); std::advance(itr, pos);
container.erase(itr); container.erase(itr);
} }
} } // namespace detail
template<typename ContainerType> template<typename ContainerType>
void input_range_type(const std::string &type, Module& m) void input_range_type(const std::string &type, Module &m) {
{ detail::input_range_type_impl<Bidir_Range<ContainerType, typename ContainerType::iterator>>(type, m);
detail::input_range_type_impl<Bidir_Range<ContainerType, typename ContainerType::iterator> >(type,m); detail::input_range_type_impl<Bidir_Range<const ContainerType, typename ContainerType::const_iterator>>("Const_" + type, m);
detail::input_range_type_impl<Bidir_Range<const ContainerType, typename ContainerType::const_iterator> >("Const_" + type,m);
} }
/// Add random_access_container concept to the given ContainerType /// Add random_access_container concept to the given ContainerType
/// http://www.sgi.com/tech/stl/RandomAccessContainer.html /// http://www.sgi.com/tech/stl/RandomAccessContainer.html
template<typename ContainerType> template<typename ContainerType>
void random_access_container_type(const std::string &/*type*/, Module& m) void random_access_container_type(const std::string & /*type*/, Module &m) {
{ // In the interest of runtime safety for the m, we prefer the at() method for [] access,
//In the interest of runtime safety for the m, we prefer the at() method for [] access, // to throw an exception in an out of bounds condition.
//to throw an exception in an out of bounds condition. m.add(fun([](ContainerType &c, int index) -> typename ContainerType::reference {
m.add(
fun(
[](ContainerType &c, int index) -> typename ContainerType::reference {
/// \todo we are preferring to keep the key as 'int' to avoid runtime conversions /// \todo we are preferring to keep the key as 'int' to avoid runtime conversions
/// during dispatch. reevaluate /// during dispatch. reevaluate
return c.at(static_cast<typename ContainerType::size_type>(index)); return c.at(static_cast<typename ContainerType::size_type>(index));
}), "[]"); }),
"[]");
m.add( m.add(fun([](const ContainerType &c, int index) -> typename ContainerType::const_reference {
fun(
[](const ContainerType &c, int index) -> typename ContainerType::const_reference {
/// \todo we are preferring to keep the key as 'int' to avoid runtime conversions /// \todo we are preferring to keep the key as 'int' to avoid runtime conversions
/// during dispatch. reevaluate /// during dispatch. reevaluate
return c.at(static_cast<typename ContainerType::size_type>(index)); return c.at(static_cast<typename ContainerType::size_type>(index));
}), "[]"); }),
"[]");
} }
/// Add assignable concept to the given ContainerType /// Add assignable concept to the given ContainerType
/// http://www.sgi.com/tech/stl/Assignable.html /// http://www.sgi.com/tech/stl/Assignable.html
template<typename ContainerType> template<typename ContainerType>
void assignable_type(const std::string &type, Module& m) void assignable_type(const std::string &type, Module &m) {
{
copy_constructor<ContainerType>(type, m); copy_constructor<ContainerType>(type, m);
operators::assign<ContainerType>(m); operators::assign<ContainerType>(m);
} }
@ -217,46 +177,43 @@ namespace chaiscript
/// Add container resize concept to the given ContainerType /// Add container resize concept to the given ContainerType
/// http://www.cplusplus.com/reference/stl/ /// http://www.cplusplus.com/reference/stl/
template<typename ContainerType> template<typename ContainerType>
void resizable_type(const std::string &/*type*/, Module& m) void resizable_type(const std::string & /*type*/, Module &m) {
{ m.add(fun([](ContainerType *a, typename ContainerType::size_type n, const typename ContainerType::value_type &val) {
m.add(fun([](ContainerType *a, typename ContainerType::size_type n, const typename ContainerType::value_type& val) { return a->resize(n, val); } ), "resize"); return a->resize(n, val);
m.add(fun([](ContainerType *a, typename ContainerType::size_type n) { return a->resize(n); } ), "resize"); }),
"resize");
m.add(fun([](ContainerType *a, typename ContainerType::size_type n) { return a->resize(n); }), "resize");
} }
/// Add container reserve concept to the given ContainerType /// Add container reserve concept to the given ContainerType
/// http://www.cplusplus.com/reference/stl/ /// http://www.cplusplus.com/reference/stl/
template<typename ContainerType> template<typename ContainerType>
void reservable_type(const std::string &/*type*/, Module& m) void reservable_type(const std::string & /*type*/, Module &m) {
{ m.add(fun([](ContainerType *a, typename ContainerType::size_type n) { return a->reserve(n); }), "reserve");
m.add(fun([](ContainerType *a, typename ContainerType::size_type n) { return a->reserve(n); } ), "reserve"); m.add(fun([](const ContainerType *a) { return a->capacity(); }), "capacity");
m.add(fun([](const ContainerType *a) { return a->capacity(); } ), "capacity");
} }
/// Add container concept to the given ContainerType /// Add container concept to the given ContainerType
/// http://www.sgi.com/tech/stl/Container.html /// http://www.sgi.com/tech/stl/Container.html
template<typename ContainerType> template<typename ContainerType>
void container_type(const std::string &/*type*/, Module& m) void container_type(const std::string & /*type*/, Module &m) {
{ m.add(fun([](const ContainerType *a) { return a->size(); }), "size");
m.add(fun([](const ContainerType *a) { return a->size(); } ), "size"); m.add(fun([](const ContainerType *a) { return a->empty(); }), "empty");
m.add(fun([](const ContainerType *a) { return a->empty(); } ), "empty"); m.add(fun([](ContainerType *a) { a->clear(); }), "clear");
m.add(fun([](ContainerType *a) { a->clear(); } ), "clear");
} }
/// Add default constructable concept to the given Type /// Add default constructable concept to the given Type
/// http://www.sgi.com/tech/stl/DefaultConstructible.html /// http://www.sgi.com/tech/stl/DefaultConstructible.html
template<typename Type> template<typename Type>
void default_constructible_type(const std::string &type, Module& m) void default_constructible_type(const std::string &type, Module &m) {
{ m.add(constructor<Type()>(), type);
m.add(constructor<Type ()>(), type);
} }
/// Add sequence concept to the given ContainerType /// Add sequence concept to the given ContainerType
/// http://www.sgi.com/tech/stl/Sequence.html /// http://www.sgi.com/tech/stl/Sequence.html
template<typename ContainerType> template<typename ContainerType>
void sequence_type(const std::string &/*type*/, Module& m) void sequence_type(const std::string & /*type*/, Module &m) {
{ m.add(fun(&detail::insert_at<ContainerType>), []() -> std::string {
m.add(fun(&detail::insert_at<ContainerType>),
[]()->std::string{
if (typeid(typename ContainerType::value_type) == typeid(Boxed_Value)) { if (typeid(typename ContainerType::value_type) == typeid(Boxed_Value)) {
return "insert_ref_at"; return "insert_ref_at";
} else { } else {
@ -270,35 +227,31 @@ namespace chaiscript
/// Add back insertion sequence concept to the given ContainerType /// Add back insertion sequence concept to the given ContainerType
/// http://www.sgi.com/tech/stl/BackInsertionSequence.html /// http://www.sgi.com/tech/stl/BackInsertionSequence.html
template<typename ContainerType> template<typename ContainerType>
void back_insertion_sequence_type(const std::string &type, Module& m) void back_insertion_sequence_type(const std::string &type, Module &m) {
{ m.add(fun([](ContainerType &container) -> decltype(auto) {
m.add(fun([](ContainerType &container)->decltype(auto){
if (container.empty()) { if (container.empty()) {
throw std::range_error("Container empty"); throw std::range_error("Container empty");
} else { } else {
return (container.back()); return (container.back());
} }
} }),
) "back");
, "back"); m.add(fun([](const ContainerType &container) -> decltype(auto) {
m.add(fun([](const ContainerType &container)->decltype(auto){
if (container.empty()) { if (container.empty()) {
throw std::range_error("Container empty"); throw std::range_error("Container empty");
} else { } else {
return (container.back()); return (container.back());
} }
} }),
) "back");
, "back");
using push_back = void (ContainerType::*)(const typename ContainerType::value_type &); using push_back = void (ContainerType::*)(const typename ContainerType::value_type &);
m.add(fun(static_cast<push_back>(&ContainerType::push_back)), m.add(fun(static_cast<push_back>(&ContainerType::push_back)), [&]() -> std::string {
[&]()->std::string{
if (typeid(typename ContainerType::value_type) == typeid(Boxed_Value)) { if (typeid(typename ContainerType::value_type) == typeid(Boxed_Value)) {
m.eval( m.eval("# Pushes the second value onto the container while making a clone of the value\n"
"# Pushes the second value onto the container while making a clone of the value\n" "def push_back("
"def push_back(" + type + " container, x)\n" + type
+ " container, x)\n"
"{ \n" "{ \n"
" if (x.is_var_return_value()) {\n" " if (x.is_var_return_value()) {\n"
" x.reset_var_return_value() \n" " x.reset_var_return_value() \n"
@ -306,8 +259,7 @@ namespace chaiscript
" } else { \n" " } else { \n"
" container.push_back_ref(clone(x)); \n" " container.push_back_ref(clone(x)); \n"
" }\n" " }\n"
"} \n" "} \n");
);
return "push_back_ref"; return "push_back_ref";
} else { } else {
@ -318,42 +270,37 @@ namespace chaiscript
m.add(fun(&ContainerType::pop_back), "pop_back"); m.add(fun(&ContainerType::pop_back), "pop_back");
} }
/// Front insertion sequence /// Front insertion sequence
/// http://www.sgi.com/tech/stl/FrontInsertionSequence.html /// http://www.sgi.com/tech/stl/FrontInsertionSequence.html
template<typename ContainerType> template<typename ContainerType>
void front_insertion_sequence_type(const std::string &type, Module& m) void front_insertion_sequence_type(const std::string &type, Module &m) {
{
using push_ptr = void (ContainerType::*)(typename ContainerType::const_reference); using push_ptr = void (ContainerType::*)(typename ContainerType::const_reference);
using pop_ptr = void (ContainerType::*)(); using pop_ptr = void (ContainerType::*)();
m.add(fun([](ContainerType &container)->decltype(auto){ m.add(fun([](ContainerType &container) -> decltype(auto) {
if (container.empty()) { if (container.empty()) {
throw std::range_error("Container empty"); throw std::range_error("Container empty");
} else { } else {
return (container.front()); return (container.front());
} }
} }),
) "front");
, "front");
m.add(fun([](const ContainerType &container)->decltype(auto){ m.add(fun([](const ContainerType &container) -> decltype(auto) {
if (container.empty()) { if (container.empty()) {
throw std::range_error("Container empty"); throw std::range_error("Container empty");
} else { } else {
return (container.front()); return (container.front());
} }
} }),
) "front");
, "front");
m.add(fun(static_cast<push_ptr>(&ContainerType::push_front)), [&]() -> std::string {
m.add(fun(static_cast<push_ptr>(&ContainerType::push_front)),
[&]()->std::string{
if (typeid(typename ContainerType::value_type) == typeid(Boxed_Value)) { if (typeid(typename ContainerType::value_type) == typeid(Boxed_Value)) {
m.eval( m.eval("# Pushes the second value onto the front of container while making a clone of the value\n"
"# Pushes the second value onto the front of container while making a clone of the value\n" "def push_front("
"def push_front(" + type + " container, x)\n" + type
+ " container, x)\n"
"{ \n" "{ \n"
" if (x.is_var_return_value()) {\n" " if (x.is_var_return_value()) {\n"
" x.reset_var_return_value() \n" " x.reset_var_return_value() \n"
@ -361,8 +308,7 @@ namespace chaiscript
" } else { \n" " } else { \n"
" container.push_front_ref(clone(x)); \n" " container.push_front_ref(clone(x)); \n"
" }\n" " }\n"
"} \n" "} \n");
);
return "push_front_ref"; return "push_front_ref";
} else { } else {
return "push_front"; return "push_front";
@ -375,32 +321,28 @@ namespace chaiscript
/// bootstrap a given PairType /// bootstrap a given PairType
/// http://www.sgi.com/tech/stl/pair.html /// http://www.sgi.com/tech/stl/pair.html
template<typename PairType> template<typename PairType>
void pair_type(const std::string &type, Module& m) void pair_type(const std::string &type, Module &m) {
{
m.add(user_type<PairType>(), type); m.add(user_type<PairType>(), type);
m.add(fun(&PairType::first), "first"); m.add(fun(&PairType::first), "first");
m.add(fun(&PairType::second), "second"); m.add(fun(&PairType::second), "second");
basic_constructors<PairType>(type, m); basic_constructors<PairType>(type, m);
m.add(constructor<PairType (const typename PairType::first_type &, const typename PairType::second_type &)>(), type); m.add(constructor<PairType(const typename PairType::first_type &, const typename PairType::second_type &)>(), type);
} }
/// Add pair associative container concept to the given ContainerType /// Add pair associative container concept to the given ContainerType
/// http://www.sgi.com/tech/stl/PairAssociativeContainer.html /// http://www.sgi.com/tech/stl/PairAssociativeContainer.html
template<typename ContainerType> template<typename ContainerType>
void pair_associative_container_type(const std::string &type, Module& m) void pair_associative_container_type(const std::string &type, Module &m) {
{
pair_type<typename ContainerType::value_type>(type + "_Pair", m); pair_type<typename ContainerType::value_type>(type + "_Pair", m);
} }
/// Add unique associative container concept to the given ContainerType /// Add unique associative container concept to the given ContainerType
/// http://www.sgi.com/tech/stl/UniqueAssociativeContainer.html /// http://www.sgi.com/tech/stl/UniqueAssociativeContainer.html
template<typename ContainerType> template<typename ContainerType>
void unique_associative_container_type(const std::string &/*type*/, Module& m) void unique_associative_container_type(const std::string & /*type*/, Module &m) {
{
m.add(fun(detail::count<ContainerType>), "count"); m.add(fun(detail::count<ContainerType>), "count");
using erase_ptr = size_t (ContainerType::*)(const typename ContainerType::key_type &); using erase_ptr = size_t (ContainerType::*)(const typename ContainerType::key_type &);
@ -409,8 +351,7 @@ namespace chaiscript
m.add(fun(&detail::insert<ContainerType>), "insert"); m.add(fun(&detail::insert<ContainerType>), "insert");
m.add(fun(&detail::insert_ref<ContainerType>), m.add(fun(&detail::insert_ref<ContainerType>), []() -> std::string {
[]()->std::string{
if (typeid(typename ContainerType::mapped_type) == typeid(Boxed_Value)) { if (typeid(typename ContainerType::mapped_type) == typeid(Boxed_Value)) {
return "insert_ref"; return "insert_ref";
} else { } else {
@ -422,8 +363,7 @@ namespace chaiscript
/// Add a MapType container /// Add a MapType container
/// http://www.sgi.com/tech/stl/Map.html /// http://www.sgi.com/tech/stl/Map.html
template<typename MapType> template<typename MapType>
void map_type(const std::string &type, Module& m) void map_type(const std::string &type, Module &m) {
{
m.add(user_type<MapType>(), type); m.add(user_type<MapType>(), type);
using elem_access = typename MapType::mapped_type &(MapType::*)(const typename MapType::key_type &); using elem_access = typename MapType::mapped_type &(MapType::*)(const typename MapType::key_type &);
@ -434,8 +374,7 @@ namespace chaiscript
m.add(fun(static_cast<elem_access>(&MapType::at)), "at"); m.add(fun(static_cast<elem_access>(&MapType::at)), "at");
m.add(fun(static_cast<const_elem_access>(&MapType::at)), "at"); m.add(fun(static_cast<const_elem_access>(&MapType::at)), "at");
if (typeid(MapType) == typeid(std::map<std::string, Boxed_Value>)) if (typeid(MapType) == typeid(std::map<std::string, Boxed_Value>)) {
{
m.eval(R"( m.eval(R"(
def Map::`==`(Map rhs) { def Map::`==`(Map rhs) {
if ( rhs.size() != this.size() ) { if ( rhs.size() != this.size() ) {
@ -454,8 +393,7 @@ namespace chaiscript
} }
true; true;
} }
} )" } )");
);
} }
container_type<MapType>(type, m); container_type<MapType>(type, m);
@ -468,8 +406,7 @@ namespace chaiscript
/// http://www.sgi.com/tech/stl/List.html /// http://www.sgi.com/tech/stl/List.html
template<typename ListType> template<typename ListType>
void list_type(const std::string &type, Module& m) void list_type(const std::string &type, Module &m) {
{
m.add(user_type<ListType>(), type); m.add(user_type<ListType>(), type);
front_insertion_sequence_type<ListType>(type, m); front_insertion_sequence_type<ListType>(type, m);
@ -485,32 +422,26 @@ namespace chaiscript
/// Create a vector type with associated concepts /// Create a vector type with associated concepts
/// http://www.sgi.com/tech/stl/Vector.html /// http://www.sgi.com/tech/stl/Vector.html
template<typename VectorType> template<typename VectorType>
void vector_type(const std::string &type, Module& m) void vector_type(const std::string &type, Module &m) {
{
m.add(user_type<VectorType>(), type); m.add(user_type<VectorType>(), type);
m.add(fun([](VectorType &container)->decltype(auto){ m.add(fun([](VectorType &container) -> decltype(auto) {
if (container.empty()) { if (container.empty()) {
throw std::range_error("Container empty"); throw std::range_error("Container empty");
} else { } else {
return (container.front()); return (container.front());
} }
} }),
) "front");
, "front");
m.add(fun([](const VectorType &container)->decltype(auto){ m.add(fun([](const VectorType &container) -> decltype(auto) {
if (container.empty()) { if (container.empty()) {
throw std::range_error("Container empty"); throw std::range_error("Container empty");
} else { } else {
return (container.front()); return (container.front());
} }
} }),
) "front");
, "front");
back_insertion_sequence_type<VectorType>(type, m); back_insertion_sequence_type<VectorType>(type, m);
sequence_type<VectorType>(type, m); sequence_type<VectorType>(type, m);
@ -522,8 +453,7 @@ namespace chaiscript
assignable_type<VectorType>(type, m); assignable_type<VectorType>(type, m);
input_range_type<VectorType>(type, m); input_range_type<VectorType>(type, m);
if (typeid(VectorType) == typeid(std::vector<Boxed_Value>)) if (typeid(VectorType) == typeid(std::vector<Boxed_Value>)) {
{
m.eval(R"( m.eval(R"(
def Vector::`==`(Vector rhs) { def Vector::`==`(Vector rhs) {
if ( rhs.size() != this.size() ) { if ( rhs.size() != this.size() ) {
@ -542,16 +472,14 @@ namespace chaiscript
} }
true; true;
} }
} )" } )");
);
} }
} }
/// Add a String container /// Add a String container
/// http://www.sgi.com/tech/stl/basic_string.html /// http://www.sgi.com/tech/stl/basic_string.html
template<typename String> template<typename String>
void string_type(const std::string &type, Module& m) void string_type(const std::string &type, Module &m) {
{
m.add(user_type<String>(), type); m.add(user_type<String>(), type);
operators::addition<String>(m); operators::addition<String>(m);
operators::assign_sum<String>(m); operators::assign_sum<String>(m);
@ -563,9 +491,8 @@ namespace chaiscript
assignable_type<String>(type, m); assignable_type<String>(type, m);
input_range_type<String>(type, m); input_range_type<String>(type, m);
//Special case: add push_back to string (which doesn't support other back_insertion operations // Special case: add push_back to string (which doesn't support other back_insertion operations
m.add(fun(&String::push_back), m.add(fun(&String::push_back), []() -> std::string {
[]()->std::string{
if (typeid(typename String::value_type) == typeid(Boxed_Value)) { if (typeid(typename String::value_type) == typeid(Boxed_Value)) {
return "push_back_ref"; return "push_back_ref";
} else { } else {
@ -573,42 +500,34 @@ namespace chaiscript
} }
}()); }());
m.add(fun([](const String *s, const String &f, size_t pos) { return s->find(f, pos); }), "find");
m.add(fun([](const String *s, const String &f, size_t pos) { return s->rfind(f, pos); }), "rfind");
m.add(fun([](const String *s, const String &f, size_t pos) { return s->find_first_of(f, pos); }), "find_first_of");
m.add(fun([](const String *s, const String &f, size_t pos) { return s->find_last_of(f, pos); }), "find_last_of");
m.add(fun([](const String *s, const String &f, size_t pos) { return s->find_last_not_of(f, pos); }), "find_last_not_of");
m.add(fun([](const String *s, const String &f, size_t pos) { return s->find_first_not_of(f, pos); }), "find_first_not_of");
m.add(fun([](const String *s, const String &f, size_t pos) { return s->find(f, pos); } ), "find"); m.add(fun([](String *s, typename String::value_type c) -> decltype(auto) { return (*s += c); }), "+=");
m.add(fun([](const String *s, const String &f, size_t pos) { return s->rfind(f, pos); } ), "rfind");
m.add(fun([](const String *s, const String &f, size_t pos) { return s->find_first_of(f, pos); } ), "find_first_of");
m.add(fun([](const String *s, const String &f, size_t pos) { return s->find_last_of(f, pos); } ), "find_last_of");
m.add(fun([](const String *s, const String &f, size_t pos) { return s->find_last_not_of(f, pos); } ), "find_last_not_of");
m.add(fun([](const String *s, const String &f, size_t pos) { return s->find_first_not_of(f, pos); } ), "find_first_not_of");
m.add(fun([](String *s, typename String::value_type c) -> decltype(auto) { return (*s += c); } ), "+="); m.add(fun([](String *s) { s->clear(); }), "clear");
m.add(fun([](const String *s) { return s->empty(); }), "empty");
m.add(fun([](const String *s) { return s->size(); }), "size");
m.add(fun([](String *s) { s->clear(); } ), "clear"); m.add(fun([](const String *s) { return s->c_str(); }), "c_str");
m.add(fun([](const String *s) { return s->empty(); } ), "empty"); m.add(fun([](const String *s) { return s->data(); }), "data");
m.add(fun([](const String *s) { return s->size(); } ), "size"); m.add(fun([](const String *s, size_t pos, size_t len) { return s->substr(pos, len); }), "substr");
m.add(fun([](const String *s) { return s->c_str(); } ), "c_str");
m.add(fun([](const String *s) { return s->data(); } ), "data");
m.add(fun([](const String *s, size_t pos, size_t len) { return s->substr(pos, len); } ), "substr");
} }
/// Add a MapType container /// Add a MapType container
/// http://www.sgi.com/tech/stl/Map.html /// http://www.sgi.com/tech/stl/Map.html
template<typename FutureType> template<typename FutureType>
void future_type(const std::string &type, Module& m) void future_type(const std::string &type, Module &m) {
{
m.add(user_type<FutureType>(), type); m.add(user_type<FutureType>(), type);
m.add(fun([](const FutureType &t) { return t.valid(); }), "valid"); m.add(fun([](const FutureType &t) { return t.valid(); }), "valid");
m.add(fun([](FutureType &t) { return t.get(); }), "get"); m.add(fun([](FutureType &t) { return t.get(); }), "get");
m.add(fun(&FutureType::wait), "wait"); m.add(fun(&FutureType::wait), "wait");
} }
} } // namespace chaiscript::bootstrap::standard_library
}
}
#endif #endif

View File

@ -7,7 +7,6 @@
// This is an open source non-commercial project. Dear PVS-Studio, please check it. // This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com // PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_BOXED_CAST_HPP_ #ifndef CHAISCRIPT_BOXED_CAST_HPP_
#define CHAISCRIPT_BOXED_CAST_HPP_ #define CHAISCRIPT_BOXED_CAST_HPP_
@ -19,17 +18,13 @@
#include "type_info.hpp" #include "type_info.hpp"
namespace chaiscript { namespace chaiscript {
class Type_Conversions; class Type_Conversions;
namespace detail { }
namespace exception { namespace chaiscript::detail::exception {
class bad_any_cast; class bad_any_cast;
} // namespace exception } // namespace chaiscript::detail::exception
} // namespace detail
} // namespace chaiscript
namespace chaiscript
{
namespace chaiscript {
/// \brief Function for extracting a value stored in a Boxed_Value object /// \brief Function for extracting a value stored in a Boxed_Value object
/// \tparam Type The type to extract from the Boxed_Value /// \tparam Type The type to extract from the Boxed_Value
/// \param[in] bv The Boxed_Value to extract a typed value from /// \param[in] bv The Boxed_Value to extract a typed value from
@ -73,26 +68,24 @@ namespace chaiscript
/// assert(i == 5); /// assert(i == 5);
/// \endcode /// \endcode
template<typename Type> template<typename Type>
decltype(auto) boxed_cast(const Boxed_Value &bv, const Type_Conversions_State *t_conversions = nullptr) decltype(auto) boxed_cast(const Boxed_Value &bv, const Type_Conversions_State *t_conversions = nullptr) {
{
if (!t_conversions || bv.get_type_info().bare_equal(user_type<Type>()) || (t_conversions && !(*t_conversions)->convertable_type<Type>())) { if (!t_conversions || bv.get_type_info().bare_equal(user_type<Type>()) || (t_conversions && !(*t_conversions)->convertable_type<Type>())) {
try { try {
return(detail::Cast_Helper<Type>::cast(bv, t_conversions)); return detail::Cast_Helper<Type>::cast(bv, t_conversions);
} catch (const chaiscript::detail::exception::bad_any_cast &) { } catch (const chaiscript::detail::exception::bad_any_cast &) {
} }
} }
if (t_conversions && (*t_conversions)->convertable_type<Type>()) {
if (t_conversions && (*t_conversions)->convertable_type<Type>())
{
try { try {
// We will not catch any bad_boxed_dynamic_cast that is thrown, let the user get it // 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 // either way, we are not responsible if it doesn't work
return(detail::Cast_Helper<Type>::cast((*t_conversions)->boxed_type_conversion<Type>(t_conversions->saves(), bv), t_conversions)); return (detail::Cast_Helper<Type>::cast((*t_conversions)->boxed_type_conversion<Type>(t_conversions->saves(), bv), t_conversions));
} catch (...) { } catch (...) {
try { try {
// try going the other way // try going the other way
return(detail::Cast_Helper<Type>::cast((*t_conversions)->boxed_type_down_conversion<Type>(t_conversions->saves(), bv), t_conversions)); return (detail::Cast_Helper<Type>::cast((*t_conversions)->boxed_type_down_conversion<Type>(t_conversions->saves(), bv),
t_conversions));
} catch (const chaiscript::detail::exception::bad_any_cast &) { } catch (const chaiscript::detail::exception::bad_any_cast &) {
throw exception::bad_boxed_cast(bv.get_type_info(), typeid(Type)); throw exception::bad_boxed_cast(bv.get_type_info(), typeid(Type));
} }
@ -102,12 +95,8 @@ namespace chaiscript
// attempted dynamic_cast // attempted dynamic_cast
throw exception::bad_boxed_cast(bv.get_type_info(), typeid(Type)); throw exception::bad_boxed_cast(bv.get_type_info(), typeid(Type));
} }
} }
} } // namespace chaiscript
#endif #endif

View File

@ -7,7 +7,6 @@
// This is an open source non-commercial project. Dear PVS-Studio, please check it. // This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com // PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_BOXED_CAST_HELPER_HPP_ #ifndef CHAISCRIPT_BOXED_CAST_HELPER_HPP_
#define CHAISCRIPT_BOXED_CAST_HELPER_HPP_ #define CHAISCRIPT_BOXED_CAST_HELPER_HPP_
@ -17,19 +16,17 @@
#include "boxed_value.hpp" #include "boxed_value.hpp"
#include "type_info.hpp" #include "type_info.hpp"
namespace chaiscript {
namespace chaiscript
{
class Type_Conversions_State; class Type_Conversions_State;
namespace detail namespace detail {
{
// Cast_Helper_Inner helper classes // Cast_Helper_Inner helper classes
template<typename T> template<typename T>
constexpr T* throw_if_null(T *t) constexpr T *throw_if_null(T *t) {
{ if (t) {
if (t) { return t; } return t;
}
throw std::runtime_error("Attempted to dereference null Boxed_Value"); throw std::runtime_error("Attempted to dereference null Boxed_Value");
} }
@ -51,7 +48,6 @@ namespace chaiscript
} }
} }
template<typename T> template<typename T>
static const T *verify_type(const Boxed_Value &ob, const std::type_info &ti, const T *ptr) { static const T *verify_type(const Boxed_Value &ob, const std::type_info &ti, const T *ptr) {
if (ob.get_type_info().bare_equal_type_info(ti)) { if (ob.get_type_info().bare_equal_type_info(ti)) {
@ -72,79 +68,60 @@ namespace chaiscript
/// Generic Cast_Helper_Inner, for casting to any type /// Generic Cast_Helper_Inner, for casting to any type
template<typename Result> template<typename Result>
struct Cast_Helper_Inner struct Cast_Helper_Inner {
{ static Result cast(const Boxed_Value &ob, const Type_Conversions_State *) {
static Result cast(const Boxed_Value &ob, const Type_Conversions_State *)
{
return *static_cast<const Result *>(verify_type(ob, typeid(Result), ob.get_const_ptr())); return *static_cast<const Result *>(verify_type(ob, typeid(Result), ob.get_const_ptr()));
} }
}; };
template<typename Result> template<typename Result>
struct Cast_Helper_Inner<const Result> : Cast_Helper_Inner<Result> struct Cast_Helper_Inner<const Result> : Cast_Helper_Inner<Result> {
{
}; };
/// Cast_Helper_Inner for casting to a const * type /// Cast_Helper_Inner for casting to a const * type
template<typename Result> template<typename Result>
struct Cast_Helper_Inner<const Result *> struct Cast_Helper_Inner<const Result *> {
{ static const Result *cast(const Boxed_Value &ob, const Type_Conversions_State *) {
static const Result * cast(const Boxed_Value &ob, const Type_Conversions_State *)
{
return static_cast<const Result *>(verify_type_no_throw(ob, typeid(Result), ob.get_const_ptr())); return static_cast<const Result *>(verify_type_no_throw(ob, typeid(Result), ob.get_const_ptr()));
} }
}; };
/// Cast_Helper_Inner for casting to a * type /// Cast_Helper_Inner for casting to a * type
template<typename Result> template<typename Result>
struct Cast_Helper_Inner<Result *> struct Cast_Helper_Inner<Result *> {
{ static Result *cast(const Boxed_Value &ob, const Type_Conversions_State *) {
static Result * cast(const Boxed_Value &ob, const Type_Conversions_State *)
{
return static_cast<Result *>(verify_type_no_throw(ob, typeid(Result), ob.get_ptr())); return static_cast<Result *>(verify_type_no_throw(ob, typeid(Result), ob.get_ptr()));
} }
}; };
template<typename Result> template<typename Result>
struct Cast_Helper_Inner<Result * const &> : public Cast_Helper_Inner<Result *> struct Cast_Helper_Inner<Result *const &> : public Cast_Helper_Inner<Result *> {
{
}; };
template<typename Result> template<typename Result>
struct Cast_Helper_Inner<const Result * const &> : public Cast_Helper_Inner<const Result *> struct Cast_Helper_Inner<const Result *const &> : public Cast_Helper_Inner<const Result *> {
{
}; };
/// Cast_Helper_Inner for casting to a & type /// Cast_Helper_Inner for casting to a & type
template<typename Result> template<typename Result>
struct Cast_Helper_Inner<const Result &> struct Cast_Helper_Inner<const Result &> {
{ static const Result &cast(const Boxed_Value &ob, const Type_Conversions_State *) {
static const Result & cast(const Boxed_Value &ob, const Type_Conversions_State *)
{
return *static_cast<const Result *>(verify_type(ob, typeid(Result), ob.get_const_ptr())); return *static_cast<const Result *>(verify_type(ob, typeid(Result), ob.get_const_ptr()));
} }
}; };
/// Cast_Helper_Inner for casting to a & type /// Cast_Helper_Inner for casting to a & type
template<typename Result> template<typename Result>
struct Cast_Helper_Inner<Result &> struct Cast_Helper_Inner<Result &> {
{ static Result &cast(const Boxed_Value &ob, const Type_Conversions_State *) {
static Result& cast(const Boxed_Value &ob, const Type_Conversions_State *)
{
return *static_cast<Result *>(verify_type(ob, typeid(Result), ob.get_ptr())); return *static_cast<Result *>(verify_type(ob, typeid(Result), ob.get_ptr()));
} }
}; };
/// Cast_Helper_Inner for casting to a && type /// Cast_Helper_Inner for casting to a && type
template<typename Result> template<typename Result>
struct Cast_Helper_Inner<Result &&> struct Cast_Helper_Inner<Result &&> {
{ static Result &&cast(const Boxed_Value &ob, const Type_Conversions_State *) {
static Result&& cast(const Boxed_Value &ob, const Type_Conversions_State *)
{
return std::move(*static_cast<Result *>(verify_type(ob, typeid(Result), ob.get_ptr()))); return std::move(*static_cast<Result *>(verify_type(ob, typeid(Result), ob.get_ptr())));
} }
}; };
@ -152,10 +129,8 @@ namespace chaiscript
/// Cast_Helper_Inner for casting to a std::unique_ptr<> && type /// Cast_Helper_Inner for casting to a std::unique_ptr<> && type
/// \todo Fix the fact that this has to be in a shared_ptr for now /// \todo Fix the fact that this has to be in a shared_ptr for now
template<typename Result> template<typename Result>
struct Cast_Helper_Inner<std::unique_ptr<Result> &&> struct Cast_Helper_Inner<std::unique_ptr<Result> &&> {
{ static std::unique_ptr<Result> &&cast(const Boxed_Value &ob, const Type_Conversions_State *) {
static std::unique_ptr<Result> &&cast(const Boxed_Value &ob, const Type_Conversions_State *)
{
return std::move(*(ob.get().cast<std::shared_ptr<std::unique_ptr<Result>>>())); return std::move(*(ob.get().cast<std::shared_ptr<std::unique_ptr<Result>>>()));
} }
}; };
@ -163,10 +138,8 @@ namespace chaiscript
/// Cast_Helper_Inner for casting to a std::unique_ptr<> & type /// Cast_Helper_Inner for casting to a std::unique_ptr<> & type
/// \todo Fix the fact that this has to be in a shared_ptr for now /// \todo Fix the fact that this has to be in a shared_ptr for now
template<typename Result> template<typename Result>
struct Cast_Helper_Inner<std::unique_ptr<Result> &> struct Cast_Helper_Inner<std::unique_ptr<Result> &> {
{ static std::unique_ptr<Result> &cast(const Boxed_Value &ob, const Type_Conversions_State *) {
static std::unique_ptr<Result> &cast(const Boxed_Value &ob, const Type_Conversions_State *)
{
return *(ob.get().cast<std::shared_ptr<std::unique_ptr<Result>>>()); return *(ob.get().cast<std::shared_ptr<std::unique_ptr<Result>>>());
} }
}; };
@ -174,150 +147,114 @@ namespace chaiscript
/// Cast_Helper_Inner for casting to a std::unique_ptr<> & type /// Cast_Helper_Inner for casting to a std::unique_ptr<> & type
/// \todo Fix the fact that this has to be in a shared_ptr for now /// \todo Fix the fact that this has to be in a shared_ptr for now
template<typename Result> template<typename Result>
struct Cast_Helper_Inner<const std::unique_ptr<Result> &> struct Cast_Helper_Inner<const std::unique_ptr<Result> &> {
{ static std::unique_ptr<Result> &cast(const Boxed_Value &ob, const Type_Conversions_State *) {
static std::unique_ptr<Result> &cast(const Boxed_Value &ob, const Type_Conversions_State *)
{
return *(ob.get().cast<std::shared_ptr<std::unique_ptr<Result>>>()); return *(ob.get().cast<std::shared_ptr<std::unique_ptr<Result>>>());
} }
}; };
/// Cast_Helper_Inner for casting to a std::shared_ptr<> type /// Cast_Helper_Inner for casting to a std::shared_ptr<> type
template<typename Result> template<typename Result>
struct Cast_Helper_Inner<std::shared_ptr<Result> > struct Cast_Helper_Inner<std::shared_ptr<Result>> {
{ static auto cast(const Boxed_Value &ob, const Type_Conversions_State *) { return ob.get().cast<std::shared_ptr<Result>>(); }
static auto cast(const Boxed_Value &ob, const Type_Conversions_State *)
{
return ob.get().cast<std::shared_ptr<Result> >();
}
}; };
/// Cast_Helper_Inner for casting to a std::shared_ptr<const> type /// Cast_Helper_Inner for casting to a std::shared_ptr<const> type
template<typename Result> template<typename Result>
struct Cast_Helper_Inner<std::shared_ptr<const Result> > struct Cast_Helper_Inner<std::shared_ptr<const Result>> {
{ static auto cast(const Boxed_Value &ob, const Type_Conversions_State *) {
static auto cast(const Boxed_Value &ob, const Type_Conversions_State *) if (!ob.get_type_info().is_const()) {
{ return std::const_pointer_cast<const Result>(ob.get().cast<std::shared_ptr<Result>>());
if (!ob.get_type_info().is_const())
{
return std::const_pointer_cast<const Result>(ob.get().cast<std::shared_ptr<Result> >());
} else { } else {
return ob.get().cast<std::shared_ptr<const Result> >(); return ob.get().cast<std::shared_ptr<const Result>>();
} }
} }
}; };
/// Cast_Helper_Inner for casting to a const std::shared_ptr<> & type /// Cast_Helper_Inner for casting to a const std::shared_ptr<> & type
template<typename Result> template<typename Result>
struct Cast_Helper_Inner<const std::shared_ptr<Result> > : Cast_Helper_Inner<std::shared_ptr<Result> > struct Cast_Helper_Inner<const std::shared_ptr<Result>> : Cast_Helper_Inner<std::shared_ptr<Result>> {
{
}; };
template<typename Result> template<typename Result>
struct Cast_Helper_Inner<const std::shared_ptr<Result> &> : Cast_Helper_Inner<std::shared_ptr<Result> > struct Cast_Helper_Inner<const std::shared_ptr<Result> &> : Cast_Helper_Inner<std::shared_ptr<Result>> {
{
}; };
template<typename Result> template<typename Result>
struct Cast_Helper_Inner<std::shared_ptr<Result> &> struct Cast_Helper_Inner<std::shared_ptr<Result> &> {
{
static_assert(!std::is_const<Result>::value, "Non-const reference to std::shared_ptr<const T> is not supported"); static_assert(!std::is_const<Result>::value, "Non-const reference to std::shared_ptr<const T> is not supported");
static auto cast(const Boxed_Value &ob, const Type_Conversions_State *) static auto cast(const Boxed_Value &ob, const Type_Conversions_State *) {
{ std::shared_ptr<Result> &res = ob.get().cast<std::shared_ptr<Result>>();
std::shared_ptr<Result> &res = ob.get().cast<std::shared_ptr<Result> >();
return ob.pointer_sentinel(res); return ob.pointer_sentinel(res);
} }
}; };
/// Cast_Helper_Inner for casting to a const std::shared_ptr<const> & type /// Cast_Helper_Inner for casting to a const std::shared_ptr<const> & type
template<typename Result> template<typename Result>
struct Cast_Helper_Inner<const std::shared_ptr<const Result> > : Cast_Helper_Inner<std::shared_ptr<const Result> > struct Cast_Helper_Inner<const std::shared_ptr<const Result>> : Cast_Helper_Inner<std::shared_ptr<const Result>> {
{
}; };
template<typename Result> template<typename Result>
struct Cast_Helper_Inner<const std::shared_ptr<const Result> &> : Cast_Helper_Inner<std::shared_ptr<const Result> > struct Cast_Helper_Inner<const std::shared_ptr<const Result> &> : Cast_Helper_Inner<std::shared_ptr<const Result>> {
{
}; };
/// Cast_Helper_Inner for casting to a Boxed_Value type /// Cast_Helper_Inner for casting to a Boxed_Value type
template<> template<>
struct Cast_Helper_Inner<Boxed_Value> struct Cast_Helper_Inner<Boxed_Value> {
{ static Boxed_Value cast(const Boxed_Value &ob, const Type_Conversions_State *) { return ob; }
static Boxed_Value cast(const Boxed_Value &ob, const Type_Conversions_State *)
{
return ob;
}
}; };
/// Cast_Helper_Inner for casting to a Boxed_Value & type /// Cast_Helper_Inner for casting to a Boxed_Value & type
template<> template<>
struct Cast_Helper_Inner<Boxed_Value &> struct Cast_Helper_Inner<Boxed_Value &> {
{ static std::reference_wrapper<Boxed_Value> cast(const Boxed_Value &ob, const Type_Conversions_State *) {
static std::reference_wrapper<Boxed_Value> cast(const Boxed_Value &ob, const Type_Conversions_State *)
{
return std::ref(const_cast<Boxed_Value &>(ob)); return std::ref(const_cast<Boxed_Value &>(ob));
} }
}; };
/// Cast_Helper_Inner for casting to a const Boxed_Value & type /// Cast_Helper_Inner for casting to a const Boxed_Value & type
template<> template<>
struct Cast_Helper_Inner<const Boxed_Value> : Cast_Helper_Inner<Boxed_Value> struct Cast_Helper_Inner<const Boxed_Value> : Cast_Helper_Inner<Boxed_Value> {
{
}; };
template<> template<>
struct Cast_Helper_Inner<const Boxed_Value &> : Cast_Helper_Inner<Boxed_Value> struct Cast_Helper_Inner<const Boxed_Value &> : Cast_Helper_Inner<Boxed_Value> {
{
}; };
/// Cast_Helper_Inner for casting to a std::reference_wrapper type /// Cast_Helper_Inner for casting to a std::reference_wrapper type
template<typename Result> template<typename Result>
struct Cast_Helper_Inner<std::reference_wrapper<Result> > : Cast_Helper_Inner<Result &> struct Cast_Helper_Inner<std::reference_wrapper<Result>> : Cast_Helper_Inner<Result &> {
{
}; };
template<typename Result> template<typename Result>
struct Cast_Helper_Inner<const std::reference_wrapper<Result> > : Cast_Helper_Inner<Result &> struct Cast_Helper_Inner<const std::reference_wrapper<Result>> : Cast_Helper_Inner<Result &> {
{
}; };
template<typename Result> template<typename Result>
struct Cast_Helper_Inner<const std::reference_wrapper<Result> &> : Cast_Helper_Inner<Result &> struct Cast_Helper_Inner<const std::reference_wrapper<Result> &> : Cast_Helper_Inner<Result &> {
{
}; };
template<typename Result> template<typename Result>
struct Cast_Helper_Inner<std::reference_wrapper<const Result> > : Cast_Helper_Inner<const Result &> struct Cast_Helper_Inner<std::reference_wrapper<const Result>> : Cast_Helper_Inner<const Result &> {
{
}; };
template<typename Result> template<typename Result>
struct Cast_Helper_Inner<const std::reference_wrapper<const Result> > : Cast_Helper_Inner<const Result &> struct Cast_Helper_Inner<const std::reference_wrapper<const Result>> : Cast_Helper_Inner<const Result &> {
{
}; };
template<typename Result> template<typename Result>
struct Cast_Helper_Inner<const std::reference_wrapper<const Result> & > : Cast_Helper_Inner<const Result &> struct Cast_Helper_Inner<const std::reference_wrapper<const Result> &> : Cast_Helper_Inner<const Result &> {
{
}; };
/// The exposed Cast_Helper object that by default just calls the Cast_Helper_Inner /// The exposed Cast_Helper object that by default just calls the Cast_Helper_Inner
template<typename T> template<typename T>
struct Cast_Helper struct Cast_Helper {
{ static decltype(auto) cast(const Boxed_Value &ob, const Type_Conversions_State *t_conversions) {
static decltype(auto) cast(const Boxed_Value &ob, const Type_Conversions_State *t_conversions) return (Cast_Helper_Inner<T>::cast(ob, t_conversions));
{
return(Cast_Helper_Inner<T>::cast(ob, t_conversions));
} }
}; };
} } // namespace detail
} } // namespace chaiscript
#endif #endif

View File

@ -22,25 +22,20 @@
#include "type_info.hpp" #include "type_info.hpp"
namespace chaiscript { namespace chaiscript {
class Type_Conversions; class Type_Conversions;
} // namespace chaiscript } // namespace chaiscript
namespace chaiscript namespace chaiscript::exception {
{ struct arithmetic_error : std::runtime_error {
namespace exception explicit arithmetic_error(const std::string &reason)
{ : std::runtime_error("Arithmetic error: " + reason) {
struct arithmetic_error : std::runtime_error }
{
explicit arithmetic_error(const std::string& reason) : std::runtime_error("Arithmetic error: " + reason) {}
arithmetic_error(const arithmetic_error &) = default; arithmetic_error(const arithmetic_error &) = default;
~arithmetic_error() noexcept override = default; ~arithmetic_error() noexcept override = default;
}; };
} } // namespace chaiscript::exception
}
namespace chaiscript
{
namespace chaiscript {
// Due to the nature of generating every possible arithmetic operation, there // Due to the nature of generating every possible arithmetic operation, there
// are going to be warnings generated on every platform regarding size and sign, // are going to be warnings generated on every platform regarding size and sign,
// this is OK, so we're disabling size/and sign type warnings // this is OK, so we're disabling size/and sign type warnings
@ -49,7 +44,6 @@ namespace chaiscript
#pragma warning(disable : 4244 4018 4389 4146 4365 4267 4242) #pragma warning(disable : 4244 4018 4389 4146 4365 4267 4242)
#endif #endif
#ifdef __GNUC__ #ifdef __GNUC__
#pragma GCC diagnostic push #pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunknown-pragmas" #pragma GCC diagnostic ignored "-Wunknown-pragmas"
@ -63,8 +57,7 @@ namespace chaiscript
#endif #endif
/// \brief Represents any numeric type, generically. Used internally for generic operations between POD values /// \brief Represents any numeric type, generically. Used internally for generic operations between POD values
class Boxed_Number class Boxed_Number {
{
private: private:
enum class Common_Types { enum class Common_Types {
t_int32, t_int32,
@ -81,8 +74,7 @@ namespace chaiscript
}; };
template<typename T> template<typename T>
constexpr static inline void check_divide_by_zero([[maybe_unused]] T t) constexpr static inline void check_divide_by_zero([[maybe_unused]] T t) {
{
#ifndef CHAISCRIPT_NO_PROTECT_DIVIDEBYZERO #ifndef CHAISCRIPT_NO_PROTECT_DIVIDEBYZERO
if constexpr (!std::is_floating_point<T>::value) { if constexpr (!std::is_floating_point<T>::value) {
if (t == 0) { if (t == 0) {
@ -92,21 +84,18 @@ namespace chaiscript
#endif #endif
} }
constexpr static Common_Types get_common_type(size_t t_size, bool t_signed) noexcept constexpr static Common_Types get_common_type(size_t t_size, bool t_signed) noexcept {
{ return (t_size == 1 && t_signed) ? (Common_Types::t_int8)
return (t_size == 1 && t_signed)?(Common_Types::t_int8) : (t_size == 1) ? (Common_Types::t_uint8)
:(t_size == 1)?(Common_Types::t_uint8) : (t_size == 2 && t_signed) ? (Common_Types::t_int16)
:(t_size == 2 && t_signed)?(Common_Types::t_int16) : (t_size == 2) ? (Common_Types::t_uint16)
:(t_size == 2)?(Common_Types::t_uint16) : (t_size == 4 && t_signed) ? (Common_Types::t_int32)
:(t_size == 4 && t_signed)?(Common_Types::t_int32) : (t_size == 4) ? (Common_Types::t_uint32)
:(t_size == 4)?(Common_Types::t_uint32) : (t_size == 8 && t_signed) ? (Common_Types::t_int64)
:(t_size == 8 && t_signed)?(Common_Types::t_int64) : (Common_Types::t_uint64);
:(Common_Types::t_uint64);
} }
static Common_Types get_common_type(const Boxed_Value &t_bv) {
static Common_Types get_common_type(const Boxed_Value &t_bv)
{
const Type_Info &inp_ = t_bv.get_type_info(); const Type_Info &inp_ = t_bv.get_type_info();
if (inp_ == user_type<int>()) { if (inp_ == user_type<int>()) {
@ -158,11 +147,8 @@ namespace chaiscript
} }
} }
template<typename LHS, typename RHS> template<typename LHS, typename RHS>
static auto go(Operators::Opers t_oper, const Boxed_Value &t_bv, LHS *t_lhs, const LHS &c_lhs, const RHS &c_rhs) static auto go(Operators::Opers t_oper, const Boxed_Value &t_bv, LHS *t_lhs, const LHS &c_lhs, const RHS &c_rhs) {
{
switch (t_oper) { switch (t_oper) {
case Operators::Opers::equals: case Operators::Opers::equals:
return const_var(c_lhs == c_rhs); return const_var(c_lhs == c_rhs);
@ -189,7 +175,6 @@ namespace chaiscript
break; break;
} }
if constexpr (!std::is_floating_point<LHS>::value && !std::is_floating_point<RHS>::value) { if constexpr (!std::is_floating_point<LHS>::value && !std::is_floating_point<RHS>::value) {
switch (t_oper) { switch (t_oper) {
case Operators::Opers::shift_left: case Operators::Opers::shift_left:
@ -263,8 +248,7 @@ namespace chaiscript
} }
template<typename Callable> template<typename Callable>
inline static auto visit(const Boxed_Value &bv, Callable &&callable) inline static auto visit(const Boxed_Value &bv, Callable &&callable) {
{
switch (get_common_type(bv)) { switch (get_common_type(bv)) {
case Common_Types::t_int32: case Common_Types::t_int32:
return callable(*static_cast<const std::int32_t *>(bv.get_const_ptr())); return callable(*static_cast<const std::int32_t *>(bv.get_const_ptr()));
@ -292,9 +276,8 @@ namespace chaiscript
throw chaiscript::detail::exception::bad_any_cast(); throw chaiscript::detail::exception::bad_any_cast();
} }
inline static Boxed_Value oper(Operators::Opers t_oper, const Boxed_Value &t_lhs) inline static Boxed_Value oper(Operators::Opers t_oper, const Boxed_Value &t_lhs) {
{ auto unary_operator = [t_oper, &t_lhs](const auto &c_lhs) {
auto unary_operator = [t_oper, &t_lhs](const auto &c_lhs){
auto *lhs = static_cast<std::decay_t<decltype(c_lhs)> *>(t_lhs.get_ptr()); auto *lhs = static_cast<std::decay_t<decltype(c_lhs)> *>(t_lhs.get_ptr());
if (lhs) { if (lhs) {
@ -334,16 +317,11 @@ namespace chaiscript
return visit(t_lhs, unary_operator); return visit(t_lhs, unary_operator);
} }
inline static Boxed_Value oper(Operators::Opers t_oper, const Boxed_Value &t_lhs, const Boxed_Value &t_rhs) {
auto lhs_visit = [t_oper, &t_lhs, &t_rhs](const auto &c_lhs) {
auto *lhs = t_lhs.is_return_value() ? nullptr : static_cast<std::decay_t<decltype(c_lhs)> *>(t_lhs.get_ptr());
inline static Boxed_Value oper(Operators::Opers t_oper, const Boxed_Value &t_lhs, const Boxed_Value &t_rhs) auto rhs_visit = [t_oper, &t_lhs, lhs, &c_lhs](const auto &c_rhs) { return go(t_oper, t_lhs, lhs, c_lhs, c_rhs); };
{
auto lhs_visit = [t_oper, &t_lhs, &t_rhs](const auto &c_lhs){
auto *lhs = t_lhs.is_return_value()?nullptr:static_cast<std::decay_t<decltype(c_lhs)> *>(t_lhs.get_ptr());
auto rhs_visit = [t_oper, &t_lhs, lhs, &c_lhs](const auto &c_rhs) {
return go(t_oper, t_lhs, lhs, c_lhs, c_rhs);
};
return visit(t_rhs, rhs_visit); return visit(t_rhs, rhs_visit);
}; };
@ -352,14 +330,12 @@ namespace chaiscript
} }
template<typename Target, typename Source> template<typename Target, typename Source>
static inline Target get_as_aux(const Boxed_Value &t_bv) static inline Target get_as_aux(const Boxed_Value &t_bv) {
{
return static_cast<Target>(*static_cast<const Source *>(t_bv.get_const_ptr())); return static_cast<Target>(*static_cast<const Source *>(t_bv.get_const_ptr()));
} }
template<typename Source> template<typename Source>
static std::string to_string_aux(const Boxed_Value &v) static std::string to_string_aux(const Boxed_Value &v) {
{
std::ostringstream oss; std::ostringstream oss;
oss << *static_cast<const Source *>(v.get_const_ptr()); oss << *static_cast<const Source *>(v.get_const_ptr());
return oss.str(); return oss.str();
@ -367,32 +343,27 @@ namespace chaiscript
public: public:
Boxed_Number() Boxed_Number()
: bv(Boxed_Value(0)) : bv(Boxed_Value(0)) {
{
} }
explicit Boxed_Number(Boxed_Value v) explicit Boxed_Number(Boxed_Value v)
: bv(std::move(v)) : bv(std::move(v)) {
{
validate_boxed_number(bv); validate_boxed_number(bv);
} }
Boxed_Number(const Boxed_Number &) = default; Boxed_Number(const Boxed_Number &) = default;
Boxed_Number(Boxed_Number &&) = default; Boxed_Number(Boxed_Number &&) = default;
Boxed_Number& operator=(Boxed_Number &&) = default; Boxed_Number &operator=(Boxed_Number &&) = default;
template<typename T> explicit Boxed_Number(T t) template<typename T>
: bv(Boxed_Value(t)) explicit Boxed_Number(T t)
{ : bv(Boxed_Value(t)) {
validate_boxed_number(bv); validate_boxed_number(bv);
} }
static Boxed_Value clone(const Boxed_Value &t_bv) { static Boxed_Value clone(const Boxed_Value &t_bv) { return Boxed_Number(t_bv).get_as(t_bv.get_type_info()).bv; }
return Boxed_Number(t_bv).get_as(t_bv.get_type_info()).bv;
}
static bool is_floating_point(const Boxed_Value &t_bv) static bool is_floating_point(const Boxed_Value &t_bv) {
{
const Type_Info &inp_ = t_bv.get_type_info(); const Type_Info &inp_ = t_bv.get_type_info();
if (inp_ == user_type<double>()) { if (inp_ == user_type<double>()) {
@ -406,8 +377,7 @@ namespace chaiscript
} }
} }
Boxed_Number get_as(const Type_Info &inp_) const Boxed_Number get_as(const Type_Info &inp_) const {
{
if (inp_.bare_equal(user_type<int>())) { if (inp_.bare_equal(user_type<int>())) {
return Boxed_Number(get_as<int>()); return Boxed_Number(get_as<int>());
} else if (inp_.bare_equal(user_type<double>())) { } else if (inp_.bare_equal(user_type<double>())) {
@ -455,21 +425,17 @@ namespace chaiscript
} else { } else {
throw chaiscript::detail::exception::bad_any_cast(); throw chaiscript::detail::exception::bad_any_cast();
} }
} }
template<typename Source, typename Target> template<typename Source, typename Target>
static void check_type() static void check_type() {
{
#ifdef CHAISCRIPT_MSVC #ifdef CHAISCRIPT_MSVC
// MSVC complains about this being redundant / tautologica l // MSVC complains about this being redundant / tautologica l
#pragma warning(push) #pragma warning(push)
#pragma warning(disable : 4127 6287) #pragma warning(disable : 4127 6287)
#endif #endif
if (sizeof(Source) != sizeof(Target) if (sizeof(Source) != sizeof(Target) || std::is_signed<Source>() != std::is_signed<Target>()
|| std::is_signed<Source>() != std::is_signed<Target>() || std::is_floating_point<Source>() != std::is_floating_point<Target>()) {
|| std::is_floating_point<Source>() != std::is_floating_point<Target>())
{
throw chaiscript::detail::exception::bad_any_cast(); throw chaiscript::detail::exception::bad_any_cast();
} }
#ifdef CHAISCRIPT_MSVC #ifdef CHAISCRIPT_MSVC
@ -477,8 +443,8 @@ namespace chaiscript
#endif #endif
} }
template<typename Target> Target get_as_checked() const template<typename Target>
{ Target get_as_checked() const {
switch (get_common_type(bv)) { switch (get_common_type(bv)) {
case Common_Types::t_int32: case Common_Types::t_int32:
check_type<int32_t, Target>(); check_type<int32_t, Target>();
@ -518,9 +484,8 @@ namespace chaiscript
throw chaiscript::detail::exception::bad_any_cast(); throw chaiscript::detail::exception::bad_any_cast();
} }
template<typename Target>
template<typename Target> Target get_as() const Target get_as() const {
{
switch (get_common_type(bv)) { switch (get_common_type(bv)) {
case Common_Types::t_int32: case Common_Types::t_int32:
return get_as_aux<Target, int32_t>(bv); return get_as_aux<Target, int32_t>(bv);
@ -549,8 +514,7 @@ namespace chaiscript
throw chaiscript::detail::exception::bad_any_cast(); throw chaiscript::detail::exception::bad_any_cast();
} }
std::string to_string() const std::string to_string() const {
{
switch (get_common_type(bv)) { switch (get_common_type(bv)) {
case Common_Types::t_int32: case Common_Types::t_int32:
return std::to_string(get_as<int32_t>()); return std::to_string(get_as<int32_t>());
@ -579,222 +543,162 @@ namespace chaiscript
throw chaiscript::detail::exception::bad_any_cast(); throw chaiscript::detail::exception::bad_any_cast();
} }
static void validate_boxed_number(const Boxed_Value &v) static void validate_boxed_number(const Boxed_Value &v) {
{
const Type_Info &inp_ = v.get_type_info(); const Type_Info &inp_ = v.get_type_info();
if (inp_ == user_type<bool>()) if (inp_ == user_type<bool>()) {
{
throw chaiscript::detail::exception::bad_any_cast(); throw chaiscript::detail::exception::bad_any_cast();
} }
if (!inp_.is_arithmetic()) if (!inp_.is_arithmetic()) {
{
throw chaiscript::detail::exception::bad_any_cast(); throw chaiscript::detail::exception::bad_any_cast();
} }
} }
static bool equals(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs) {
static bool equals(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs)
{
return boxed_cast<bool>(oper(Operators::Opers::equals, t_lhs.bv, t_rhs.bv)); return boxed_cast<bool>(oper(Operators::Opers::equals, t_lhs.bv, t_rhs.bv));
} }
static bool less_than(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs) static bool less_than(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs) {
{
return boxed_cast<bool>(oper(Operators::Opers::less_than, t_lhs.bv, t_rhs.bv)); return boxed_cast<bool>(oper(Operators::Opers::less_than, t_lhs.bv, t_rhs.bv));
} }
static bool greater_than(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs) static bool greater_than(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs) {
{
return boxed_cast<bool>(oper(Operators::Opers::greater_than, t_lhs.bv, t_rhs.bv)); return boxed_cast<bool>(oper(Operators::Opers::greater_than, t_lhs.bv, t_rhs.bv));
} }
static bool greater_than_equal(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs) static bool greater_than_equal(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs) {
{
return boxed_cast<bool>(oper(Operators::Opers::greater_than_equal, t_lhs.bv, t_rhs.bv)); return boxed_cast<bool>(oper(Operators::Opers::greater_than_equal, t_lhs.bv, t_rhs.bv));
} }
static bool less_than_equal(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs) static bool less_than_equal(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs) {
{
return boxed_cast<bool>(oper(Operators::Opers::less_than_equal, t_lhs.bv, t_rhs.bv)); return boxed_cast<bool>(oper(Operators::Opers::less_than_equal, t_lhs.bv, t_rhs.bv));
} }
static bool not_equal(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs) static bool not_equal(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs) {
{
return boxed_cast<bool>(oper(Operators::Opers::not_equal, t_lhs.bv, t_rhs.bv)); return boxed_cast<bool>(oper(Operators::Opers::not_equal, t_lhs.bv, t_rhs.bv));
} }
static Boxed_Number pre_decrement(Boxed_Number t_lhs) static Boxed_Number pre_decrement(Boxed_Number t_lhs) { return Boxed_Number(oper(Operators::Opers::pre_decrement, t_lhs.bv)); }
{
return Boxed_Number(oper(Operators::Opers::pre_decrement, t_lhs.bv));
}
static Boxed_Number pre_increment(Boxed_Number t_lhs) static Boxed_Number pre_increment(Boxed_Number t_lhs) { return Boxed_Number(oper(Operators::Opers::pre_increment, t_lhs.bv)); }
{
return Boxed_Number(oper(Operators::Opers::pre_increment, t_lhs.bv));
}
static const Boxed_Number sum(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs) static const Boxed_Number sum(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs) {
{
return Boxed_Number(oper(Operators::Opers::sum, t_lhs.bv, t_rhs.bv)); return Boxed_Number(oper(Operators::Opers::sum, t_lhs.bv, t_rhs.bv));
} }
static const Boxed_Number unary_plus(const Boxed_Number &t_lhs) static const Boxed_Number unary_plus(const Boxed_Number &t_lhs) { return Boxed_Number(oper(Operators::Opers::unary_plus, t_lhs.bv)); }
{
return Boxed_Number(oper(Operators::Opers::unary_plus, t_lhs.bv));
}
static const Boxed_Number unary_minus(const Boxed_Number &t_lhs) static const Boxed_Number unary_minus(const Boxed_Number &t_lhs) { return Boxed_Number(oper(Operators::Opers::unary_minus, t_lhs.bv)); }
{
return Boxed_Number(oper(Operators::Opers::unary_minus, t_lhs.bv));
}
static const Boxed_Number difference(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs) static const Boxed_Number difference(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs) {
{
return Boxed_Number(oper(Operators::Opers::difference, t_lhs.bv, t_rhs.bv)); return Boxed_Number(oper(Operators::Opers::difference, t_lhs.bv, t_rhs.bv));
} }
static Boxed_Number assign_bitwise_and(Boxed_Number t_lhs, const Boxed_Number &t_rhs) static Boxed_Number assign_bitwise_and(Boxed_Number t_lhs, const Boxed_Number &t_rhs) {
{
return Boxed_Number(oper(Operators::Opers::assign_bitwise_and, t_lhs.bv, t_rhs.bv)); return Boxed_Number(oper(Operators::Opers::assign_bitwise_and, t_lhs.bv, t_rhs.bv));
} }
static Boxed_Number assign(Boxed_Number t_lhs, const Boxed_Number &t_rhs) static Boxed_Number assign(Boxed_Number t_lhs, const Boxed_Number &t_rhs) {
{
return Boxed_Number(oper(Operators::Opers::assign, t_lhs.bv, t_rhs.bv)); return Boxed_Number(oper(Operators::Opers::assign, t_lhs.bv, t_rhs.bv));
} }
static Boxed_Number assign_bitwise_or(Boxed_Number t_lhs, const Boxed_Number &t_rhs) static Boxed_Number assign_bitwise_or(Boxed_Number t_lhs, const Boxed_Number &t_rhs) {
{
return Boxed_Number(oper(Operators::Opers::assign_bitwise_or, t_lhs.bv, t_rhs.bv)); return Boxed_Number(oper(Operators::Opers::assign_bitwise_or, t_lhs.bv, t_rhs.bv));
} }
static Boxed_Number assign_bitwise_xor(Boxed_Number t_lhs, const Boxed_Number &t_rhs) static Boxed_Number assign_bitwise_xor(Boxed_Number t_lhs, const Boxed_Number &t_rhs) {
{
return Boxed_Number(oper(Operators::Opers::assign_bitwise_xor, t_lhs.bv, t_rhs.bv)); return Boxed_Number(oper(Operators::Opers::assign_bitwise_xor, t_lhs.bv, t_rhs.bv));
} }
static Boxed_Number assign_remainder(Boxed_Number t_lhs, const Boxed_Number &t_rhs) static Boxed_Number assign_remainder(Boxed_Number t_lhs, const Boxed_Number &t_rhs) {
{
return Boxed_Number(oper(Operators::Opers::assign_remainder, t_lhs.bv, t_rhs.bv)); return Boxed_Number(oper(Operators::Opers::assign_remainder, t_lhs.bv, t_rhs.bv));
} }
static Boxed_Number assign_shift_left(Boxed_Number t_lhs, const Boxed_Number &t_rhs) static Boxed_Number assign_shift_left(Boxed_Number t_lhs, const Boxed_Number &t_rhs) {
{
return Boxed_Number(oper(Operators::Opers::assign_shift_left, t_lhs.bv, t_rhs.bv)); return Boxed_Number(oper(Operators::Opers::assign_shift_left, t_lhs.bv, t_rhs.bv));
} }
static Boxed_Number assign_shift_right(Boxed_Number t_lhs, const Boxed_Number &t_rhs) static Boxed_Number assign_shift_right(Boxed_Number t_lhs, const Boxed_Number &t_rhs) {
{
return Boxed_Number(oper(Operators::Opers::assign_shift_right, t_lhs.bv, t_rhs.bv)); return Boxed_Number(oper(Operators::Opers::assign_shift_right, t_lhs.bv, t_rhs.bv));
} }
static const Boxed_Number bitwise_and(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs) static const Boxed_Number bitwise_and(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs) {
{
return Boxed_Number(oper(Operators::Opers::bitwise_and, t_lhs.bv, t_rhs.bv)); return Boxed_Number(oper(Operators::Opers::bitwise_and, t_lhs.bv, t_rhs.bv));
} }
static const Boxed_Number bitwise_complement(const Boxed_Number &t_lhs) static const Boxed_Number bitwise_complement(const Boxed_Number &t_lhs) {
{
return Boxed_Number(oper(Operators::Opers::bitwise_complement, t_lhs.bv, Boxed_Value(0))); return Boxed_Number(oper(Operators::Opers::bitwise_complement, t_lhs.bv, Boxed_Value(0)));
} }
static const Boxed_Number bitwise_xor(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs) static const Boxed_Number bitwise_xor(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs) {
{
return Boxed_Number(oper(Operators::Opers::bitwise_xor, t_lhs.bv, t_rhs.bv)); return Boxed_Number(oper(Operators::Opers::bitwise_xor, t_lhs.bv, t_rhs.bv));
} }
static const Boxed_Number bitwise_or(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs) static const Boxed_Number bitwise_or(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs) {
{
return Boxed_Number(oper(Operators::Opers::bitwise_or, t_lhs.bv, t_rhs.bv)); return Boxed_Number(oper(Operators::Opers::bitwise_or, t_lhs.bv, t_rhs.bv));
} }
static Boxed_Number assign_product(Boxed_Number t_lhs, const Boxed_Number &t_rhs) static Boxed_Number assign_product(Boxed_Number t_lhs, const Boxed_Number &t_rhs) {
{
return Boxed_Number(oper(Operators::Opers::assign_product, t_lhs.bv, t_rhs.bv)); return Boxed_Number(oper(Operators::Opers::assign_product, t_lhs.bv, t_rhs.bv));
} }
static Boxed_Number assign_quotient(Boxed_Number t_lhs, const Boxed_Number &t_rhs) static Boxed_Number assign_quotient(Boxed_Number t_lhs, const Boxed_Number &t_rhs) {
{
return Boxed_Number(oper(Operators::Opers::assign_quotient, t_lhs.bv, t_rhs.bv)); return Boxed_Number(oper(Operators::Opers::assign_quotient, t_lhs.bv, t_rhs.bv));
} }
static Boxed_Number assign_sum(Boxed_Number t_lhs, const Boxed_Number &t_rhs) static Boxed_Number assign_sum(Boxed_Number t_lhs, const Boxed_Number &t_rhs) {
{
return Boxed_Number(oper(Operators::Opers::assign_sum, t_lhs.bv, t_rhs.bv)); return Boxed_Number(oper(Operators::Opers::assign_sum, t_lhs.bv, t_rhs.bv));
} }
static Boxed_Number assign_difference(Boxed_Number t_lhs, const Boxed_Number &t_rhs) static Boxed_Number assign_difference(Boxed_Number t_lhs, const Boxed_Number &t_rhs) {
{
return Boxed_Number(oper(Operators::Opers::assign_difference, t_lhs.bv, t_rhs.bv)); return Boxed_Number(oper(Operators::Opers::assign_difference, t_lhs.bv, t_rhs.bv));
} }
static const Boxed_Number quotient(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs) static const Boxed_Number quotient(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs) {
{
return Boxed_Number(oper(Operators::Opers::quotient, t_lhs.bv, t_rhs.bv)); return Boxed_Number(oper(Operators::Opers::quotient, t_lhs.bv, t_rhs.bv));
} }
static const Boxed_Number shift_left(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs) static const Boxed_Number shift_left(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs) {
{
return Boxed_Number(oper(Operators::Opers::shift_left, t_lhs.bv, t_rhs.bv)); return Boxed_Number(oper(Operators::Opers::shift_left, t_lhs.bv, t_rhs.bv));
} }
static const Boxed_Number product(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs) static const Boxed_Number product(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs) {
{
return Boxed_Number(oper(Operators::Opers::product, t_lhs.bv, t_rhs.bv)); return Boxed_Number(oper(Operators::Opers::product, t_lhs.bv, t_rhs.bv));
} }
static const Boxed_Number remainder(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs) static const Boxed_Number remainder(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs) {
{
return Boxed_Number(oper(Operators::Opers::remainder, t_lhs.bv, t_rhs.bv)); return Boxed_Number(oper(Operators::Opers::remainder, t_lhs.bv, t_rhs.bv));
} }
static const Boxed_Number shift_right(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs) static const Boxed_Number shift_right(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs) {
{
return Boxed_Number(oper(Operators::Opers::shift_right, t_lhs.bv, t_rhs.bv)); return Boxed_Number(oper(Operators::Opers::shift_right, t_lhs.bv, t_rhs.bv));
} }
static Boxed_Value do_oper(Operators::Opers t_oper, const Boxed_Value &t_lhs, const Boxed_Value &t_rhs) {
static Boxed_Value do_oper(Operators::Opers t_oper, const Boxed_Value &t_lhs, const Boxed_Value &t_rhs)
{
return oper(t_oper, t_lhs, t_rhs); return oper(t_oper, t_lhs, t_rhs);
} }
static Boxed_Value do_oper(Operators::Opers t_oper, const Boxed_Value &t_lhs) static Boxed_Value do_oper(Operators::Opers t_oper, const Boxed_Value &t_lhs) { return oper(t_oper, t_lhs); }
{
return oper(t_oper, t_lhs);
}
Boxed_Value bv; Boxed_Value bv;
}; };
namespace detail namespace detail {
{
/// Cast_Helper for converting from Boxed_Value to Boxed_Number /// Cast_Helper for converting from Boxed_Value to Boxed_Number
template<> template<>
struct Cast_Helper<Boxed_Number> struct Cast_Helper<Boxed_Number> {
{ static Boxed_Number cast(const Boxed_Value &ob, const Type_Conversions_State *) { return Boxed_Number(ob); }
static Boxed_Number cast(const Boxed_Value &ob, const Type_Conversions_State *)
{
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<> template<>
struct Cast_Helper<const Boxed_Number &> : Cast_Helper<Boxed_Number> 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<> template<>
struct Cast_Helper<const Boxed_Number> : Cast_Helper<Boxed_Number> struct Cast_Helper<const Boxed_Number> : Cast_Helper<Boxed_Number> {
{
}; };
} } // namespace detail
#ifdef __GNUC__ #ifdef __GNUC__
#pragma GCC diagnostic pop #pragma GCC diagnostic pop
@ -804,9 +708,6 @@ namespace chaiscript
#pragma warning(pop) #pragma warning(pop)
#endif #endif
} } // namespace chaiscript
#endif #endif

View File

@ -7,7 +7,6 @@
// This is an open source non-commercial project. Dear PVS-Studio, please check it. // This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com // PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_BOXED_VALUE_HPP_ #ifndef CHAISCRIPT_BOXED_VALUE_HPP_
#define CHAISCRIPT_BOXED_VALUE_HPP_ #define CHAISCRIPT_BOXED_VALUE_HPP_
@ -19,36 +18,29 @@
#include "any.hpp" #include "any.hpp"
#include "type_info.hpp" #include "type_info.hpp"
namespace chaiscript namespace chaiscript {
{
/// \brief A wrapper for holding any valid C++ type. All types in ChaiScript are Boxed_Value objects /// \brief A wrapper for holding any valid C++ type. All types in ChaiScript are Boxed_Value objects
/// \sa chaiscript::boxed_cast /// \sa chaiscript::boxed_cast
class Boxed_Value class Boxed_Value {
{
public: public:
/// used for explicitly creating a "void" object /// used for explicitly creating a "void" object
struct Void_Type struct Void_Type {
{
}; };
private: private:
/// structure which holds the internal state of a Boxed_Value /// structure which holds the internal state of a Boxed_Value
/// \todo Get rid of Any and merge it with this, reducing an allocation in the process /// \todo Get rid of Any and merge it with this, reducing an allocation in the process
struct Data struct Data {
{ Data(const Type_Info &ti, chaiscript::detail::Any to, bool is_ref, const void *t_void_ptr, bool t_return_value)
Data(const Type_Info &ti, : m_type_info(ti)
chaiscript::detail::Any to, , m_obj(std::move(to))
bool is_ref, , m_data_ptr(ti.is_const() ? nullptr : const_cast<void *>(t_void_ptr))
const void *t_void_ptr, , m_const_data_ptr(t_void_ptr)
bool t_return_value) , m_is_ref(is_ref)
: m_type_info(ti), m_obj(std::move(to)), m_data_ptr(ti.is_const()?nullptr:const_cast<void *>(t_void_ptr)), m_const_data_ptr(t_void_ptr), , m_return_value(t_return_value) {
m_is_ref(is_ref), m_return_value(t_return_value)
{
} }
Data &operator=(const Data &rhs) Data &operator=(const Data &rhs) {
{
m_type_info = rhs.m_type_info; m_type_info = rhs.m_type_info;
m_obj = rhs.m_obj; m_obj = rhs.m_obj;
m_is_ref = rhs.m_is_ref; m_is_ref = rhs.m_is_ref;
@ -56,8 +48,7 @@ namespace chaiscript
m_const_data_ptr = rhs.m_const_data_ptr; m_const_data_ptr = rhs.m_const_data_ptr;
m_return_value = rhs.m_return_value; m_return_value = rhs.m_return_value;
if (rhs.m_attrs) if (rhs.m_attrs) {
{
m_attrs = std::make_unique<std::map<std::string, std::shared_ptr<Data>>>(*rhs.m_attrs); m_attrs = std::make_unique<std::map<std::string, std::shared_ptr<Data>>>(*rhs.m_attrs);
} }
@ -69,7 +60,6 @@ namespace chaiscript
Data(Data &&) = default; Data(Data &&) = default;
Data &operator=(Data &&rhs) = default; Data &operator=(Data &&rhs) = default;
Type_Info m_type_info; Type_Info m_type_info;
chaiscript::detail::Any m_obj; chaiscript::detail::Any m_obj;
void *m_data_ptr; void *m_data_ptr;
@ -79,197 +69,118 @@ namespace chaiscript
bool m_return_value; bool m_return_value;
}; };
struct Object_Data struct Object_Data {
{ static auto get(Boxed_Value::Void_Type, bool t_return_value) {
static auto get(Boxed_Value::Void_Type, bool t_return_value) return std::make_shared<Data>(detail::Get_Type_Info<void>::get(), chaiscript::detail::Any(), false, nullptr, t_return_value);
{
return std::make_shared<Data>(
detail::Get_Type_Info<void>::get(),
chaiscript::detail::Any(),
false,
nullptr,
t_return_value)
;
} }
template<typename T> template<typename T>
static auto get(const std::shared_ptr<T> *obj, bool t_return_value) static auto get(const std::shared_ptr<T> *obj, bool t_return_value) {
{
return get(*obj, t_return_value); return get(*obj, t_return_value);
} }
template<typename T> template<typename T>
static auto get(const std::shared_ptr<T> &obj, bool t_return_value) static auto get(const std::shared_ptr<T> &obj, bool t_return_value) {
{ return std::make_shared<Data>(detail::Get_Type_Info<T>::get(), chaiscript::detail::Any(obj), false, obj.get(), t_return_value);
return std::make_shared<Data>(
detail::Get_Type_Info<T>::get(),
chaiscript::detail::Any(obj),
false,
obj.get(),
t_return_value
);
} }
template<typename T> template<typename T>
static auto get(std::shared_ptr<T> &&obj, bool t_return_value) static auto get(std::shared_ptr<T> &&obj, bool t_return_value) {
{
auto ptr = obj.get(); auto ptr = obj.get();
return std::make_shared<Data>( return std::make_shared<Data>(detail::Get_Type_Info<T>::get(), chaiscript::detail::Any(std::move(obj)), false, ptr, t_return_value);
detail::Get_Type_Info<T>::get(),
chaiscript::detail::Any(std::move(obj)),
false,
ptr,
t_return_value
);
} }
template<typename T> template<typename T>
static auto get(T *t, bool t_return_value) static auto get(T *t, bool t_return_value) {
{
return get(std::ref(*t), t_return_value); return get(std::ref(*t), t_return_value);
} }
template<typename T> template<typename T>
static auto get(const T *t, bool t_return_value) static auto get(const T *t, bool t_return_value) {
{
return get(std::cref(*t), t_return_value); return get(std::cref(*t), t_return_value);
} }
template<typename T> template<typename T>
static auto get(std::reference_wrapper<T> obj, bool t_return_value) static auto get(std::reference_wrapper<T> obj, bool t_return_value) {
{
auto p = &obj.get(); auto p = &obj.get();
return std::make_shared<Data>( return std::make_shared<Data>(detail::Get_Type_Info<T>::get(), chaiscript::detail::Any(std::move(obj)), true, p, t_return_value);
detail::Get_Type_Info<T>::get(),
chaiscript::detail::Any(std::move(obj)),
true,
p,
t_return_value
);
} }
template<typename T> template<typename T>
static auto get(std::unique_ptr<T> &&obj, bool t_return_value) static auto get(std::unique_ptr<T> &&obj, bool t_return_value) {
{
auto ptr = obj.get(); auto ptr = obj.get();
return std::make_shared<Data>( return std::make_shared<Data>(detail::Get_Type_Info<T>::get(),
detail::Get_Type_Info<T>::get(),
chaiscript::detail::Any(std::make_shared<std::unique_ptr<T>>(std::move(obj))), chaiscript::detail::Any(std::make_shared<std::unique_ptr<T>>(std::move(obj))),
true, true,
ptr, ptr,
t_return_value t_return_value);
);
} }
template<typename T> template<typename T>
static auto get(T t, bool t_return_value) static auto get(T t, bool t_return_value) {
{
auto p = std::make_shared<T>(std::move(t)); auto p = std::make_shared<T>(std::move(t));
auto ptr = p.get(); auto ptr = p.get();
return std::make_shared<Data>( return std::make_shared<Data>(detail::Get_Type_Info<T>::get(), chaiscript::detail::Any(std::move(p)), false, ptr, t_return_value);
detail::Get_Type_Info<T>::get(),
chaiscript::detail::Any(std::move(p)),
false,
ptr,
t_return_value
);
}
static std::shared_ptr<Data> get()
{
return std::make_shared<Data>(
Type_Info(),
chaiscript::detail::Any(),
false,
nullptr,
false
);
} }
static std::shared_ptr<Data> get() { return std::make_shared<Data>(Type_Info(), chaiscript::detail::Any(), false, nullptr, false); }
}; };
public: public:
/// Basic Boxed_Value constructor /// Basic Boxed_Value constructor
template<typename T, template<typename T, typename = std::enable_if_t<!std::is_same_v<Boxed_Value, std::decay_t<T>>>>
typename = std::enable_if_t<!std::is_same_v<Boxed_Value, std::decay_t<T>>>>
explicit Boxed_Value(T &&t, bool t_return_value = false) explicit Boxed_Value(T &&t, bool t_return_value = false)
: m_data(Object_Data::get(std::forward<T>(t), t_return_value)) : m_data(Object_Data::get(std::forward<T>(t), t_return_value)) {
{
} }
/// Unknown-type constructor /// Unknown-type constructor
Boxed_Value() = default; Boxed_Value() = default;
Boxed_Value(Boxed_Value&&) = default; Boxed_Value(Boxed_Value &&) = default;
Boxed_Value& operator=(Boxed_Value&&) = default; Boxed_Value &operator=(Boxed_Value &&) = default;
Boxed_Value(const Boxed_Value&) = default; Boxed_Value(const Boxed_Value &) = default;
Boxed_Value& operator=(const Boxed_Value&) = default; Boxed_Value &operator=(const Boxed_Value &) = default;
void swap(Boxed_Value &rhs) noexcept void swap(Boxed_Value &rhs) noexcept { std::swap(m_data, rhs.m_data); }
{
std::swap(m_data, rhs.m_data);
}
/// Copy the values stored in rhs.m_data to m_data. /// Copy the values stored in rhs.m_data to m_data.
/// m_data pointers are not shared in this case /// m_data pointers are not shared in this case
Boxed_Value assign(const Boxed_Value &rhs) noexcept Boxed_Value assign(const Boxed_Value &rhs) noexcept {
{
(*m_data) = (*rhs.m_data); (*m_data) = (*rhs.m_data);
return *this; return *this;
} }
const Type_Info &get_type_info() const noexcept const Type_Info &get_type_info() const noexcept { return m_data->m_type_info; }
{
return m_data->m_type_info;
}
/// return true if the object is uninitialized /// return true if the object is uninitialized
bool is_undef() const noexcept bool is_undef() const noexcept { return m_data->m_type_info.is_undef(); }
{
return m_data->m_type_info.is_undef();
}
bool is_const() const noexcept bool is_const() const noexcept { return m_data->m_type_info.is_const(); }
{
return m_data->m_type_info.is_const();
}
bool is_type(const Type_Info &ti) const noexcept
{
return m_data->m_type_info.bare_equal(ti);
}
bool is_type(const Type_Info &ti) const noexcept { return m_data->m_type_info.bare_equal(ti); }
template<typename T> template<typename T>
auto pointer_sentinel(std::shared_ptr<T> &ptr) const noexcept auto pointer_sentinel(std::shared_ptr<T> &ptr) const noexcept {
{
struct Sentinel { struct Sentinel {
Sentinel(std::shared_ptr<T> &t_ptr, Data &data) Sentinel(std::shared_ptr<T> &t_ptr, Data &data)
: m_ptr(t_ptr), m_data(data) : m_ptr(t_ptr)
{ , m_data(data) {
} }
~Sentinel() ~Sentinel() {
{
// save new pointer data // save new pointer data
const auto ptr_ = m_ptr.get().get(); const auto ptr_ = m_ptr.get().get();
m_data.get().m_data_ptr = ptr_; m_data.get().m_data_ptr = ptr_;
m_data.get().m_const_data_ptr = ptr_; m_data.get().m_const_data_ptr = ptr_;
} }
Sentinel& operator=(Sentinel&&s) = default; Sentinel &operator=(Sentinel &&s) = default;
Sentinel(Sentinel &&s) = default; Sentinel(Sentinel &&s) = default;
operator std::shared_ptr<T>&() const noexcept operator std::shared_ptr<T> &() const noexcept { return m_ptr.get(); }
{
return m_ptr.get();
}
Sentinel &operator=(const Sentinel &) = delete; Sentinel &operator=(const Sentinel &) = delete;
Sentinel(Sentinel&) = delete; Sentinel(Sentinel &) = delete;
std::reference_wrapper<std::shared_ptr<T>> m_ptr; std::reference_wrapper<std::shared_ptr<T>> m_ptr;
std::reference_wrapper<Data> m_data; std::reference_wrapper<Data> m_data;
@ -278,50 +189,24 @@ namespace chaiscript
return Sentinel(ptr, *(m_data.get())); return Sentinel(ptr, *(m_data.get()));
} }
bool is_null() const noexcept bool is_null() const noexcept { return (m_data->m_data_ptr == nullptr && m_data->m_const_data_ptr == nullptr); }
{
return (m_data->m_data_ptr == nullptr && m_data->m_const_data_ptr == nullptr);
}
const chaiscript::detail::Any & get() const noexcept const chaiscript::detail::Any &get() const noexcept { return m_data->m_obj; }
{
return m_data->m_obj;
}
bool is_ref() const noexcept bool is_ref() const noexcept { return m_data->m_is_ref; }
{
return m_data->m_is_ref;
}
bool is_return_value() const noexcept bool is_return_value() const noexcept { return m_data->m_return_value; }
{
return m_data->m_return_value;
}
void reset_return_value() const noexcept void reset_return_value() const noexcept { m_data->m_return_value = false; }
{
m_data->m_return_value = false;
}
bool is_pointer() const noexcept bool is_pointer() const noexcept { return !is_ref(); }
{
return !is_ref();
}
void *get_ptr() const noexcept void *get_ptr() const noexcept { return m_data->m_data_ptr; }
{
return m_data->m_data_ptr;
}
const void *get_const_ptr() const noexcept const void *get_const_ptr() const noexcept { return m_data->m_const_data_ptr; }
{
return m_data->m_const_data_ptr;
}
Boxed_Value get_attr(const std::string &t_name) Boxed_Value get_attr(const std::string &t_name) {
{ if (!m_data->m_attrs) {
if (!m_data->m_attrs)
{
m_data->m_attrs = std::make_unique<std::map<std::string, std::shared_ptr<Data>>>(); m_data->m_attrs = std::make_unique<std::map<std::string, std::shared_ptr<Data>>>();
} }
@ -329,38 +214,32 @@ namespace chaiscript
if (attr) { if (attr) {
return Boxed_Value(attr, Internal_Construction()); return Boxed_Value(attr, Internal_Construction());
} else { } else {
Boxed_Value bv; //default construct a new one Boxed_Value bv; // default construct a new one
attr = bv.m_data; attr = bv.m_data;
return bv; return bv;
} }
} }
Boxed_Value &copy_attrs(const Boxed_Value &t_obj) Boxed_Value &copy_attrs(const Boxed_Value &t_obj) {
{ if (t_obj.m_data->m_attrs) {
if (t_obj.m_data->m_attrs)
{
m_data->m_attrs = std::make_unique<std::map<std::string, std::shared_ptr<Data>>>(*t_obj.m_data->m_attrs); m_data->m_attrs = std::make_unique<std::map<std::string, std::shared_ptr<Data>>>(*t_obj.m_data->m_attrs);
} }
return *this; return *this;
} }
Boxed_Value &clone_attrs(const Boxed_Value &t_obj) Boxed_Value &clone_attrs(const Boxed_Value &t_obj) {
{
copy_attrs(t_obj); copy_attrs(t_obj);
reset_return_value(); reset_return_value();
return *this; return *this;
} }
/// \returns true if the two Boxed_Values share the same internal type /// \returns true if the two Boxed_Values share the same internal type
static bool type_match(const Boxed_Value &l, const Boxed_Value &r) noexcept static bool type_match(const Boxed_Value &l, const Boxed_Value &r) noexcept { return l.get_type_info() == r.get_type_info(); }
{
return l.get_type_info() == r.get_type_info();
}
private: private:
// necessary to avoid hitting the templated && constructor of Boxed_Value // necessary to avoid hitting the templated && constructor of Boxed_Value
struct Internal_Construction{}; struct Internal_Construction {
};
Boxed_Value(std::shared_ptr<Data> t_data, Internal_Construction) Boxed_Value(std::shared_ptr<Data> t_data, Internal_Construction)
: m_data(std::move(t_data)) { : m_data(std::move(t_data)) {
@ -369,7 +248,8 @@ namespace chaiscript
std::shared_ptr<Data> m_data = Object_Data::get(); std::shared_ptr<Data> m_data = Object_Data::get();
}; };
/// @brief Creates a Boxed_Value. If the object passed in is a value type, it is copied. If it is a pointer, std::shared_ptr, or std::reference_type /// @brief Creates a Boxed_Value. If the object passed in is a value type, it is copied. If it is a pointer, std::shared_ptr, or
/// std::reference_type
/// a copy is not made. /// a copy is not made.
/// @param t The value to box /// @param t The value to box
/// ///
@ -384,8 +264,7 @@ namespace chaiscript
/// ///
/// @sa @ref adding_objects /// @sa @ref adding_objects
template<typename T> template<typename T>
Boxed_Value var(T &&t) Boxed_Value var(T &&t) {
{
return Boxed_Value(std::forward<T>(t)); return Boxed_Value(std::forward<T>(t));
} }
@ -395,9 +274,8 @@ namespace chaiscript
/// \returns Immutable Boxed_Value /// \returns Immutable Boxed_Value
/// \sa Boxed_Value::is_const /// \sa Boxed_Value::is_const
template<typename T> template<typename T>
Boxed_Value const_var_impl(const T &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));
} }
/// \brief Takes a pointer to a value, adds const to the pointed to type and returns an immutable Boxed_Value. /// \brief Takes a pointer to a value, adds const to the pointed to type and returns an immutable Boxed_Value.
@ -406,9 +284,8 @@ namespace chaiscript
/// \returns Immutable Boxed_Value /// \returns Immutable Boxed_Value
/// \sa Boxed_Value::is_const /// \sa Boxed_Value::is_const
template<typename T> template<typename T>
Boxed_Value const_var_impl(T *t) Boxed_Value const_var_impl(T *t) {
{ return Boxed_Value(const_cast<typename std::add_const<T>::type *>(t));
return Boxed_Value( const_cast<typename std::add_const<T>::type *>(t) );
} }
/// \brief Takes a std::shared_ptr to a value, adds const to the pointed to type and returns an immutable Boxed_Value. /// \brief Takes a std::shared_ptr to a value, adds const to the pointed to type and returns an immutable Boxed_Value.
@ -417,9 +294,8 @@ namespace chaiscript
/// \returns Immutable Boxed_Value /// \returns Immutable Boxed_Value
/// \sa Boxed_Value::is_const /// \sa Boxed_Value::is_const
template<typename T> template<typename T>
Boxed_Value const_var_impl(const std::shared_ptr<T> &t) Boxed_Value const_var_impl(const std::shared_ptr<T> &t) {
{ return Boxed_Value(std::const_pointer_cast<typename std::add_const<T>::type>(t));
return Boxed_Value( std::const_pointer_cast<typename std::add_const<T>::type>(t) );
} }
/// \brief Takes a std::reference_wrapper value, adds const to the referenced type and returns an immutable Boxed_Value. /// \brief Takes a std::reference_wrapper value, adds const to the referenced type and returns an immutable Boxed_Value.
@ -428,11 +304,10 @@ namespace chaiscript
/// \returns Immutable Boxed_Value /// \returns Immutable Boxed_Value
/// \sa Boxed_Value::is_const /// \sa Boxed_Value::is_const
template<typename T> template<typename T>
Boxed_Value const_var_impl(const std::reference_wrapper<T> &t) Boxed_Value const_var_impl(const std::reference_wrapper<T> &t) {
{ return Boxed_Value(std::cref(t.get()));
return Boxed_Value( std::cref(t.get()) );
}
} }
} // namespace detail
/// \brief Takes an object and returns an immutable Boxed_Value. If the object is a std::reference or pointer type /// \brief Takes an object and returns an immutable Boxed_Value. If the object is a std::reference or pointer type
/// the value is not copied. If it is an object type, it is copied. /// the value is not copied. If it is an object type, it is copied.
@ -458,8 +333,7 @@ namespace chaiscript
/// \todo support C++11 strongly typed enums /// \todo support C++11 strongly typed enums
/// \sa \ref adding_objects /// \sa \ref adding_objects
template<typename T> template<typename T>
Boxed_Value const_var(const T &t) Boxed_Value const_var(const T &t) {
{
return detail::const_var_impl(t); return detail::const_var_impl(t);
} }
@ -479,7 +353,6 @@ namespace chaiscript
} }
} }
} } // namespace chaiscript
#endif #endif

View File

@ -12,49 +12,50 @@
namespace chaiscript { namespace chaiscript {
namespace dispatch { namespace dispatch {
namespace detail { namespace detail {
template<typename Class, typename... Param>
template<typename Class, typename ... Param> struct Constructor {
struct Constructor template<typename... Inner>
{ std::shared_ptr<Class> operator()(Inner &&...inner) const {
template<typename ... Inner>
std::shared_ptr<Class> operator()(Inner&& ... inner) const {
return std::make_shared<Class>(std::forward<Inner>(inner)...); return std::make_shared<Class>(std::forward<Inner>(inner)...);
} }
}; };
template<typename Ret, typename Class, typename ... Param> template<typename Ret, typename Class, typename... Param>
struct Const_Caller struct Const_Caller {
{ explicit Const_Caller(Ret (Class::*t_func)(Param...) const)
explicit Const_Caller(Ret (Class::*t_func)(Param...) const) : m_func(t_func) {} : m_func(t_func) {
}
template<typename ... Inner> template<typename... Inner>
Ret operator()(const Class &o, Inner&& ... inner) const { Ret operator()(const Class &o, Inner &&...inner) const {
return (o.*m_func)(std::forward<Inner>(inner)...); return (o.*m_func)(std::forward<Inner>(inner)...);
} }
Ret (Class::*m_func)(Param...) const; Ret (Class::*m_func)(Param...) const;
}; };
template<typename Ret, typename ... Param> template<typename Ret, typename... Param>
struct Fun_Caller struct Fun_Caller {
{ explicit Fun_Caller(Ret (*t_func)(Param...))
explicit Fun_Caller(Ret( * t_func)(Param...) ) : m_func(t_func) {} : m_func(t_func) {
}
template<typename ... Inner> template<typename... Inner>
Ret operator()(Inner&& ... inner) const { Ret operator()(Inner &&...inner) const {
return (m_func)(std::forward<Inner>(inner)...); return (m_func)(std::forward<Inner>(inner)...);
} }
Ret(*m_func)(Param...); Ret (*m_func)(Param...);
}; };
template<typename Ret, typename Class, typename ... Param> template<typename Ret, typename Class, typename... Param>
struct Caller struct Caller {
{ explicit Caller(Ret (Class::*t_func)(Param...))
explicit Caller(Ret (Class::*t_func)(Param...)) : m_func(t_func) {} : m_func(t_func) {
}
template<typename ... Inner> template<typename... Inner>
Ret operator()(Class &o, Inner&& ... inner) const { Ret operator()(Class &o, Inner &&...inner) const {
return (o.*m_func)(std::forward<Inner>(inner)...); return (o.*m_func)(std::forward<Inner>(inner)...);
} }
@ -62,46 +63,37 @@ namespace chaiscript {
}; };
template<typename T> template<typename T>
struct Arity struct Arity {
{
}; };
template<typename Ret, typename ... Params> template<typename Ret, typename... Params>
struct Arity<Ret (Params...)> struct Arity<Ret(Params...)> {
{
static const size_t arity = sizeof...(Params); static const size_t arity = sizeof...(Params);
}; };
template<typename T>
struct Function_Signature {
};
template<typename Ret, typename... Params>
struct Function_Signature<Ret(Params...)> {
using Return_Type = Ret;
using Signature = Ret()(Params...);
};
template<typename Ret, typename T, typename... Params>
struct Function_Signature<Ret (T::*)(Params...) const> {
using Return_Type = Ret;
using Signature = Ret()(Params...);
};
template<typename T> template<typename T>
struct Function_Signature struct Callable_Traits {
{
};
template<typename Ret, typename ... Params>
struct Function_Signature<Ret (Params...)>
{
using Return_Type = Ret;
using Signature = Ret ()(Params...);
};
template<typename Ret, typename T, typename ... Params>
struct Function_Signature<Ret (T::*)(Params...) const>
{
using Return_Type = Ret;
using Signature = Ret ()(Params...);
};
template<typename T>
struct Callable_Traits
{
using Signature = typename Function_Signature<decltype(&T::operator())>::Signature; using Signature = typename Function_Signature<decltype(&T::operator())>::Signature;
using Return_Type = typename Function_Signature<decltype(&T::operator())>::Return_Type; using Return_Type = typename Function_Signature<decltype(&T::operator())>::Return_Type;
}; };
} } // namespace detail
} } // namespace dispatch
} } // namespace chaiscript
#endif #endif

File diff suppressed because it is too large Load Diff

View File

@ -7,7 +7,6 @@
// This is an open source non-commercial project. Dear PVS-Studio, please check it. // This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com // PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_DYNAMIC_OBJECT_HPP_ #ifndef CHAISCRIPT_DYNAMIC_OBJECT_HPP_
#define CHAISCRIPT_DYNAMIC_OBJECT_HPP_ #define CHAISCRIPT_DYNAMIC_OBJECT_HPP_
@ -18,21 +17,17 @@
#include "boxed_value.hpp" #include "boxed_value.hpp"
namespace chaiscript { namespace chaiscript {
class Type_Conversions; class Type_Conversions;
namespace dispatch { namespace dispatch {
class Proxy_Function_Base; class Proxy_Function_Base;
} // namespace dispatch } // namespace dispatch
} // namespace chaiscript } // namespace chaiscript
namespace chaiscript namespace chaiscript {
{ namespace dispatch {
namespace dispatch
{
struct option_explicit_set : std::runtime_error { struct option_explicit_set : std::runtime_error {
explicit option_explicit_set(const std::string &t_param_name) explicit option_explicit_set(const std::string &t_param_name)
: std::runtime_error("option explicit set and parameter '" + t_param_name + "' does not exist") : std::runtime_error("option explicit set and parameter '" + t_param_name + "' does not exist") {
{
} }
option_explicit_set(const option_explicit_set &) = default; option_explicit_set(const option_explicit_set &) = default;
@ -40,43 +35,26 @@ namespace chaiscript
~option_explicit_set() noexcept override = default; ~option_explicit_set() noexcept override = default;
}; };
class Dynamic_Object class Dynamic_Object {
{
public: public:
explicit Dynamic_Object(std::string t_type_name) explicit Dynamic_Object(std::string t_type_name)
: m_type_name(std::move(t_type_name)), m_option_explicit(false) : m_type_name(std::move(t_type_name))
{ , m_option_explicit(false) {
} }
Dynamic_Object() = default; Dynamic_Object() = default;
bool is_explicit() const noexcept bool is_explicit() const noexcept { return m_option_explicit; }
{
return m_option_explicit;
}
void set_explicit(const bool t_explicit) noexcept void set_explicit(const bool t_explicit) noexcept { m_option_explicit = t_explicit; }
{
m_option_explicit = t_explicit;
}
const std::string &get_type_name() const noexcept const std::string &get_type_name() const noexcept { return m_type_name; }
{
return m_type_name;
}
const Boxed_Value &operator[](const std::string &t_attr_name) const const Boxed_Value &operator[](const std::string &t_attr_name) const { return get_attr(t_attr_name); }
{
return get_attr(t_attr_name);
}
Boxed_Value &operator[](const std::string &t_attr_name) Boxed_Value &operator[](const std::string &t_attr_name) { return get_attr(t_attr_name); }
{
return get_attr(t_attr_name);
}
const Boxed_Value &get_attr(const std::string &t_attr_name) const const Boxed_Value &get_attr(const std::string &t_attr_name) const {
{
auto a = m_attrs.find(t_attr_name); auto a = m_attrs.find(t_attr_name);
if (a != m_attrs.end()) { if (a != m_attrs.end()) {
@ -86,17 +64,11 @@ namespace chaiscript
} }
} }
bool has_attr(const std::string &t_attr_name) const { bool has_attr(const std::string &t_attr_name) const { return m_attrs.find(t_attr_name) != m_attrs.end(); }
return m_attrs.find(t_attr_name) != m_attrs.end();
}
Boxed_Value &get_attr(const std::string &t_attr_name) Boxed_Value &get_attr(const std::string &t_attr_name) { return m_attrs[t_attr_name]; }
{
return m_attrs[t_attr_name];
}
Boxed_Value &method_missing(const std::string &t_method_name) Boxed_Value &method_missing(const std::string &t_method_name) {
{
if (m_option_explicit && m_attrs.find(t_method_name) == m_attrs.end()) { if (m_option_explicit && m_attrs.find(t_method_name) == m_attrs.end()) {
throw option_explicit_set(t_method_name); throw option_explicit_set(t_method_name);
} }
@ -104,8 +76,7 @@ namespace chaiscript
return get_attr(t_method_name); return get_attr(t_method_name);
} }
const Boxed_Value &method_missing(const std::string &t_method_name) const const Boxed_Value &method_missing(const std::string &t_method_name) const {
{
if (m_option_explicit && m_attrs.find(t_method_name) == m_attrs.end()) { if (m_option_explicit && m_attrs.find(t_method_name) == m_attrs.end()) {
throw option_explicit_set(t_method_name); throw option_explicit_set(t_method_name);
} }
@ -113,10 +84,7 @@ namespace chaiscript
return get_attr(t_method_name); return get_attr(t_method_name);
} }
std::map<std::string, Boxed_Value> get_attrs() const std::map<std::string, Boxed_Value> get_attrs() const { return m_attrs; }
{
return m_attrs;
}
private: private:
const std::string m_type_name = ""; const std::string m_type_name = "";
@ -125,7 +93,6 @@ namespace chaiscript
std::map<std::string, Boxed_Value> m_attrs; std::map<std::string, Boxed_Value> m_attrs;
}; };
} } // namespace dispatch
} } // namespace chaiscript
#endif #endif

View File

@ -19,62 +19,51 @@
#include "boxed_cast.hpp" #include "boxed_cast.hpp"
#include "boxed_cast_helper.hpp" #include "boxed_cast_helper.hpp"
#include "boxed_value.hpp" #include "boxed_value.hpp"
#include "dynamic_object.hpp"
#include "proxy_functions.hpp" #include "proxy_functions.hpp"
#include "type_info.hpp" #include "type_info.hpp"
#include "dynamic_object.hpp"
namespace chaiscript { namespace chaiscript {
class Type_Conversions; class Type_Conversions;
namespace dispatch { namespace dispatch {
class Proxy_Function_Base; class Proxy_Function_Base;
} // namespace dispatch } // namespace dispatch
} // namespace chaiscript } // namespace chaiscript
namespace chaiscript namespace chaiscript {
{ namespace dispatch {
namespace dispatch namespace detail {
{
namespace detail
{
/// A Proxy_Function implementation designed for calling a function /// A Proxy_Function implementation designed for calling a function
/// that is automatically guarded based on the first param based on the /// that is automatically guarded based on the first param based on the
/// param's type name /// param's type name
class Dynamic_Object_Function final : public Proxy_Function_Base class Dynamic_Object_Function final : public Proxy_Function_Base {
{
public: public:
Dynamic_Object_Function( Dynamic_Object_Function(std::string t_type_name, const Proxy_Function &t_func, bool t_is_attribute = false)
std::string t_type_name, : Proxy_Function_Base(t_func->get_param_types(), t_func->get_arity())
const Proxy_Function &t_func, , m_type_name(std::move(t_type_name))
bool t_is_attribute = false) , m_func(t_func)
: Proxy_Function_Base(t_func->get_param_types(), t_func->get_arity()), , m_doti(user_type<Dynamic_Object>())
m_type_name(std::move(t_type_name)), m_func(t_func), m_doti(user_type<Dynamic_Object>()), , m_is_attribute(t_is_attribute) {
m_is_attribute(t_is_attribute) assert((t_func->get_arity() > 0 || t_func->get_arity() < 0)
{
assert( (t_func->get_arity() > 0 || t_func->get_arity() < 0)
&& "Programming error, Dynamic_Object_Function must have at least one parameter (this)"); && "Programming error, Dynamic_Object_Function must have at least one parameter (this)");
} }
Dynamic_Object_Function( Dynamic_Object_Function(std::string t_type_name, const Proxy_Function &t_func, const Type_Info &t_ti, bool t_is_attribute = false)
std::string t_type_name, : Proxy_Function_Base(build_param_types(t_func->get_param_types(), t_ti), t_func->get_arity())
const Proxy_Function &t_func, , m_type_name(std::move(t_type_name))
const Type_Info &t_ti, , m_func(t_func)
bool t_is_attribute = false) , m_ti(t_ti.is_undef() ? nullptr : new Type_Info(t_ti))
: Proxy_Function_Base(build_param_types(t_func->get_param_types(), t_ti), t_func->get_arity()), , m_doti(user_type<Dynamic_Object>())
m_type_name(std::move(t_type_name)), m_func(t_func), m_ti(t_ti.is_undef()?nullptr:new Type_Info(t_ti)), m_doti(user_type<Dynamic_Object>()), , m_is_attribute(t_is_attribute) {
m_is_attribute(t_is_attribute) assert((t_func->get_arity() > 0 || t_func->get_arity() < 0)
{
assert( (t_func->get_arity() > 0 || t_func->get_arity() < 0)
&& "Programming error, Dynamic_Object_Function must have at least one parameter (this)"); && "Programming error, Dynamic_Object_Function must have at least one parameter (this)");
} }
Dynamic_Object_Function &operator=(const Dynamic_Object_Function) = delete; Dynamic_Object_Function &operator=(const Dynamic_Object_Function) = delete;
Dynamic_Object_Function(Dynamic_Object_Function &) = delete; Dynamic_Object_Function(Dynamic_Object_Function &) = delete;
bool operator==(const Proxy_Function_Base &f) const noexcept override bool operator==(const Proxy_Function_Base &f) const noexcept override {
{ if (const auto *df = dynamic_cast<const Dynamic_Object_Function *>(&f)) {
if (const auto *df = dynamic_cast<const Dynamic_Object_Function *>(&f))
{
return df->m_type_name == m_type_name && (*df->m_func) == (*m_func); return df->m_type_name == m_type_name && (*df->m_func) == (*m_func);
} else { } else {
return false; return false;
@ -83,54 +72,44 @@ namespace chaiscript
bool is_attribute_function() const noexcept override { return m_is_attribute; } bool is_attribute_function() const noexcept override { return m_is_attribute; }
bool call_match(const chaiscript::Function_Params &vals, const Type_Conversions_State &t_conversions) const noexcept override bool call_match(const chaiscript::Function_Params &vals, const Type_Conversions_State &t_conversions) const noexcept override {
{ if (dynamic_object_typename_match(vals, m_type_name, m_ti, t_conversions)) {
if (dynamic_object_typename_match(vals, m_type_name, m_ti, t_conversions))
{
return m_func->call_match(vals, t_conversions); return m_func->call_match(vals, t_conversions);
} else { } else {
return false; return false;
} }
} }
std::vector<Const_Proxy_Function> get_contained_functions() const override std::vector<Const_Proxy_Function> get_contained_functions() const override { return {m_func}; }
{
return {m_func};
}
protected: protected:
Boxed_Value do_call(const chaiscript::Function_Params &params, const Type_Conversions_State &t_conversions) const override Boxed_Value do_call(const chaiscript::Function_Params &params, const Type_Conversions_State &t_conversions) const override {
{ if (dynamic_object_typename_match(params, m_type_name, m_ti, t_conversions)) {
if (dynamic_object_typename_match(params, m_type_name, m_ti, t_conversions))
{
return (*m_func)(params, t_conversions); return (*m_func)(params, t_conversions);
} else { } else {
throw exception::guard_error(); throw exception::guard_error();
} }
} }
bool compare_first_type(const Boxed_Value &bv, const Type_Conversions_State &t_conversions) const noexcept override bool compare_first_type(const Boxed_Value &bv, const Type_Conversions_State &t_conversions) const noexcept override {
{
return dynamic_object_typename_match(bv, m_type_name, m_ti, t_conversions); return dynamic_object_typename_match(bv, m_type_name, m_ti, t_conversions);
} }
private: private:
static std::vector<Type_Info> build_param_types( static std::vector<Type_Info> build_param_types(const std::vector<Type_Info> &t_inner_types, const Type_Info &t_objectti) {
const std::vector<Type_Info> &t_inner_types, const Type_Info& t_objectti)
{
std::vector<Type_Info> types(t_inner_types); std::vector<Type_Info> types(t_inner_types);
assert(types.size() > 1); assert(types.size() > 1);
//assert(types[1].bare_equal(user_type<Boxed_Value>())); // assert(types[1].bare_equal(user_type<Boxed_Value>()));
types[1] = t_objectti; types[1] = t_objectti;
return types; return types;
} }
bool dynamic_object_typename_match(const Boxed_Value &bv, const std::string &name, bool dynamic_object_typename_match(const Boxed_Value &bv,
const std::unique_ptr<Type_Info> &ti, const Type_Conversions_State &t_conversions) const noexcept const std::string &name,
{ const std::unique_ptr<Type_Info> &ti,
if (bv.get_type_info().bare_equal(m_doti)) const Type_Conversions_State &t_conversions) const noexcept {
{ if (bv.get_type_info().bare_equal(m_doti)) {
try { try {
const Dynamic_Object &d = boxed_cast<const Dynamic_Object &>(bv, &t_conversions); const Dynamic_Object &d = boxed_cast<const Dynamic_Object &>(bv, &t_conversions);
return name == "Dynamic_Object" || d.get_type_name() == name; return name == "Dynamic_Object" || d.get_type_name() == name;
@ -138,21 +117,19 @@ namespace chaiscript
return false; return false;
} }
} else { } else {
if (ti) if (ti) {
{
return bv.get_type_info().bare_equal(*ti); return bv.get_type_info().bare_equal(*ti);
} else { } else {
return false; return false;
} }
} }
} }
bool dynamic_object_typename_match(const chaiscript::Function_Params &bvs, const std::string &name, bool dynamic_object_typename_match(const chaiscript::Function_Params &bvs,
const std::unique_ptr<Type_Info> &ti, const Type_Conversions_State &t_conversions) const noexcept const std::string &name,
{ const std::unique_ptr<Type_Info> &ti,
if (!bvs.empty()) const Type_Conversions_State &t_conversions) const noexcept {
{ if (!bvs.empty()) {
return dynamic_object_typename_match(bvs[0], name, ti, t_conversions); return dynamic_object_typename_match(bvs[0], name, ti, t_conversions);
} else { } else {
return false; return false;
@ -166,47 +143,39 @@ namespace chaiscript
const bool m_is_attribute; const bool m_is_attribute;
}; };
/** /**
* A Proxy_Function implementation designed for creating a new * A Proxy_Function implementation designed for creating a new
* Dynamic_Object * Dynamic_Object
* that is automatically guarded based on the first param based on the * that is automatically guarded based on the first param based on the
* param's type name * param's type name
*/ */
class Dynamic_Object_Constructor final : public Proxy_Function_Base class Dynamic_Object_Constructor final : public Proxy_Function_Base {
{
public: public:
Dynamic_Object_Constructor( Dynamic_Object_Constructor(std::string t_type_name, const Proxy_Function &t_func)
std::string t_type_name, : Proxy_Function_Base(build_type_list(t_func->get_param_types()), t_func->get_arity() - 1)
const Proxy_Function &t_func) , m_type_name(std::move(t_type_name))
: Proxy_Function_Base(build_type_list(t_func->get_param_types()), t_func->get_arity() - 1), , m_func(t_func) {
m_type_name(std::move(t_type_name)), m_func(t_func) assert((t_func->get_arity() > 0 || t_func->get_arity() < 0)
{
assert( (t_func->get_arity() > 0 || t_func->get_arity() < 0)
&& "Programming error, Dynamic_Object_Function must have at least one parameter (this)"); && "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) static std::vector<Type_Info> build_type_list(const std::vector<Type_Info> &tl) {
{
auto begin = tl.begin(); auto begin = tl.begin();
auto end = tl.end(); auto end = tl.end();
if (begin != end) if (begin != end) {
{
++begin; ++begin;
} }
return std::vector<Type_Info>(begin, end); return std::vector<Type_Info>(begin, end);
} }
bool operator==(const Proxy_Function_Base &f) const noexcept override bool operator==(const Proxy_Function_Base &f) const noexcept override {
{ const Dynamic_Object_Constructor *dc = dynamic_cast<const Dynamic_Object_Constructor *>(&f);
const Dynamic_Object_Constructor *dc = dynamic_cast<const Dynamic_Object_Constructor*>(&f);
return (dc != nullptr) && dc->m_type_name == m_type_name && (*dc->m_func) == (*m_func); return (dc != nullptr) && dc->m_type_name == m_type_name && (*dc->m_func) == (*m_func);
} }
bool call_match(const chaiscript::Function_Params &vals, const Type_Conversions_State &t_conversions) const override bool call_match(const chaiscript::Function_Params &vals, const Type_Conversions_State &t_conversions) const override {
{
std::vector<Boxed_Value> new_vals{Boxed_Value(Dynamic_Object(m_type_name))}; std::vector<Boxed_Value> new_vals{Boxed_Value(Dynamic_Object(m_type_name))};
new_vals.insert(new_vals.end(), vals.begin(), vals.end()); new_vals.insert(new_vals.end(), vals.begin(), vals.end());
@ -214,8 +183,7 @@ namespace chaiscript
} }
protected: protected:
Boxed_Value do_call(const chaiscript::Function_Params &params, const Type_Conversions_State &t_conversions) const override Boxed_Value do_call(const chaiscript::Function_Params &params, const Type_Conversions_State &t_conversions) const override {
{
auto bv = Boxed_Value(Dynamic_Object(m_type_name), true); auto bv = Boxed_Value(Dynamic_Object(m_type_name), true);
std::vector<Boxed_Value> new_params{bv}; std::vector<Boxed_Value> new_params{bv};
new_params.insert(new_params.end(), params.begin(), params.end()); new_params.insert(new_params.end(), params.begin(), params.end());
@ -228,10 +196,8 @@ namespace chaiscript
private: private:
const std::string m_type_name; const std::string m_type_name;
const Proxy_Function m_func; const Proxy_Function m_func;
}; };
} } // namespace detail
} } // namespace dispatch
} } // namespace chaiscript
#endif #endif

View File

@ -7,7 +7,6 @@
// This is an open source non-commercial project. Dear PVS-Studio, please check it. // This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com // PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_EXCEPTION_SPECIFICATION_HPP_ #ifndef CHAISCRIPT_EXCEPTION_SPECIFICATION_HPP_
#define CHAISCRIPT_EXCEPTION_SPECIFICATION_HPP_ #define CHAISCRIPT_EXCEPTION_SPECIFICATION_HPP_
@ -17,39 +16,28 @@
#include "boxed_cast.hpp" #include "boxed_cast.hpp"
namespace chaiscript { namespace chaiscript {
class Boxed_Value; namespace detail {
namespace exception { struct Exception_Handler_Base {
class bad_boxed_cast;
} // namespace exception
} // namespace chaiscript
namespace chaiscript
{
namespace detail
{
struct Exception_Handler_Base
{
virtual void handle(const Boxed_Value &bv, const Dispatch_Engine &t_engine) = 0; virtual void handle(const Boxed_Value &bv, const Dispatch_Engine &t_engine) = 0;
virtual ~Exception_Handler_Base() = default; virtual ~Exception_Handler_Base() = default;
protected: protected:
template<typename T> template<typename T>
static void throw_type(const Boxed_Value &bv, const Dispatch_Engine &t_engine) static void throw_type(const Boxed_Value &bv, const Dispatch_Engine &t_engine) {
{ try {
try { T t = t_engine.boxed_cast<T>(bv); throw t; } catch (const chaiscript::exception::bad_boxed_cast &) {} T t = t_engine.boxed_cast<T>(bv);
throw t;
} catch (const chaiscript::exception::bad_boxed_cast &) {
}
} }
}; };
template<typename ... T> template<typename... T>
struct Exception_Handler_Impl : Exception_Handler_Base struct Exception_Handler_Impl : Exception_Handler_Base {
{ void handle(const Boxed_Value &bv, const Dispatch_Engine &t_engine) override { (throw_type<T>(bv, t_engine), ...); }
void handle(const Boxed_Value &bv, const Dispatch_Engine &t_engine) override
{
(throw_type<T>(bv, t_engine), ...);
}
}; };
} } // namespace detail
/// \brief Used in the automatic unboxing of exceptions thrown during script evaluation /// \brief Used in the automatic unboxing of exceptions thrown during script evaluation
/// ///
@ -61,7 +49,8 @@ namespace chaiscript
/// chaiscript::ChaiScript chai; /// chaiscript::ChaiScript chai;
/// ///
/// try { /// try {
/// chai.eval("throw(runtime_error(\"error\"))", chaiscript::exception_specification<int, double, float, const std::string &, const std::exception &>()); /// chai.eval("throw(runtime_error(\"error\"))", chaiscript::exception_specification<int, double, float, const std::string &, const
/// std::exception &>());
/// } catch (const double e) { /// } catch (const double e) {
/// } catch (int) { /// } catch (int) {
/// } catch (float) { /// } catch (float) {
@ -105,13 +94,10 @@ namespace chaiscript
/// \brief creates a chaiscript::Exception_Handler which handles one type of exception unboxing /// \brief creates a chaiscript::Exception_Handler which handles one type of exception unboxing
/// \sa \ref exceptions /// \sa \ref exceptions
template<typename ... T> template<typename... T>
Exception_Handler exception_specification() Exception_Handler exception_specification() {
{
return std::make_shared<detail::Exception_Handler_Impl<T...>>(); return std::make_shared<detail::Exception_Handler_Impl<T...>>();
} }
} } // namespace chaiscript
#endif #endif

View File

@ -7,7 +7,6 @@
// This is an open source non-commercial project. Dear PVS-Studio, please check it. // This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com // PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_FUNCTION_CALL_HPP_ #ifndef CHAISCRIPT_FUNCTION_CALL_HPP_
#define CHAISCRIPT_FUNCTION_CALL_HPP_ #define CHAISCRIPT_FUNCTION_CALL_HPP_
@ -20,25 +19,22 @@
#include "proxy_functions.hpp" #include "proxy_functions.hpp"
namespace chaiscript { namespace chaiscript {
class Boxed_Value; class Boxed_Value;
class Type_Conversions_State; class Type_Conversions_State;
namespace detail { namespace detail {
template <typename T> struct Cast_Helper; template<typename T>
} // namespace detail struct Cast_Helper;
} // namespace detail
} // namespace chaiscript } // namespace chaiscript
namespace chaiscript namespace chaiscript {
{ namespace dispatch {
namespace dispatch namespace detail {
{ template<typename Ret, typename... Param>
namespace detail constexpr auto arity(Ret (*)(Param...)) noexcept {
{
template<typename Ret, typename ... Param>
constexpr auto arity(Ret (*)(Param...)) noexcept
{
return sizeof...(Param); return sizeof...(Param);
} }
} } // namespace detail
/// Build a function caller that knows how to dispatch on a set of functions /// Build a function caller that knows how to dispatch on a set of functions
/// example: /// example:
@ -47,10 +43,8 @@ namespace chaiscript
/// \returns A std::function object for dispatching /// \returns A std::function object for dispatching
/// \param[in] funcs the set of functions to dispatch on. /// \param[in] funcs the set of functions to dispatch on.
template<typename FunctionType> template<typename FunctionType>
std::function<FunctionType> functor(const std::vector<Const_Proxy_Function> &funcs, const Type_Conversions_State *t_conversions) std::function<FunctionType> functor(const std::vector<Const_Proxy_Function> &funcs, const Type_Conversions_State *t_conversions) {
{ const bool has_arity_match = std::any_of(funcs.begin(), funcs.end(), [](const Const_Proxy_Function &f) {
const bool has_arity_match = std::any_of(funcs.begin(), funcs.end(),
[](const Const_Proxy_Function &f) {
return f->get_arity() == -1 || size_t(f->get_arity()) == detail::arity(static_cast<FunctionType *>(nullptr)); return f->get_arity() == -1 || size_t(f->get_arity()) == detail::arity(static_cast<FunctionType *>(nullptr));
}); });
@ -58,7 +52,7 @@ namespace chaiscript
throw exception::bad_boxed_cast(user_type<Const_Proxy_Function>(), typeid(std::function<FunctionType>)); throw exception::bad_boxed_cast(user_type<Const_Proxy_Function>(), typeid(std::function<FunctionType>));
} }
FunctionType *p=nullptr; FunctionType *p = nullptr;
return detail::build_function_caller_helper(p, funcs, t_conversions); return detail::build_function_caller_helper(p, funcs, t_conversions);
} }
@ -74,29 +68,24 @@ namespace chaiscript
/// \returns A std::function object for dispatching /// \returns A std::function object for dispatching
/// \param[in] func A function to execute. /// \param[in] func A function to execute.
template<typename FunctionType> template<typename FunctionType>
std::function<FunctionType> functor(Const_Proxy_Function func, const Type_Conversions_State *t_conversions) std::function<FunctionType> functor(Const_Proxy_Function func, const Type_Conversions_State *t_conversions) {
{
return functor<FunctionType>(std::vector<Const_Proxy_Function>({std::move(func)}), t_conversions); return functor<FunctionType>(std::vector<Const_Proxy_Function>({std::move(func)}), t_conversions);
} }
/// Helper for automatically unboxing a Boxed_Value that contains a function object /// Helper for automatically unboxing a Boxed_Value that contains a function object
/// and creating a typesafe C++ function caller from it. /// and creating a typesafe C++ function caller from it.
template<typename FunctionType> template<typename FunctionType>
std::function<FunctionType> functor(const Boxed_Value &bv, const Type_Conversions_State *t_conversions) std::function<FunctionType> functor(const Boxed_Value &bv, const Type_Conversions_State *t_conversions) {
{ return functor<FunctionType>(boxed_cast<Const_Proxy_Function>(bv, t_conversions), t_conversions);
return functor<FunctionType>(boxed_cast<Const_Proxy_Function >(bv, t_conversions), t_conversions);
}
} }
} // namespace dispatch
namespace detail{ 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> template<typename Signature>
struct Cast_Helper<const std::function<Signature> &> struct Cast_Helper<const std::function<Signature> &> {
{ static std::function<Signature> cast(const Boxed_Value &ob, const Type_Conversions_State *t_conversions) {
static std::function<Signature> cast(const Boxed_Value &ob, const Type_Conversions_State *t_conversions) if (ob.get_type_info().bare_equal(user_type<Const_Proxy_Function>())) {
{
if (ob.get_type_info().bare_equal(user_type<Const_Proxy_Function>()))
{
return dispatch::functor<Signature>(ob, t_conversions); return dispatch::functor<Signature>(ob, t_conversions);
} else { } else {
return Cast_Helper_Inner<const std::function<Signature> &>::cast(ob, t_conversions); return Cast_Helper_Inner<const std::function<Signature> &>::cast(ob, t_conversions);
@ -106,35 +95,28 @@ namespace chaiscript
/// Cast helper to handle automatic casting to std::function /// Cast helper to handle automatic casting to std::function
template<typename Signature> template<typename Signature>
struct Cast_Helper<std::function<Signature> > struct Cast_Helper<std::function<Signature>> {
{ static std::function<Signature> cast(const Boxed_Value &ob, const Type_Conversions_State *t_conversions) {
static std::function<Signature> cast(const Boxed_Value &ob, const Type_Conversions_State *t_conversions) if (ob.get_type_info().bare_equal(user_type<Const_Proxy_Function>())) {
{
if (ob.get_type_info().bare_equal(user_type<Const_Proxy_Function>()))
{
return dispatch::functor<Signature>(ob, t_conversions); return dispatch::functor<Signature>(ob, t_conversions);
} else { } else {
return Cast_Helper_Inner<std::function<Signature> >::cast(ob, t_conversions); return Cast_Helper_Inner<std::function<Signature>>::cast(ob, t_conversions);
} }
} }
}; };
/// Cast helper to handle automatic casting to const std::function /// Cast helper to handle automatic casting to const std::function
template<typename Signature> template<typename Signature>
struct Cast_Helper<const std::function<Signature> > struct Cast_Helper<const std::function<Signature>> {
{ static std::function<Signature> cast(const Boxed_Value &ob, const Type_Conversions_State *t_conversions) {
static std::function<Signature> cast(const Boxed_Value &ob, const Type_Conversions_State *t_conversions) if (ob.get_type_info().bare_equal(user_type<Const_Proxy_Function>())) {
{
if (ob.get_type_info().bare_equal(user_type<Const_Proxy_Function>()))
{
return dispatch::functor<Signature>(ob, t_conversions); return dispatch::functor<Signature>(ob, t_conversions);
} else { } else {
return Cast_Helper_Inner<const std::function<Signature> >::cast(ob, t_conversions); return Cast_Helper_Inner<const std::function<Signature>>::cast(ob, t_conversions);
} }
} }
}; };
} } // namespace detail
} } // namespace chaiscript
#endif #endif

View File

@ -7,7 +7,6 @@
// This is an open source non-commercial project. Dear PVS-Studio, please check it. // This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com // PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_FUNCTION_CALL_DETAIL_HPP_ #ifndef CHAISCRIPT_FUNCTION_CALL_DETAIL_HPP_
#define CHAISCRIPT_FUNCTION_CALL_DETAIL_HPP_ #define CHAISCRIPT_FUNCTION_CALL_DETAIL_HPP_
@ -20,27 +19,19 @@
#include "boxed_cast.hpp" #include "boxed_cast.hpp"
#include "boxed_number.hpp" #include "boxed_number.hpp"
#include "boxed_value.hpp" #include "boxed_value.hpp"
#include "type_conversions.hpp"
#include "proxy_functions.hpp" #include "proxy_functions.hpp"
#include "type_conversions.hpp"
namespace chaiscript namespace chaiscript::dispatch::detail {
{
namespace dispatch
{
namespace detail
{
/// used internally for unwrapping a function call's types /// used internally for unwrapping a function call's types
template<typename Ret, typename ... Param> template<typename Ret, typename... Param>
struct Build_Function_Caller_Helper 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 Type_Conversions *t_conversions)
: m_funcs(std::move(t_funcs)), : m_funcs(std::move(t_funcs))
m_conversions(t_conversions) , m_conversions(t_conversions) {
{
} }
Ret call(const chaiscript::Function_Params &params, const Type_Conversions_State &t_state) Ret call(const chaiscript::Function_Params &params, const Type_Conversions_State &t_state) {
{
if constexpr (std::is_arithmetic_v<Ret> && !std::is_same_v<std::remove_cv_t<std::remove_reference_t<Ret>>, bool>) { if constexpr (std::is_arithmetic_v<Ret> && !std::is_same_v<std::remove_cv_t<std::remove_reference_t<Ret>>, bool>) {
return Boxed_Number(dispatch::dispatch(m_funcs, params, t_state)).get_as<Ret>(); return Boxed_Number(dispatch::dispatch(m_funcs, params, t_state)).get_as<Ret>();
} else if constexpr (std::is_same_v<void, Ret>) { } else if constexpr (std::is_same_v<void, Ret>) {
@ -50,9 +41,8 @@ namespace chaiscript
} }
} }
template<typename ... P> template<typename... P>
Ret operator()(P&& ... param) Ret operator()(P &&...param) {
{
std::array<Boxed_Value, sizeof...(P)> params{box<P>(std::forward<P>(param))...}; std::array<Boxed_Value, sizeof...(P)> params{box<P>(std::forward<P>(param))...};
if (m_conversions) { if (m_conversions) {
@ -63,10 +53,8 @@ namespace chaiscript
Type_Conversions_State state(conv, conv.conversion_saves()); Type_Conversions_State state(conv, conv.conversion_saves());
return call(chaiscript::Function_Params{params}, state); return call(chaiscript::Function_Params{params}, state);
} }
} }
template<typename P, typename Q> template<typename P, typename Q>
static Boxed_Value box(Q &&q) { static Boxed_Value box(Q &&q) {
if constexpr (std::is_same_v<chaiscript::Boxed_Value, std::decay_t<Q>>) { if constexpr (std::is_same_v<chaiscript::Boxed_Value, std::decay_t<Q>>) {
@ -78,17 +66,14 @@ namespace chaiscript
} }
} }
std::vector<Const_Proxy_Function> m_funcs; std::vector<Const_Proxy_Function> m_funcs;
const Type_Conversions *m_conversions; const Type_Conversions *m_conversions;
}; };
/// \todo what happens if t_conversions is deleted out from under us?! /// \todo what happens if t_conversions is deleted out from under us?!
template<typename Ret, typename ... Params> 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_State *t_conversions) std::function<Ret(Params...)>
{ build_function_caller_helper(Ret(Params...), const std::vector<Const_Proxy_Function> &funcs, const Type_Conversions_State *t_conversions) {
/* /*
if (funcs.size() == 1) if (funcs.size() == 1)
{ {
@ -103,13 +88,10 @@ namespace chaiscript
// looks like this either wasn't a Proxy_Function_Impl or the types didn't match // looks like this either wasn't a Proxy_Function_Impl or the types didn't match
// we cannot make any other guesses or assumptions really, so continuing // 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->get():nullptr)); return std::function<Ret(Params...)>(Build_Function_Caller_Helper<Ret, Params...>(funcs, t_conversions ? t_conversions->get() : nullptr));
} }
} } // namespace chaiscript::dispatch::detail
}
}
#endif #endif

View File

@ -7,66 +7,48 @@
// This is an open source non-commercial project. Dear PVS-Studio, please check it. // This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com // PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_FUNCTION_PARAMS_HPP #ifndef CHAISCRIPT_FUNCTION_PARAMS_HPP
#define CHAISCRIPT_FUNCTION_PARAMS_HPP #define CHAISCRIPT_FUNCTION_PARAMS_HPP
#include "boxed_value.hpp" #include "boxed_value.hpp"
namespace chaiscript { namespace chaiscript {
class Function_Params {
class Function_Params
{
public: public:
constexpr Function_Params(const Boxed_Value * const t_begin, const Boxed_Value * const t_end) constexpr Function_Params(const Boxed_Value *const t_begin, const Boxed_Value *const t_end)
: m_begin(t_begin), m_end(t_end) : m_begin(t_begin)
{ , m_end(t_end) {
} }
explicit Function_Params(const Boxed_Value &bv) explicit Function_Params(const Boxed_Value &bv)
: m_begin(&bv), m_end(m_begin + 1) : m_begin(&bv)
{ , m_end(m_begin + 1) {
} }
explicit Function_Params(const std::vector<Boxed_Value> &vec) explicit Function_Params(const std::vector<Boxed_Value> &vec)
: m_begin(vec.empty() ? nullptr : &vec.front()), m_end(vec.empty() ? nullptr : &vec.front() + vec.size()) : m_begin(vec.empty() ? nullptr : &vec.front())
{ , m_end(vec.empty() ? nullptr : &vec.front() + vec.size()) {
} }
template<size_t Size> template<size_t Size>
constexpr explicit Function_Params(const std::array<Boxed_Value, Size> &a) constexpr explicit Function_Params(const std::array<Boxed_Value, Size> &a)
: m_begin(&a.front()), m_end(&a.front() + Size) : m_begin(&a.front())
{ , m_end(&a.front() + Size) {
} }
[[nodiscard]] constexpr const Boxed_Value &operator[](const std::size_t t_i) const noexcept { [[nodiscard]] constexpr const Boxed_Value &operator[](const std::size_t t_i) const noexcept { return m_begin[t_i]; }
return m_begin[t_i];
}
[[nodiscard]] constexpr const Boxed_Value *begin() const noexcept { [[nodiscard]] constexpr const Boxed_Value *begin() const noexcept { return m_begin; }
return m_begin;
}
[[nodiscard]] constexpr const Boxed_Value &front() const noexcept { [[nodiscard]] constexpr const Boxed_Value &front() const noexcept { return *m_begin; }
return *m_begin;
}
[[nodiscard]] constexpr const Boxed_Value *end() const noexcept { [[nodiscard]] constexpr const Boxed_Value *end() const noexcept { return m_end; }
return m_end;
}
[[nodiscard]] constexpr std::size_t size() const noexcept { [[nodiscard]] constexpr std::size_t size() const noexcept { return std::size_t(m_end - m_begin); }
return std::size_t(m_end - m_begin);
}
[[nodiscard]] std::vector<Boxed_Value> to_vector() const { [[nodiscard]] std::vector<Boxed_Value> to_vector() const { return std::vector<Boxed_Value>{m_begin, m_end}; }
return std::vector<Boxed_Value>{m_begin, m_end};
}
[[nodiscard]] constexpr bool empty() const noexcept { [[nodiscard]] constexpr bool empty() const noexcept { return m_begin == m_end; }
return m_begin == m_end;
}
private: private:
const Boxed_Value *m_begin = nullptr; const Boxed_Value *m_begin = nullptr;
@ -76,10 +58,10 @@ namespace chaiscript {
// Constructor specialization for array of size 0 // Constructor specialization for array of size 0
template<> template<>
constexpr Function_Params::Function_Params(const std::array<Boxed_Value, size_t{0}> & /* a */) constexpr Function_Params::Function_Params(const std::array<Boxed_Value, size_t{0}> & /* a */)
: m_begin(nullptr), m_end(nullptr) : m_begin(nullptr)
{ , m_end(nullptr) {
} }
} } // namespace chaiscript
#endif #endif

View File

@ -4,142 +4,146 @@
#include <type_traits> #include <type_traits>
namespace chaiscript::dispatch::detail { namespace chaiscript::dispatch::detail {
template<typename... Param>
struct Function_Params {
};
template<typename... Param> template<typename Ret, typename Params, bool IsNoExcept = false, bool IsMember = false, bool IsMemberObject = false, bool IsObject = false>
struct Function_Params struct Function_Signature {
{
};
template<typename Ret, typename Params, bool IsNoExcept = false, bool IsMember = false, bool IsMemberObject = false, bool IsObject = false>
struct Function_Signature
{
using Param_Types = Params; using Param_Types = Params;
using Return_Type = Ret; using Return_Type = Ret;
constexpr static const bool is_object = IsObject; constexpr static const bool is_object = IsObject;
constexpr static const bool is_member_object = IsMemberObject; constexpr static const bool is_member_object = IsMemberObject;
constexpr static const bool is_noexcept = IsNoExcept; constexpr static const bool is_noexcept = IsNoExcept;
template<typename T> template<typename T>
constexpr Function_Signature(T &&) noexcept {} constexpr Function_Signature(T &&) noexcept {
}
constexpr Function_Signature() noexcept = default; constexpr Function_Signature() noexcept = default;
}; };
// Free functions // Free functions
template<typename Ret, typename... Param> template<typename Ret, typename... Param>
Function_Signature(Ret (*f)(Param...))->Function_Signature<Ret, Function_Params<Param...>>; Function_Signature(Ret (*f)(Param...)) -> Function_Signature<Ret, Function_Params<Param...>>;
template<typename Ret, typename... Param> template<typename Ret, typename... Param>
Function_Signature(Ret (*f)(Param...) noexcept)->Function_Signature<Ret, Function_Params<Param...>, true>; Function_Signature(Ret (*f)(Param...) noexcept) -> Function_Signature<Ret, Function_Params<Param...>, true>;
// no reference specifier // no reference specifier
template<typename Ret, typename Class, typename... Param> template<typename Ret, typename Class, typename... Param>
Function_Signature(Ret (Class::*f)(Param...) volatile)->Function_Signature<Ret, Function_Params<volatile Class &, Param...>, false, true>; Function_Signature(Ret (Class::*f)(Param...) volatile) -> Function_Signature<Ret, Function_Params<volatile Class &, Param...>, false, true>;
template<typename Ret, typename Class, typename... Param> template<typename Ret, typename Class, typename... Param>
Function_Signature(Ret (Class::*f)(Param...) volatile noexcept)->Function_Signature<Ret, Function_Params<volatile Class &, Param...>, true, true>; Function_Signature(Ret (Class::*f)(Param...) volatile noexcept)
-> Function_Signature<Ret, Function_Params<volatile Class &, Param...>, true, true>;
template<typename Ret, typename Class, typename... Param> template<typename Ret, typename Class, typename... Param>
Function_Signature(Ret (Class::*f)(Param...) volatile const)->Function_Signature<Ret, Function_Params<volatile const Class &, Param...>, false, true>; Function_Signature(Ret (Class::*f)(Param...) volatile const)
-> Function_Signature<Ret, Function_Params<volatile const Class &, Param...>, false, true>;
template<typename Ret, typename Class, typename... Param> template<typename Ret, typename Class, typename... Param>
Function_Signature(Ret (Class::*f)(Param...) volatile const noexcept)->Function_Signature<Ret, Function_Params<volatile const Class &, Param...>, true, true>; Function_Signature(Ret (Class::*f)(Param...) volatile const noexcept)
-> Function_Signature<Ret, Function_Params<volatile const Class &, Param...>, true, true>;
template<typename Ret, typename Class, typename... Param> template<typename Ret, typename Class, typename... Param>
Function_Signature(Ret (Class::*f)(Param...))->Function_Signature<Ret, Function_Params<Class &, Param...>, false, true>; Function_Signature(Ret (Class::*f)(Param...)) -> Function_Signature<Ret, Function_Params<Class &, Param...>, false, true>;
template<typename Ret, typename Class, typename... Param> template<typename Ret, typename Class, typename... Param>
Function_Signature(Ret (Class::*f)(Param...) noexcept)->Function_Signature<Ret, Function_Params<Class &, Param...>, true, true>; Function_Signature(Ret (Class::*f)(Param...) noexcept) -> Function_Signature<Ret, Function_Params<Class &, Param...>, true, true>;
template<typename Ret, typename Class, typename... Param> template<typename Ret, typename Class, typename... Param>
Function_Signature(Ret (Class::*f)(Param...) const)->Function_Signature<Ret, Function_Params<const Class &, Param...>, false, true>; Function_Signature(Ret (Class::*f)(Param...) const) -> Function_Signature<Ret, Function_Params<const Class &, Param...>, false, true>;
template<typename Ret, typename Class, typename... Param> template<typename Ret, typename Class, typename... Param>
Function_Signature(Ret (Class::*f)(Param...) const noexcept)->Function_Signature<Ret, Function_Params<const Class &, Param...>, true, true>; Function_Signature(Ret (Class::*f)(Param...) const noexcept) -> Function_Signature<Ret, Function_Params<const Class &, Param...>, true, true>;
// & reference specifier // & reference specifier
template<typename Ret, typename Class, typename... Param> template<typename Ret, typename Class, typename... Param>
Function_Signature(Ret (Class::*f)(Param...) volatile &)->Function_Signature<Ret, Function_Params<volatile Class &, Param...>, false, true>; Function_Signature(Ret (Class::*f)(Param...) volatile &) -> Function_Signature<Ret, Function_Params<volatile Class &, Param...>, false, true>;
template<typename Ret, typename Class, typename... Param> template<typename Ret, typename Class, typename... Param>
Function_Signature(Ret (Class::*f)(Param...) volatile &noexcept)->Function_Signature<Ret, Function_Params<volatile Class &, Param...>, true, true>; Function_Signature(Ret (Class::*f)(Param...) volatile &noexcept)
-> Function_Signature<Ret, Function_Params<volatile Class &, Param...>, true, true>;
template<typename Ret, typename Class, typename... Param> template<typename Ret, typename Class, typename... Param>
Function_Signature(Ret (Class::*f)(Param...) volatile const &)->Function_Signature<Ret, Function_Params<volatile const Class &, Param...>, false, true>; Function_Signature(Ret (Class::*f)(Param...) volatile const &)
-> Function_Signature<Ret, Function_Params<volatile const Class &, Param...>, false, true>;
template<typename Ret, typename Class, typename... Param> template<typename Ret, typename Class, typename... Param>
Function_Signature(Ret (Class::*f)(Param...) volatile const &noexcept)->Function_Signature<Ret, Function_Params<volatile const Class &, Param...>, true, true>; Function_Signature(Ret (Class::*f)(Param...) volatile const &noexcept)
-> Function_Signature<Ret, Function_Params<volatile const Class &, Param...>, true, true>;
template<typename Ret, typename Class, typename... Param> template<typename Ret, typename Class, typename... Param>
Function_Signature(Ret (Class::*f)(Param...) &)->Function_Signature<Ret, Function_Params<Class &, Param...>, false, true>; Function_Signature(Ret (Class::*f)(Param...) &) -> Function_Signature<Ret, Function_Params<Class &, Param...>, false, true>;
template<typename Ret, typename Class, typename... Param> template<typename Ret, typename Class, typename... Param>
Function_Signature(Ret (Class::*f)(Param...) & noexcept)->Function_Signature<Ret, Function_Params<Class &, Param...>, true, true>; Function_Signature(Ret (Class::*f)(Param...) &noexcept) -> Function_Signature<Ret, Function_Params<Class &, Param...>, true, true>;
template<typename Ret, typename Class, typename... Param> template<typename Ret, typename Class, typename... Param>
Function_Signature(Ret (Class::*f)(Param...) const &)->Function_Signature<Ret, Function_Params<const Class &, Param...>, false, true>; Function_Signature(Ret (Class::*f)(Param...) const &) -> Function_Signature<Ret, Function_Params<const Class &, Param...>, false, true>;
template<typename Ret, typename Class, typename... Param> template<typename Ret, typename Class, typename... Param>
Function_Signature(Ret (Class::*f)(Param...) const &noexcept)->Function_Signature<Ret, Function_Params<const Class &, Param...>, true, true>; Function_Signature(Ret (Class::*f)(Param...) const &noexcept) -> Function_Signature<Ret, Function_Params<const Class &, Param...>, true, true>;
// && reference specifier // && reference specifier
template<typename Ret, typename Class, typename... Param> template<typename Ret, typename Class, typename... Param>
Function_Signature(Ret (Class::*f)(Param...) volatile &&)->Function_Signature<Ret, Function_Params<volatile Class &&, Param...>, false, true>; Function_Signature(Ret (Class::*f)(Param...) volatile &&) -> Function_Signature<Ret, Function_Params<volatile Class &&, Param...>, false, true>;
template<typename Ret, typename Class, typename... Param> template<typename Ret, typename Class, typename... Param>
Function_Signature(Ret (Class::*f)(Param...) volatile &&noexcept)->Function_Signature<Ret, Function_Params<volatile Class &&, Param...>, true, true>; Function_Signature(Ret (Class::*f)(Param...) volatile &&noexcept)
-> Function_Signature<Ret, Function_Params<volatile Class &&, Param...>, true, true>;
template<typename Ret, typename Class, typename... Param> template<typename Ret, typename Class, typename... Param>
Function_Signature(Ret (Class::*f)(Param...) volatile const &&)->Function_Signature<Ret, Function_Params<volatile const Class &&, Param...>, false, true>; Function_Signature(Ret (Class::*f)(Param...) volatile const &&)
-> Function_Signature<Ret, Function_Params<volatile const Class &&, Param...>, false, true>;
template<typename Ret, typename Class, typename... Param> template<typename Ret, typename Class, typename... Param>
Function_Signature(Ret (Class::*f)(Param...) volatile const &&noexcept)->Function_Signature<Ret, Function_Params<volatile const Class &&, Param...>, true, true>; Function_Signature(Ret (Class::*f)(Param...) volatile const &&noexcept)
-> Function_Signature<Ret, Function_Params<volatile const Class &&, Param...>, true, true>;
template<typename Ret, typename Class, typename... Param> template<typename Ret, typename Class, typename... Param>
Function_Signature(Ret (Class::*f)(Param...) &&)->Function_Signature<Ret, Function_Params<Class &&, Param...>, false, true>; Function_Signature(Ret (Class::*f)(Param...) &&) -> Function_Signature<Ret, Function_Params<Class &&, Param...>, false, true>;
template<typename Ret, typename Class, typename... Param> template<typename Ret, typename Class, typename... Param>
Function_Signature(Ret (Class::*f)(Param...) && noexcept)->Function_Signature<Ret, Function_Params<Class &&, Param...>, true, true>; Function_Signature(Ret (Class::*f)(Param...) &&noexcept) -> Function_Signature<Ret, Function_Params<Class &&, Param...>, true, true>;
template<typename Ret, typename Class, typename... Param> template<typename Ret, typename Class, typename... Param>
Function_Signature(Ret (Class::*f)(Param...) const &&)->Function_Signature<Ret, Function_Params<const Class &&, Param...>, false, true>; Function_Signature(Ret (Class::*f)(Param...) const &&) -> Function_Signature<Ret, Function_Params<const Class &&, Param...>, false, true>;
template<typename Ret, typename Class, typename... Param> template<typename Ret, typename Class, typename... Param>
Function_Signature(Ret (Class::*f)(Param...) const &&noexcept)->Function_Signature<Ret, Function_Params<const Class &&, Param...>, true, true>; Function_Signature(Ret (Class::*f)(Param...) const &&noexcept)
-> Function_Signature<Ret, Function_Params<const Class &&, Param...>, true, true>;
template<typename Ret, typename Class> template<typename Ret, typename Class>
Function_Signature(Ret Class::*f)->Function_Signature<Ret, Function_Params<Class &>, true, true, true>; Function_Signature(Ret Class::*f) -> Function_Signature<Ret, Function_Params<Class &>, true, true, true>;
// primary template handles types that have no nested ::type member: // primary template handles types that have no nested ::type member:
template<class, class = std::void_t<>> template<class, class = std::void_t<>>
struct has_call_operator : std::false_type struct has_call_operator : std::false_type {
{ };
};
// specialization recognizes types that do have a nested ::type member: // specialization recognizes types that do have a nested ::type member:
template<class T> template<class T>
struct has_call_operator<T, std::void_t<decltype(&T::operator())>> : std::true_type struct has_call_operator<T, std::void_t<decltype(&T::operator())>> : std::true_type {
{ };
};
template<typename Func> template<typename Func>
auto function_signature(const Func &f) auto function_signature(const Func &f) {
{
if constexpr (has_call_operator<Func>::value) { if constexpr (has_call_operator<Func>::value) {
return Function_Signature< return Function_Signature<typename decltype(Function_Signature{&std::decay_t<Func>::operator()})::Return_Type,
typename decltype(Function_Signature{ &std::decay_t<Func>::operator() })::Return_Type, typename decltype(Function_Signature{&std::decay_t<Func>::operator()})::Param_Types,
typename decltype(Function_Signature{ &std::decay_t<Func>::operator() })::Param_Types, decltype(Function_Signature{&std::decay_t<Func>::operator()})::is_noexcept,
decltype(Function_Signature{ &std::decay_t<Func>::operator() })::is_noexcept,
false, false,
false, false,
true>{}; true>{};
} else { } else {
return Function_Signature{ f }; return Function_Signature{f};
}
} }
}
}// namespace chaiscript::dispatch::detail } // namespace chaiscript::dispatch::detail
#endif #endif

View File

@ -7,7 +7,6 @@
// This is an open source non-commercial project. Dear PVS-Studio, please check it. // This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com // PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_HANDLE_RETURN_HPP_ #ifndef CHAISCRIPT_HANDLE_RETURN_HPP_
#define CHAISCRIPT_HANDLE_RETURN_HPP_ #define CHAISCRIPT_HANDLE_RETURN_HPP_
@ -19,254 +18,178 @@
#include "boxed_value.hpp" #include "boxed_value.hpp"
namespace chaiscript { namespace chaiscript {
class Boxed_Number; class Boxed_Number;
} // namespace chaiscript } // namespace chaiscript
namespace chaiscript namespace chaiscript {
{ namespace dispatch {
namespace dispatch template<class T, class U>
{ class Proxy_Function_Callable_Impl;
template<class T, class U> class Proxy_Function_Callable_Impl; template<class T>
template<class T> class Assignable_Proxy_Function_Impl; class Assignable_Proxy_Function_Impl;
namespace detail namespace detail {
{
/// Used internally for handling a return value from a Proxy_Function call /// Used internally for handling a return value from a Proxy_Function call
template<typename Ret> template<typename Ret>
struct Handle_Return struct Handle_Return {
{ template<typename T, typename = typename std::enable_if_t<std::is_trivial_v<typename std::decay_t<T>>>>
template<typename T, static Boxed_Value handle(T r) {
typename = typename std::enable_if_t<std::is_trivial_v<typename std::decay_t<T>>>>
static Boxed_Value handle(T r)
{
return Boxed_Value(std::move(r), true); return Boxed_Value(std::move(r), true);
} }
template<typename T, template<typename T, typename = typename std::enable_if_t<!(std::is_trivial_v<typename std::decay_t<T>>)>>
typename = typename std::enable_if_t<!(std::is_trivial_v<typename std::decay_t<T>>)>> static Boxed_Value handle(T &&r) {
static Boxed_Value handle(T &&r)
{
return Boxed_Value(std::make_shared<T>(std::forward<T>(r)), true); return Boxed_Value(std::make_shared<T>(std::forward<T>(r)), true);
} }
}; };
template<typename Ret> template<typename Ret>
struct Handle_Return<const std::function<Ret> &> struct Handle_Return<const std::function<Ret> &> {
{
static Boxed_Value handle(const std::function<Ret> &f) { static Boxed_Value handle(const std::function<Ret> &f) {
return Boxed_Value( return Boxed_Value(
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Ret, std::function<Ret>>>(f) chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Ret, std::function<Ret>>>(f));
);
} }
}; };
template<typename Ret> template<typename Ret>
struct Handle_Return<std::function<Ret>> : Handle_Return<const std::function<Ret> &> struct Handle_Return<std::function<Ret>> : Handle_Return<const std::function<Ret> &> {
{
}; };
template<typename Ret> template<typename Ret>
struct Handle_Return<const std::shared_ptr<std::function<Ret>>> struct Handle_Return<const std::shared_ptr<std::function<Ret>>> {
{
static Boxed_Value handle(const std::shared_ptr<std::function<Ret>> &f) { static Boxed_Value handle(const std::shared_ptr<std::function<Ret>> &f) {
return Boxed_Value( return Boxed_Value(
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Assignable_Proxy_Function_Impl<Ret>>(std::ref(*f),f) chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Assignable_Proxy_Function_Impl<Ret>>(std::ref(*f), f));
);
} }
}; };
template<typename Ret> template<typename Ret>
struct Handle_Return<const std::shared_ptr<std::function<Ret>> &> : Handle_Return<const std::shared_ptr<std::function<Ret>>> struct Handle_Return<const std::shared_ptr<std::function<Ret>> &> : Handle_Return<const std::shared_ptr<std::function<Ret>>> {
{
}; };
template<typename Ret> template<typename Ret>
struct Handle_Return<std::shared_ptr<std::function<Ret>>> : Handle_Return<const std::shared_ptr<std::function<Ret>>> struct Handle_Return<std::shared_ptr<std::function<Ret>>> : Handle_Return<const std::shared_ptr<std::function<Ret>>> {
{
}; };
template<typename Ret> template<typename Ret>
struct Handle_Return<std::function<Ret> &> struct Handle_Return<std::function<Ret> &> {
{
static Boxed_Value handle(std::function<Ret> &f) { static Boxed_Value handle(std::function<Ret> &f) {
return Boxed_Value( return Boxed_Value(chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Assignable_Proxy_Function_Impl<Ret>>(
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Assignable_Proxy_Function_Impl<Ret>>(std::ref(f), std::ref(f), std::shared_ptr<std::function<Ret>>()));
std::shared_ptr<std::function<Ret>>())
);
} }
static Boxed_Value handle(const std::function<Ret> &f) { static Boxed_Value handle(const std::function<Ret> &f) {
return Boxed_Value( return Boxed_Value(
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Ret, std::function<Ret>>>(f) chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Ret, std::function<Ret>>>(f));
);
} }
}; };
template<typename Ret> template<typename Ret>
struct Handle_Return<Ret *&> struct Handle_Return<Ret *&> {
{ static Boxed_Value handle(Ret *p) { return Boxed_Value(p, true); }
static Boxed_Value handle(Ret *p)
{
return Boxed_Value(p, true);
}
}; };
template<typename Ret> template<typename Ret>
struct Handle_Return<const Ret *&> struct Handle_Return<const Ret *&> {
{ static Boxed_Value handle(const Ret *p) { return Boxed_Value(p, true); }
static Boxed_Value handle(const Ret *p)
{
return Boxed_Value(p, true);
}
}; };
template<typename Ret> template<typename Ret>
struct Handle_Return<Ret *> struct Handle_Return<Ret *> {
{ static Boxed_Value handle(Ret *p) { return Boxed_Value(p, true); }
static Boxed_Value handle(Ret *p)
{
return Boxed_Value(p, true);
}
}; };
template<typename Ret> template<typename Ret>
struct Handle_Return<const Ret *> struct Handle_Return<const Ret *> {
{ static Boxed_Value handle(const Ret *p) { return Boxed_Value(p, true); }
static Boxed_Value handle(const Ret *p)
{
return Boxed_Value(p, true);
}
}; };
template<typename Ret> template<typename Ret>
struct Handle_Return<std::shared_ptr<Ret> &> struct Handle_Return<std::shared_ptr<Ret> &> {
{ static Boxed_Value handle(const std::shared_ptr<Ret> &r) { return Boxed_Value(r, true); }
static Boxed_Value handle(const std::shared_ptr<Ret> &r)
{
return Boxed_Value(r, true);
}
}; };
template<typename Ret> template<typename Ret>
struct Handle_Return<std::shared_ptr<Ret>> : Handle_Return<std::shared_ptr<Ret> &> struct Handle_Return<std::shared_ptr<Ret>> : Handle_Return<std::shared_ptr<Ret> &> {
{
}; };
template<typename Ret> template<typename Ret>
struct Handle_Return<const std::shared_ptr<Ret> &> : Handle_Return<std::shared_ptr<Ret> &> struct Handle_Return<const std::shared_ptr<Ret> &> : Handle_Return<std::shared_ptr<Ret> &> {
{
}; };
template<typename Ret> template<typename Ret>
struct Handle_Return<std::unique_ptr<Ret>> : Handle_Return<std::unique_ptr<Ret> &> struct Handle_Return<std::unique_ptr<Ret>> : Handle_Return<std::unique_ptr<Ret> &> {
{ static Boxed_Value handle(std::unique_ptr<Ret> &&r) { return Boxed_Value(std::move(r), true); }
static Boxed_Value handle(std::unique_ptr<Ret> &&r)
{
return Boxed_Value(std::move(r), true);
}
}; };
template<typename Ret, bool Ptr> template<typename Ret, bool Ptr>
struct Handle_Return_Ref struct Handle_Return_Ref {
{
template<typename T> template<typename T>
static Boxed_Value handle(T &&r) static Boxed_Value handle(T &&r) {
{
return Boxed_Value(std::cref(r), true); return Boxed_Value(std::cref(r), true);
} }
}; };
template<typename Ret> template<typename Ret>
struct Handle_Return_Ref<Ret, true> struct Handle_Return_Ref<Ret, true> {
{
template<typename T> template<typename T>
static Boxed_Value handle(T &&r) static Boxed_Value handle(T &&r) {
{
return Boxed_Value(typename std::remove_reference<decltype(r)>::type{r}, true); return Boxed_Value(typename std::remove_reference<decltype(r)>::type{r}, true);
} }
}; };
template<typename Ret> template<typename Ret>
struct Handle_Return<const Ret &> : Handle_Return_Ref<const Ret &, std::is_pointer<typename std::remove_reference<const Ret &>::type>::value> struct Handle_Return<const Ret &> : Handle_Return_Ref<const Ret &, std::is_pointer<typename std::remove_reference<const Ret &>::type>::value> {
{
};
template<typename Ret>
struct Handle_Return<const Ret>
{
static Boxed_Value handle(Ret r)
{
return Boxed_Value(std::move(r));
}
}; };
template<typename Ret> template<typename Ret>
struct Handle_Return<Ret &> struct Handle_Return<const Ret> {
{ static Boxed_Value handle(Ret r) { return Boxed_Value(std::move(r)); }
static Boxed_Value handle(Ret &r) };
{
return Boxed_Value(std::ref(r)); template<typename Ret>
} struct Handle_Return<Ret &> {
static Boxed_Value handle(Ret &r) { return Boxed_Value(std::ref(r)); }
}; };
template<> template<>
struct Handle_Return<Boxed_Value> struct Handle_Return<Boxed_Value> {
{ static Boxed_Value handle(const Boxed_Value &r) noexcept { return r; }
static Boxed_Value handle(const Boxed_Value &r) noexcept
{
return r;
}
}; };
template<> template<>
struct Handle_Return<const Boxed_Value> : Handle_Return<Boxed_Value> struct Handle_Return<const Boxed_Value> : Handle_Return<Boxed_Value> {
{
}; };
template<> template<>
struct Handle_Return<Boxed_Value &> : Handle_Return<Boxed_Value> struct Handle_Return<Boxed_Value &> : Handle_Return<Boxed_Value> {
{
}; };
template<> template<>
struct Handle_Return<const Boxed_Value &> : Handle_Return<Boxed_Value> struct Handle_Return<const Boxed_Value &> : Handle_Return<Boxed_Value> {
{
}; };
/** /**
* Used internally for handling a return value from a Proxy_Function call * Used internally for handling a return value from a Proxy_Function call
*/ */
template<> template<>
struct Handle_Return<Boxed_Number> struct Handle_Return<Boxed_Number> {
{ static Boxed_Value handle(const Boxed_Number &r) noexcept { return r.bv; }
static Boxed_Value handle(const Boxed_Number &r) noexcept
{
return r.bv;
}
}; };
template<> template<>
struct Handle_Return<const Boxed_Number> : Handle_Return<Boxed_Number> struct Handle_Return<const Boxed_Number> : Handle_Return<Boxed_Number> {
{
}; };
/** /**
* Used internally for handling a return value from a Proxy_Function call * Used internally for handling a return value from a Proxy_Function call
*/ */
template<> template<>
struct Handle_Return<void> struct Handle_Return<void> {
{ static Boxed_Value handle() { return void_var(); }
static Boxed_Value handle()
{
return void_var();
}
}; };
} } // namespace detail
} } // namespace dispatch
} } // namespace chaiscript
#endif #endif

View File

@ -7,218 +7,178 @@
// This is an open source non-commercial project. Dear PVS-Studio, please check it. // This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com // PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_OPERATORS_HPP_ #ifndef CHAISCRIPT_OPERATORS_HPP_
#define CHAISCRIPT_OPERATORS_HPP_ #define CHAISCRIPT_OPERATORS_HPP_
#include "../chaiscript_defines.hpp" #include "../chaiscript_defines.hpp"
#include "../dispatchkit/dispatchkit.hpp"
#include "register_function.hpp" #include "register_function.hpp"
namespace chaiscript namespace chaiscript::bootstrap::operators {
{
namespace bootstrap
{
namespace operators
{
template<typename T> template<typename T>
void assign(Module& m) void assign(Module &m) {
{ m.add(chaiscript::fun([](T &lhs, const T &rhs) -> T & { return lhs = rhs; }), "=");
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs = rhs;}), "=");
} }
template<typename T> template<typename T>
void assign_bitwise_and(Module& m) void assign_bitwise_and(Module &m) {
{ m.add(chaiscript::fun([](T &lhs, const T &rhs) -> T & { return lhs &= rhs; }), "&=");
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs &= rhs;}), "&=");
} }
template<typename T> template<typename T>
void assign_xor(Module& m) void assign_xor(Module &m) {
{ m.add(chaiscript::fun([](T &lhs, const T &rhs) -> T & { return lhs ^= rhs; }), "^=");
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs ^= rhs;}), "^=");
} }
template<typename T> template<typename T>
void assign_bitwise_or(Module& m) void assign_bitwise_or(Module &m) {
{ m.add(chaiscript::fun([](T &lhs, const T &rhs) -> T & { return lhs |= rhs; }), "|=");
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs |= rhs;}), "|=");
} }
template<typename T> template<typename T>
void assign_difference(Module& m) void assign_difference(Module &m) {
{ m.add(chaiscript::fun([](T &lhs, const T &rhs) -> T & { return lhs -= rhs; }), "-=");
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs -= rhs;}), "-=");
} }
template<typename T> template<typename T>
void assign_left_shift(Module& m) void assign_left_shift(Module &m) {
{ m.add(chaiscript::fun([](T &lhs, const T &rhs) -> T & { return lhs <<= rhs; }), "<<=");
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs <<= rhs;}), "<<=");
} }
template<typename T> template<typename T>
void assign_product(Module& m) void assign_product(Module &m) {
{ m.add(chaiscript::fun([](T &lhs, const T &rhs) -> T & { return lhs <<= rhs; }), "*=");
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs <<= rhs;}), "*=");
} }
template<typename T> template<typename T>
void assign_quotient(Module& m) void assign_quotient(Module &m) {
{ m.add(chaiscript::fun([](T &lhs, const T &rhs) -> T & { return lhs /= rhs; }), "/=");
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs /= rhs;}), "/=");
} }
template<typename T> template<typename T>
void assign_remainder(Module& m) void assign_remainder(Module &m) {
{ m.add(chaiscript::fun([](T &lhs, const T &rhs) -> T & { return lhs %= rhs; }), "%=");
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs %= rhs;}), "%=");
} }
template<typename T> template<typename T>
void assign_right_shift(Module& m) void assign_right_shift(Module &m) {
{ m.add(chaiscript::fun([](T &lhs, const T &rhs) -> T & { return lhs >>= rhs; }), ">>=");
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs >>= rhs;}), ">>=");
} }
template<typename T> template<typename T>
void assign_sum(Module& m) void assign_sum(Module &m) {
{ m.add(chaiscript::fun([](T &lhs, const T &rhs) -> T & { return lhs += rhs; }), "+=");
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs += rhs;}), "+=");
} }
template<typename T> template<typename T>
void prefix_decrement(Module& m) void prefix_decrement(Module &m) {
{ m.add(chaiscript::fun([](T &lhs) -> T & { return --lhs; }), "--");
m.add(chaiscript::fun([](T &lhs)->T&{return --lhs;}), "--");
} }
template<typename T> template<typename T>
void prefix_increment(Module& m) void prefix_increment(Module &m) {
{ m.add(chaiscript::fun([](T &lhs) -> T & { return ++lhs; }), "++");
m.add(chaiscript::fun([](T &lhs)->T&{return ++lhs;}), "++");
} }
template<typename T> template<typename T>
void equal(Module& m) void equal(Module &m) {
{ m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs == rhs; }), "==");
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs==rhs;}), "==");
} }
template<typename T> template<typename T>
void greater_than(Module& m) void greater_than(Module &m) {
{ m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs > rhs; }), ">");
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs>rhs;}), ">");
} }
template<typename T> template<typename T>
void greater_than_equal(Module& m) void greater_than_equal(Module &m) {
{ m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs >= rhs; }), ">=");
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs>=rhs;}), ">=");
} }
template<typename T> template<typename T>
void less_than(Module& m) void less_than(Module &m) {
{ m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs < rhs; }), "<");
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs<rhs;}), "<");
} }
template<typename T> template<typename T>
void less_than_equal(Module& m) void less_than_equal(Module &m) {
{ m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs <= rhs; }), "<=");
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs<=rhs;}), "<=");
} }
template<typename T> template<typename T>
void logical_compliment(Module& m) void logical_compliment(Module &m) {
{ m.add(chaiscript::fun([](const T &lhs) { return !lhs; }), "!");
m.add(chaiscript::fun([](const T &lhs){return !lhs;}), "!");
} }
template<typename T> template<typename T>
void not_equal(Module& m) void not_equal(Module &m) {
{ m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs != rhs; }), "!=");
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs!=rhs;}), "!=");
} }
template<typename T> template<typename T>
void addition(Module& m) void addition(Module &m) {
{ m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs + rhs; }), "+");
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs+rhs;}), "+");
} }
template<typename T> template<typename T>
void unary_plus(Module& m) void unary_plus(Module &m) {
{ m.add(chaiscript::fun([](const T &lhs) { return +lhs; }), "+");
m.add(chaiscript::fun([](const T &lhs){return +lhs;}), "+");
} }
template<typename T> template<typename T>
void subtraction(Module& m) void subtraction(Module &m) {
{ m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs - rhs; }), "-");
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs-rhs;}), "-");
} }
template<typename T> template<typename T>
void unary_minus(Module& m) void unary_minus(Module &m) {
{ m.add(chaiscript::fun([](const T &lhs) { return -lhs; }), "-");
m.add(chaiscript::fun([](const T &lhs){return -lhs;}), "-");
} }
template<typename T> template<typename T>
void bitwise_and(Module& m) void bitwise_and(Module &m) {
{ m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs & rhs; }), "&");
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs&rhs;}), "&");
} }
template<typename T> template<typename T>
void bitwise_compliment(Module& m) void bitwise_compliment(Module &m) {
{ m.add(chaiscript::fun([](const T &lhs) { return ~lhs; }), "~");
m.add(chaiscript::fun([](const T &lhs){return ~lhs;}), "~");
} }
template<typename T> template<typename T>
void bitwise_xor(Module& m) void bitwise_xor(Module &m) {
{ m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs ^ rhs; }), "^");
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs^rhs;}), "^");
} }
template<typename T> template<typename T>
void bitwise_or(Module& m) void bitwise_or(Module &m) {
{ m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs | rhs; }), "|");
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs|rhs;}), "|");
} }
template<typename T> template<typename T>
void division(Module& m) void division(Module &m) {
{ m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs / rhs; }), "/");
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs/rhs;}), "/");
} }
template<typename T> template<typename T>
void left_shift(Module& m) void left_shift(Module &m) {
{ m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs << rhs; }), "<<");
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs<<rhs;}), "<<");
} }
template<typename T> template<typename T>
void multiplication(Module& m) void multiplication(Module &m) {
{ m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs * rhs; }), "*");
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs*rhs;}), "*");
} }
template<typename T> template<typename T>
void remainder(Module& m) void remainder(Module &m) {
{ m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs % rhs; }), "%");
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs%rhs;}), "%");
} }
template<typename T> template<typename T>
void right_shift(Module& m) void right_shift(Module &m) {
{ m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs >> rhs; }), ">>");
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs>>rhs;}), ">>");
} }
} } // namespace chaiscript::bootstrap::operators
}
}
#endif #endif

View File

@ -7,41 +7,31 @@
// This is an open source non-commercial project. Dear PVS-Studio, please check it. // This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com // PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_PROXY_CONSTRUCTORS_HPP_ #ifndef CHAISCRIPT_PROXY_CONSTRUCTORS_HPP_
#define CHAISCRIPT_PROXY_CONSTRUCTORS_HPP_ #define CHAISCRIPT_PROXY_CONSTRUCTORS_HPP_
#include "proxy_functions.hpp" #include "proxy_functions.hpp"
namespace chaiscript namespace chaiscript::dispatch::detail {
{ template<typename Class, typename... Params>
namespace dispatch Proxy_Function build_constructor_(Class (*)(Params...)) {
{
namespace detail
{
template<typename Class, typename ... Params >
Proxy_Function build_constructor_(Class (*)(Params...))
{
if constexpr (!std::is_copy_constructible_v<Class>) { if constexpr (!std::is_copy_constructible_v<Class>) {
auto call = [](auto && ... param) { auto call = [](auto &&...param) { return std::make_shared<Class>(std::forward<decltype(param)>(param)...); };
return std::make_shared<Class>(std::forward<decltype(param)>(param)...);
};
return Proxy_Function( return Proxy_Function(
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<std::shared_ptr<Class> (Params...), decltype(call)>>(call)); chaiscript::make_shared<dispatch::Proxy_Function_Base,
dispatch::Proxy_Function_Callable_Impl<std::shared_ptr<Class>(Params...), decltype(call)>>(call));
} else if constexpr (true) { } else if constexpr (true) {
auto call = [](auto && ... param){ auto call = [](auto &&...param) { return Class(std::forward<decltype(param)>(param)...); };
return Class(std::forward<decltype(param)>(param)...);
};
return Proxy_Function( return Proxy_Function(
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Class (Params...), decltype(call)>>(call)); chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Class(Params...), decltype(call)>>(
} call));
}
} }
} }
} // namespace chaiscript::dispatch::detail
namespace chaiscript {
/// \brief Generates a constructor function for use with ChaiScript /// \brief Generates a constructor function for use with ChaiScript
/// ///
/// \tparam T The signature of the constructor to generate. In the form of: ClassType (ParamType1, ParamType2, ...) /// \tparam T The signature of the constructor to generate. In the form of: ClassType (ParamType1, ParamType2, ...)
@ -54,13 +44,10 @@ namespace chaiscript
/// chai.add(constructor<MyClass (int, float)>(), "MyClass"); /// chai.add(constructor<MyClass (int, float)>(), "MyClass");
/// \endcode /// \endcode
template<typename T> template<typename T>
Proxy_Function constructor() Proxy_Function constructor() {
{
T *f = nullptr; T *f = nullptr;
return (dispatch::detail::build_constructor_(f)); return (dispatch::detail::build_constructor_(f));
} }
} // namespace chaiscript
}
#endif #endif

File diff suppressed because it is too large Load Diff

View File

@ -7,43 +7,39 @@
// This is an open source non-commercial project. Dear PVS-Studio, please check it. // This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com // PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_PROXY_FUNCTIONS_DETAIL_HPP_ #ifndef CHAISCRIPT_PROXY_FUNCTIONS_DETAIL_HPP_
#define CHAISCRIPT_PROXY_FUNCTIONS_DETAIL_HPP_ #define CHAISCRIPT_PROXY_FUNCTIONS_DETAIL_HPP_
#include <array>
#include <functional> #include <functional>
#include <stdexcept> #include <stdexcept>
#include <vector> #include <vector>
#include <array>
#include "../chaiscript_defines.hpp" #include "../chaiscript_defines.hpp"
#include "boxed_cast.hpp" #include "boxed_cast.hpp"
#include "boxed_value.hpp" #include "boxed_value.hpp"
#include "function_params.hpp"
#include "handle_return.hpp" #include "handle_return.hpp"
#include "type_info.hpp" #include "type_info.hpp"
#include "function_params.hpp"
namespace chaiscript { namespace chaiscript {
class Type_Conversions_State; class Type_Conversions_State;
namespace exception { namespace exception {
class bad_boxed_cast; class bad_boxed_cast;
} // namespace exception } // namespace exception
} // namespace chaiscript } // namespace chaiscript
namespace chaiscript namespace chaiscript {
{ namespace exception {
namespace exception
{
/** /**
* Exception thrown when there is a mismatch in number of * Exception thrown when there is a mismatch in number of
* parameters during Proxy_Function execution * parameters during Proxy_Function execution
*/ */
struct arity_error : std::range_error struct arity_error : std::range_error {
{
arity_error(int t_got, int t_expected) arity_error(int t_got, int t_expected)
: std::range_error("Function dispatch arity mismatch"), : std::range_error("Function dispatch arity mismatch")
got(t_got), expected(t_expected) , got(t_got)
{ , expected(t_expected) {
} }
arity_error(const arity_error &) = default; arity_error(const arity_error &) = default;
@ -53,61 +49,52 @@ namespace chaiscript
int got; int got;
int expected; int expected;
}; };
} } // namespace exception
namespace dispatch namespace dispatch {
{ namespace detail {
namespace detail
{
/** /**
* Used by Proxy_Function_Impl to return a list of all param types * Used by Proxy_Function_Impl to return a list of all param types
* it contains. * it contains.
*/ */
template<typename Ret, typename ... Params> template<typename Ret, typename... Params>
std::vector<Type_Info> build_param_type_list(Ret (*)(Params...)) std::vector<Type_Info> build_param_type_list(Ret (*)(Params...)) {
{
/// \note somehow this is responsible for a large part of the code generation /// \note somehow this is responsible for a large part of the code generation
return { user_type<Ret>(), user_type<Params>()... }; return {user_type<Ret>(), user_type<Params>()...};
} }
/** /**
* Used by Proxy_Function_Impl to determine if it is equivalent to another * Used by Proxy_Function_Impl to determine if it is equivalent to another
* Proxy_Function_Impl object. This function is primarily used to prevent * Proxy_Function_Impl object. This function is primarily used to prevent
* registration of two functions with the exact same signatures * registration of two functions with the exact same signatures
*/ */
template<typename Ret, typename ... Params> template<typename Ret, typename... Params>
bool compare_types_cast(Ret (*)(Params...), bool compare_types_cast(Ret (*)(Params...), const chaiscript::Function_Params &params, const Type_Conversions_State &t_conversions) noexcept {
const chaiscript::Function_Params &params, const Type_Conversions_State &t_conversions) noexcept
{
try { try {
std::vector<Boxed_Value>::size_type i = 0; std::vector<Boxed_Value>::size_type i = 0;
( boxed_cast<Params>(params[i++], &t_conversions), ... ); (boxed_cast<Params>(params[i++], &t_conversions), ...);
return true; return true;
} catch (const exception::bad_boxed_cast &) { } catch (const exception::bad_boxed_cast &) {
return false; return false;
} }
} }
template<typename Callable, typename Ret, typename... Params, size_t... I>
template<typename Callable, typename Ret, typename ... Params, size_t ... I>
Ret call_func(Ret (*)(Params...), Ret call_func(Ret (*)(Params...),
std::index_sequence<I...>, const Callable &f, std::index_sequence<I...>,
const Callable &f,
[[maybe_unused]] const chaiscript::Function_Params &params, [[maybe_unused]] const chaiscript::Function_Params &params,
[[maybe_unused]] const Type_Conversions_State &t_conversions) [[maybe_unused]] const Type_Conversions_State &t_conversions) {
{
return f(boxed_cast<Params>(params[I], &t_conversions)...); return f(boxed_cast<Params>(params[I], &t_conversions)...);
} }
/// Used by Proxy_Function_Impl to perform typesafe execution of a function. /// Used by Proxy_Function_Impl to perform typesafe execution of a function.
/// The function attempts to unbox each parameter to the expected type. /// The function attempts to unbox each parameter to the expected type.
/// if any unboxing fails the execution of the function fails and /// if any unboxing fails the execution of the function fails and
/// the bad_boxed_cast is passed up to the caller. /// the bad_boxed_cast is passed up to the caller.
template<typename Callable, typename Ret, typename ... Params> template<typename Callable, typename Ret, typename... Params>
Boxed_Value call_func(Ret (*sig)(Params...), const Callable &f, Boxed_Value
const chaiscript::Function_Params &params, const Type_Conversions_State &t_conversions) call_func(Ret (*sig)(Params...), const Callable &f, const chaiscript::Function_Params &params, const Type_Conversions_State &t_conversions) {
{
if constexpr (std::is_same_v<Ret, void>) { if constexpr (std::is_same_v<Ret, void>) {
call_func(sig, std::index_sequence_for<Params...>{}, f, params, t_conversions); call_func(sig, std::index_sequence_for<Params...>{}, f, params, t_conversions);
return Handle_Return<void>::handle(); return Handle_Return<void>::handle();
@ -116,10 +103,9 @@ namespace chaiscript
} }
} }
} } // namespace detail
} } // namespace dispatch
}
} // namespace chaiscript
#endif #endif

View File

@ -7,63 +7,55 @@
// This is an open source non-commercial project. Dear PVS-Studio, please check it. // This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com // PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_REGISTER_FUNCTION_HPP_ #ifndef CHAISCRIPT_REGISTER_FUNCTION_HPP_
#define CHAISCRIPT_REGISTER_FUNCTION_HPP_ #define CHAISCRIPT_REGISTER_FUNCTION_HPP_
#include <type_traits> #include <type_traits>
#include "bind_first.hpp" #include "bind_first.hpp"
#include "proxy_functions.hpp"
#include "function_signature.hpp" #include "function_signature.hpp"
#include "proxy_functions.hpp"
namespace chaiscript namespace chaiscript {
{ namespace dispatch::detail {
namespace dispatch::detail template<typename Obj, typename Param1, typename... Rest>
{ Param1 get_first_param(Function_Params<Param1, Rest...>, Obj &&obj) {
template<typename Obj, typename Param1, typename ... Rest>
Param1 get_first_param(Function_Params<Param1, Rest...>, Obj &&obj)
{
return static_cast<Param1>(std::forward<Obj>(obj)); return static_cast<Param1>(std::forward<Obj>(obj));
} }
template<typename Func, bool Is_Noexcept, bool Is_Member, bool Is_MemberObject, bool Is_Object, typename Ret, typename ... Param> template<typename Func, bool Is_Noexcept, bool Is_Member, bool Is_MemberObject, bool Is_Object, typename Ret, typename... Param>
auto make_callable_impl(Func &&func, Function_Signature<Ret, Function_Params<Param...>, Is_Noexcept, Is_Member, Is_MemberObject, Is_Object>) auto make_callable_impl(Func &&func, Function_Signature<Ret, Function_Params<Param...>, Is_Noexcept, Is_Member, Is_MemberObject, Is_Object>) {
{
if constexpr (Is_MemberObject) { if constexpr (Is_MemberObject) {
// we now that the Param pack will have only one element, so we are safe expanding it here // we now that the Param pack will have only one element, so we are safe expanding it here
return Proxy_Function(chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Attribute_Access<Ret, std::decay_t<Param>...>>(std::forward<Func>(func))); return Proxy_Function(chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Attribute_Access<Ret, std::decay_t<Param>...>>(
std::forward<Func>(func)));
} else if constexpr (Is_Member) { } else if constexpr (Is_Member) {
// TODO some kind of bug is preventing forwarding of this noexcept for the lambda // TODO some kind of bug is preventing forwarding of this noexcept for the lambda
auto call = [func = std::forward<Func>(func)](auto && obj, auto && ... param) /* noexcept(Is_Noexcept) */ -> decltype(auto) { auto call = [func = std::forward<Func>(func)](auto &&obj, auto &&...param) /* noexcept(Is_Noexcept) */ -> decltype(auto) {
return (( get_first_param(Function_Params<Param...>{}, obj).*func )(std::forward<decltype(param)>(param)...)); return ((get_first_param(Function_Params<Param...>{}, obj).*func)(std::forward<decltype(param)>(param)...));
}; };
return Proxy_Function( return Proxy_Function(
chaiscript::make_shared<dispatch::Proxy_Function_Base, chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Ret(Param...), decltype(call)>>(
dispatch::Proxy_Function_Callable_Impl<Ret (Param...), decltype(call)>>(std::move(call)) std::move(call)));
);
} else { } else {
return Proxy_Function( return Proxy_Function(
chaiscript::make_shared<dispatch::Proxy_Function_Base, chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Ret(Param...), std::decay_t<Func>>>(
dispatch::Proxy_Function_Callable_Impl<Ret (Param...), std::decay_t<Func>>>(std::forward<Func>(func)) std::forward<Func>(func)));
);
} }
} }
// this version peels off the function object itself from the function signature, when used // this version peels off the function object itself from the function signature, when used
// on a callable object // on a callable object
template<typename Func, typename Ret, typename Object, typename ... Param, bool Is_Noexcept> template<typename Func, typename Ret, typename Object, typename... Param, bool Is_Noexcept>
auto make_callable(Func &&func, Function_Signature<Ret, Function_Params<Object, Param...>, Is_Noexcept, false, false, true>) auto make_callable(Func &&func, Function_Signature<Ret, Function_Params<Object, Param...>, Is_Noexcept, false, false, true>) {
{
return make_callable_impl(std::forward<Func>(func), Function_Signature<Ret, Function_Params<Param...>, Is_Noexcept, false, false, true>{}); return make_callable_impl(std::forward<Func>(func), Function_Signature<Ret, Function_Params<Param...>, Is_Noexcept, false, false, true>{});
} }
template<typename Func, typename Ret, typename ... Param, bool Is_Noexcept, bool Is_Member, bool Is_MemberObject> template<typename Func, typename Ret, typename... Param, bool Is_Noexcept, bool Is_Member, bool Is_MemberObject>
auto make_callable(Func &&func, Function_Signature<Ret, Function_Params<Param...>, Is_Noexcept, Is_Member, Is_MemberObject, false> fs) auto make_callable(Func &&func, Function_Signature<Ret, Function_Params<Param...>, Is_Noexcept, Is_Member, Is_MemberObject, false> fs) {
{
return make_callable_impl(std::forward<Func>(func), fs); return make_callable_impl(std::forward<Func>(func), fs);
} }
} } // namespace dispatch::detail
/// \brief Creates a new Proxy_Function object from a free function, member function or data member /// \brief Creates a new Proxy_Function object from a free function, member function or data member
/// \param[in] t Function / member to expose /// \param[in] t Function / member to expose
@ -86,13 +78,10 @@ namespace chaiscript
/// ///
/// \sa \ref adding_functions /// \sa \ref adding_functions
template<typename T> template<typename T>
Proxy_Function fun(T &&t) Proxy_Function fun(T &&t) {
{
return dispatch::detail::make_callable(std::forward<T>(t), dispatch::detail::function_signature(t)); return dispatch::detail::make_callable(std::forward<T>(t), dispatch::detail::function_signature(t));
} }
/// \brief Creates a new Proxy_Function object from a free function, member function or data member and binds the first parameter of it /// \brief Creates a new Proxy_Function object from a free function, member function or data member and binds the first parameter of it
/// \param[in] t Function / member to expose /// \param[in] t Function / member to expose
/// \param[in] q Value to bind to first parameter /// \param[in] q Value to bind to first parameter
@ -112,15 +101,10 @@ namespace chaiscript
/// ///
/// \sa \ref adding_functions /// \sa \ref adding_functions
template<typename T, typename Q> template<typename T, typename Q>
Proxy_Function fun(T &&t, const Q &q) Proxy_Function fun(T &&t, const Q &q) {
{
return fun(detail::bind_first(std::forward<T>(t), q)); return fun(detail::bind_first(std::forward<T>(t), q));
} }
} // namespace chaiscript
}
#endif #endif

View File

@ -23,80 +23,70 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE. // SOFTWARE.
#include <cstddef>
#include <cassert> #include <cassert>
#include <cstddef>
template <std::size_t N, std::size_t alignment = alignof(std::max_align_t)> template<std::size_t N, std::size_t alignment = alignof(std::max_align_t)>
class arena class arena {
{
alignas(alignment) char buf_[N]; alignas(alignment) char buf_[N];
char* ptr_; char *ptr_;
public: public:
~arena() {ptr_ = nullptr;} ~arena() { ptr_ = nullptr; }
arena() noexcept : ptr_(buf_) {} arena() noexcept
arena(const arena&) = delete; : ptr_(buf_) {
arena& operator=(const arena&) = delete; }
arena(const arena &) = delete;
arena &operator=(const arena &) = delete;
template <std::size_t ReqAlign> char* allocate(std::size_t n); template<std::size_t ReqAlign>
void deallocate(char* p, std::size_t n) noexcept; char *allocate(std::size_t n);
void deallocate(char *p, std::size_t n) noexcept;
static constexpr std::size_t size() noexcept {return N;} static constexpr std::size_t size() noexcept { return N; }
std::size_t used() const noexcept {return static_cast<std::size_t>(ptr_ - buf_);} std::size_t used() const noexcept { return static_cast<std::size_t>(ptr_ - buf_); }
void reset() noexcept {ptr_ = buf_;} void reset() noexcept { ptr_ = buf_; }
private: private:
static static std::size_t align_up(std::size_t n) noexcept { return (n + (alignment - 1)) & ~(alignment - 1); }
std::size_t
align_up(std::size_t n) noexcept
{return (n + (alignment-1)) & ~(alignment-1);}
bool bool pointer_in_buffer(char *p) noexcept { return buf_ <= p && p <= buf_ + N; }
pointer_in_buffer(char* p) noexcept
{return buf_ <= p && p <= buf_ + N;}
}; };
template <std::size_t N, std::size_t alignment> template<std::size_t N, std::size_t alignment>
template <std::size_t ReqAlign> template<std::size_t ReqAlign>
char* char *arena<N, alignment>::allocate(std::size_t n) {
arena<N, alignment>::allocate(std::size_t n)
{
static_assert(ReqAlign <= alignment, "alignment is too small for this arena"); static_assert(ReqAlign <= alignment, "alignment is too small for this arena");
assert(pointer_in_buffer(ptr_) && "short_alloc has outlived arena"); assert(pointer_in_buffer(ptr_) && "short_alloc has outlived arena");
auto const aligned_n = align_up(n); auto const aligned_n = align_up(n);
if (static_cast<decltype(aligned_n)>(buf_ + N - ptr_) >= aligned_n) if (static_cast<decltype(aligned_n)>(buf_ + N - ptr_) >= aligned_n) {
{ char *r = ptr_;
char* r = ptr_;
ptr_ += aligned_n; ptr_ += aligned_n;
return r; return r;
} }
static_assert(alignment <= alignof(std::max_align_t), "you've chosen an " static_assert(alignment <= alignof(std::max_align_t),
"you've chosen an "
"alignment that is larger than alignof(std::max_align_t), and " "alignment that is larger than alignof(std::max_align_t), and "
"cannot be guaranteed by normal operator new"); "cannot be guaranteed by normal operator new");
return static_cast<char*>(::operator new(n)); return static_cast<char *>(::operator new(n));
} }
template <std::size_t N, std::size_t alignment> template<std::size_t N, std::size_t alignment>
void void arena<N, alignment>::deallocate(char *p, std::size_t n) noexcept {
arena<N, alignment>::deallocate(char* p, std::size_t n) noexcept
{
assert(pointer_in_buffer(ptr_) && "short_alloc has outlived arena"); assert(pointer_in_buffer(ptr_) && "short_alloc has outlived arena");
if (pointer_in_buffer(p)) if (pointer_in_buffer(p)) {
{
n = align_up(n); n = align_up(n);
if (p + n == ptr_) { if (p + n == ptr_) {
ptr_ = p; ptr_ = p;
} }
} } else {
else {
::operator delete(p); ::operator delete(p);
} }
} }
template <class T, std::size_t N, std::size_t Align = alignof(std::max_align_t)> template<class T, std::size_t N, std::size_t Align = alignof(std::max_align_t)>
class short_alloc class short_alloc {
{
public: public:
using value_type = T; using value_type = T;
static auto constexpr alignment = Align; static auto constexpr alignment = Align;
@ -104,56 +94,44 @@ public:
using arena_type = arena<size, alignment>; using arena_type = arena<size, alignment>;
private: private:
arena_type& a_; arena_type &a_;
public: public:
short_alloc(const short_alloc&) = default; short_alloc(const short_alloc &) = default;
short_alloc& operator=(const short_alloc&) = delete; short_alloc &operator=(const short_alloc &) = delete;
explicit short_alloc(arena_type& a) noexcept : a_(a) explicit short_alloc(arena_type &a) noexcept
{ : a_(a) {
static_assert(size % alignment == 0, static_assert(size % alignment == 0, "size N needs to be a multiple of alignment Align");
"size N needs to be a multiple of alignment Align");
} }
template <class U> template<class U>
explicit short_alloc(const short_alloc<U, N, alignment>& a) noexcept explicit short_alloc(const short_alloc<U, N, alignment> &a) noexcept
: a_(a.a_) {} : a_(a.a_) {
template <class _Up> struct rebind {using other = short_alloc<_Up, N, alignment>;};
T* allocate(std::size_t n)
{
return reinterpret_cast<T*>(a_.template allocate<alignof(T)>(n*sizeof(T)));
}
void deallocate(T* p, std::size_t n) noexcept
{
a_.deallocate(reinterpret_cast<char*>(p), n*sizeof(T));
} }
template <class T1, std::size_t N1, std::size_t A1, template<class _Up>
class U, std::size_t M, std::size_t A2> struct rebind {
friend using other = short_alloc<_Up, N, alignment>;
bool };
operator==(const short_alloc<T1, N1, A1>& x, const short_alloc<U, M, A2>& y) noexcept;
template <class U, std::size_t M, std::size_t A> friend class short_alloc; T *allocate(std::size_t n) { return reinterpret_cast<T *>(a_.template allocate<alignof(T)>(n * sizeof(T))); }
void deallocate(T *p, std::size_t n) noexcept { a_.deallocate(reinterpret_cast<char *>(p), n * sizeof(T)); }
template<class T1, std::size_t N1, std::size_t A1, class U, std::size_t M, std::size_t A2>
friend bool operator==(const short_alloc<T1, N1, A1> &x, const short_alloc<U, M, A2> &y) noexcept;
template<class U, std::size_t M, std::size_t A>
friend class short_alloc;
}; };
template <class T, std::size_t N, std::size_t A1, class U, std::size_t M, std::size_t A2> template<class T, std::size_t N, std::size_t A1, class U, std::size_t M, std::size_t A2>
inline inline bool operator==(const short_alloc<T, N, A1> &x, const short_alloc<U, M, A2> &y) noexcept {
bool
operator==(const short_alloc<T, N, A1>& x, const short_alloc<U, M, A2>& y) noexcept
{
return N == M && A1 == A2 && &x.a_ == &y.a_; return N == M && A1 == A2 && &x.a_ == &y.a_;
} }
template <class T, std::size_t N, std::size_t A1, class U, std::size_t M, std::size_t A2> template<class T, std::size_t N, std::size_t A1, class U, std::size_t M, std::size_t A2>
inline inline bool operator!=(const short_alloc<T, N, A1> &x, const short_alloc<U, M, A2> &y) noexcept {
bool
operator!=(const short_alloc<T, N, A1>& x, const short_alloc<U, M, A2>& y) noexcept
{
return !(x == y); return !(x == y);
} }
#endif // SHORT_ALLOC_HPP #endif // SHORT_ALLOC_HPP

View File

@ -7,10 +7,10 @@
// This is an open source non-commercial project. Dear PVS-Studio, please check it. // This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com // PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_DYNAMIC_CAST_CONVERSION_HPP_ #ifndef CHAISCRIPT_DYNAMIC_CAST_CONVERSION_HPP_
#define CHAISCRIPT_DYNAMIC_CAST_CONVERSION_HPP_ #define CHAISCRIPT_DYNAMIC_CAST_CONVERSION_HPP_
#include <algorithm>
#include <atomic> #include <atomic>
#include <memory> #include <memory>
#include <set> #include <set>
@ -26,37 +26,31 @@
#include "boxed_value.hpp" #include "boxed_value.hpp"
#include "type_info.hpp" #include "type_info.hpp"
namespace chaiscript namespace chaiscript {
{ namespace exception {
namespace exception
{
/// \brief Error thrown when there's a problem with type conversion /// \brief Error thrown when there's a problem with type conversion
class conversion_error: public bad_boxed_cast class conversion_error : public bad_boxed_cast {
{
public: public:
conversion_error(const Type_Info t_to, const Type_Info t_from, const utility::Static_String what) noexcept conversion_error(const Type_Info t_to, const Type_Info t_from, const utility::Static_String what) noexcept
: bad_boxed_cast(t_from, (*t_to.bare_type_info()), what), type_to(t_to) {} : bad_boxed_cast(t_from, (*t_to.bare_type_info()), what)
, type_to(t_to) {
}
Type_Info type_to; Type_Info type_to;
}; };
class bad_boxed_dynamic_cast : public bad_boxed_cast class bad_boxed_dynamic_cast : public bad_boxed_cast {
{
public: public:
bad_boxed_dynamic_cast(const Type_Info &t_from, const std::type_info &t_to, bad_boxed_dynamic_cast(const Type_Info &t_from, const std::type_info &t_to, const utility::Static_String &t_what) noexcept
const utility::Static_String &t_what) noexcept : bad_boxed_cast(t_from, t_to, t_what) {
: bad_boxed_cast(t_from, t_to, t_what)
{
} }
bad_boxed_dynamic_cast(const Type_Info &t_from, const std::type_info &t_to) noexcept bad_boxed_dynamic_cast(const Type_Info &t_from, const std::type_info &t_to) noexcept
: bad_boxed_cast(t_from, t_to) : bad_boxed_cast(t_from, t_to) {
{
} }
explicit bad_boxed_dynamic_cast(const utility::Static_String &w) noexcept explicit bad_boxed_dynamic_cast(const utility::Static_String &w) noexcept
: bad_boxed_cast(w) : bad_boxed_cast(w) {
{
} }
bad_boxed_dynamic_cast(const bad_boxed_dynamic_cast &) = default; bad_boxed_dynamic_cast(const bad_boxed_dynamic_cast &) = default;
@ -64,109 +58,78 @@ namespace chaiscript
~bad_boxed_dynamic_cast() noexcept override = default; ~bad_boxed_dynamic_cast() noexcept override = default;
}; };
class bad_boxed_type_cast : public bad_boxed_cast class bad_boxed_type_cast : public bad_boxed_cast {
{
public: public:
bad_boxed_type_cast(const Type_Info &t_from, const std::type_info &t_to, bad_boxed_type_cast(const Type_Info &t_from, const std::type_info &t_to, const utility::Static_String &t_what) noexcept
const utility::Static_String &t_what) noexcept : bad_boxed_cast(t_from, t_to, t_what) {
: bad_boxed_cast(t_from, t_to, t_what)
{
} }
bad_boxed_type_cast(const Type_Info &t_from, const std::type_info &t_to) noexcept bad_boxed_type_cast(const Type_Info &t_from, const std::type_info &t_to) noexcept
: bad_boxed_cast(t_from, t_to) : bad_boxed_cast(t_from, t_to) {
{
} }
explicit bad_boxed_type_cast(const utility::Static_String &w) noexcept explicit bad_boxed_type_cast(const utility::Static_String &w) noexcept
: bad_boxed_cast(w) : bad_boxed_cast(w) {
{
} }
bad_boxed_type_cast(const bad_boxed_type_cast &) = default; bad_boxed_type_cast(const bad_boxed_type_cast &) = default;
~bad_boxed_type_cast() noexcept override = default; ~bad_boxed_type_cast() noexcept override = default;
}; };
} } // namespace exception
namespace detail {
namespace detail class Type_Conversion_Base {
{
class Type_Conversion_Base
{
public: public:
virtual Boxed_Value convert(const Boxed_Value &from) const = 0; virtual Boxed_Value convert(const Boxed_Value &from) const = 0;
virtual Boxed_Value convert_down(const Boxed_Value &to) const = 0; virtual Boxed_Value convert_down(const Boxed_Value &to) const = 0;
const Type_Info &to() const noexcept const Type_Info &to() const noexcept { return m_to; }
{ const Type_Info &from() const noexcept { return m_from; }
return m_to;
}
const Type_Info &from() const noexcept
{
return m_from;
}
virtual bool bidir() const noexcept virtual bool bidir() const noexcept { return true; }
{
return true;
}
virtual ~Type_Conversion_Base() = default; virtual ~Type_Conversion_Base() = default;
protected: protected:
Type_Conversion_Base(Type_Info t_to, Type_Info t_from) Type_Conversion_Base(Type_Info t_to, Type_Info t_from)
: m_to(std::move(t_to)), m_from(std::move(t_from)) : m_to(std::move(t_to))
{ , m_from(std::move(t_from)) {
} }
private: private:
const Type_Info m_to; const Type_Info m_to;
const Type_Info m_from; const Type_Info m_from;
}; };
template<typename From, typename To> template<typename From, typename To>
class Static_Caster class Static_Caster {
{
public: public:
static Boxed_Value cast(const Boxed_Value &t_from) 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()) {
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 // Dynamic cast out the contained boxed value, which we know is the type we want
if (t_from.is_const()) if (t_from.is_const()) {
{ return Boxed_Value([&]() {
return Boxed_Value( if (auto data
[&](){ = std::static_pointer_cast<const To>(detail::Cast_Helper<std::shared_ptr<const From>>::cast(t_from, nullptr))) {
if (auto data = std::static_pointer_cast<const To>(detail::Cast_Helper<std::shared_ptr<const From> >::cast(t_from, nullptr)))
{
return data; return data;
} else { } else {
throw std::bad_cast(); throw std::bad_cast();
} }
}() }());
);
} else { } else {
return Boxed_Value( return Boxed_Value([&]() {
[&](){ if (auto data = std::static_pointer_cast<To>(detail::Cast_Helper<std::shared_ptr<From>>::cast(t_from, nullptr))) {
if (auto data = std::static_pointer_cast<To>(detail::Cast_Helper<std::shared_ptr<From> >::cast(t_from, nullptr)))
{
return data; return data;
} else { } else {
throw std::bad_cast(); throw std::bad_cast();
} }
}() }());
);
} }
} else { } else {
// Pull the reference out of the contained boxed value, which we know is the type we want // Pull the reference out of the contained boxed value, which we know is the type we want
if (t_from.is_const()) if (t_from.is_const()) {
{
const From &d = detail::Cast_Helper<const From &>::cast(t_from, nullptr); const From &d = detail::Cast_Helper<const From &>::cast(t_from, nullptr);
const To &data = static_cast<const To &>(d); const To &data = static_cast<const To &>(d);
return Boxed_Value(std::cref(data)); return Boxed_Value(std::cref(data));
@ -180,44 +143,33 @@ namespace chaiscript
throw chaiscript::exception::bad_boxed_dynamic_cast(t_from.get_type_info(), typeid(To), "Unknown dynamic_cast_conversion"); throw chaiscript::exception::bad_boxed_dynamic_cast(t_from.get_type_info(), typeid(To), "Unknown dynamic_cast_conversion");
} }
} }
}; };
template<typename From, typename To> template<typename From, typename To>
class Dynamic_Caster class Dynamic_Caster {
{
public: public:
static Boxed_Value cast(const Boxed_Value &t_from) static Boxed_Value cast(const Boxed_Value &t_from) {
{ if (t_from.get_type_info().bare_equal(chaiscript::user_type<From>())) {
if (t_from.get_type_info().bare_equal(chaiscript::user_type<From>())) if (t_from.is_pointer()) {
{
if (t_from.is_pointer())
{
// Dynamic cast out the contained boxed value, which we know is the type we want // Dynamic cast out the contained boxed value, which we know is the type we want
if (t_from.is_const()) if (t_from.is_const()) {
{ return Boxed_Value([&]() {
return Boxed_Value( if (auto data
[&](){ = std::dynamic_pointer_cast<const To>(detail::Cast_Helper<std::shared_ptr<const From>>::cast(t_from, nullptr))) {
if (auto data = std::dynamic_pointer_cast<const To>(detail::Cast_Helper<std::shared_ptr<const From> >::cast(t_from, nullptr)))
{
return data; return data;
} else { } else {
throw std::bad_cast(); throw std::bad_cast();
} }
}() }());
);
} else { } else {
return Boxed_Value( return Boxed_Value([&]() {
[&](){ if (auto data = std::dynamic_pointer_cast<To>(detail::Cast_Helper<std::shared_ptr<From>>::cast(t_from, nullptr))) {
if (auto data = std::dynamic_pointer_cast<To>(detail::Cast_Helper<std::shared_ptr<From> >::cast(t_from, nullptr)))
{
return data; return data;
} else { } else {
#ifdef CHAISCRIPT_LIBCPP #ifdef CHAISCRIPT_LIBCPP
/// \todo fix this someday after libc++ is fixed. /// \todo fix this someday after libc++ is fixed.
if (std::string(typeid(To).name()).find("Assignable_Proxy_Function") != std::string::npos) { if (std::string(typeid(To).name()).find("Assignable_Proxy_Function") != std::string::npos) {
auto from = detail::Cast_Helper<std::shared_ptr<From> >::cast(t_from, nullptr); auto from = detail::Cast_Helper<std::shared_ptr<From>>::cast(t_from, nullptr);
if (std::string(typeid(*from).name()).find("Assignable_Proxy_Function_Impl") != std::string::npos) { if (std::string(typeid(*from).name()).find("Assignable_Proxy_Function_Impl") != std::string::npos) {
return std::static_pointer_cast<To>(from); return std::static_pointer_cast<To>(from);
} }
@ -225,13 +177,11 @@ namespace chaiscript
#endif #endif
throw std::bad_cast(); throw std::bad_cast();
} }
}() }());
);
} }
} else { } else {
// Pull the reference out of the contained boxed value, which we know is the type we want // Pull the reference out of the contained boxed value, which we know is the type we want
if (t_from.is_const()) if (t_from.is_const()) {
{
const From &d = detail::Cast_Helper<const From &>::cast(t_from, nullptr); const From &d = detail::Cast_Helper<const From &>::cast(t_from, nullptr);
const To &data = dynamic_cast<const To &>(d); const To &data = dynamic_cast<const To &>(d);
return Boxed_Value(std::cref(data)); return Boxed_Value(std::cref(data));
@ -245,113 +195,80 @@ namespace chaiscript
throw chaiscript::exception::bad_boxed_dynamic_cast(t_from.get_type_info(), typeid(To), "Unknown dynamic_cast_conversion"); throw chaiscript::exception::bad_boxed_dynamic_cast(t_from.get_type_info(), typeid(To), "Unknown dynamic_cast_conversion");
} }
} }
}; };
template<typename Base, typename Derived> template<typename Base, typename Derived>
class Dynamic_Conversion_Impl : public Type_Conversion_Base class Dynamic_Conversion_Impl : public Type_Conversion_Base {
{
public: public:
Dynamic_Conversion_Impl() Dynamic_Conversion_Impl()
: Type_Conversion_Base(chaiscript::user_type<Base>(), chaiscript::user_type<Derived>()) : Type_Conversion_Base(chaiscript::user_type<Base>(), chaiscript::user_type<Derived>()) {
{
} }
Boxed_Value convert_down(const Boxed_Value &t_base) const override Boxed_Value convert_down(const Boxed_Value &t_base) const override { return Dynamic_Caster<Base, Derived>::cast(t_base); }
{
return Dynamic_Caster<Base, Derived>::cast(t_base);
}
Boxed_Value convert(const Boxed_Value &t_derived) const override Boxed_Value convert(const Boxed_Value &t_derived) const override { return Static_Caster<Derived, Base>::cast(t_derived); }
{
return Static_Caster<Derived, Base>::cast(t_derived);
}
}; };
template<typename Base, typename Derived> template<typename Base, typename Derived>
class Static_Conversion_Impl : public Type_Conversion_Base class Static_Conversion_Impl : public Type_Conversion_Base {
{
public: public:
Static_Conversion_Impl() Static_Conversion_Impl()
: Type_Conversion_Base(chaiscript::user_type<Base>(), chaiscript::user_type<Derived>()) : Type_Conversion_Base(chaiscript::user_type<Base>(), chaiscript::user_type<Derived>()) {
{
} }
Boxed_Value convert_down(const Boxed_Value &t_base) const override Boxed_Value convert_down(const Boxed_Value &t_base) const override {
{ throw chaiscript::exception::bad_boxed_dynamic_cast(t_base.get_type_info(),
throw chaiscript::exception::bad_boxed_dynamic_cast(t_base.get_type_info(), typeid(Derived), typeid(Derived),
"Unable to cast down inheritance hierarchy with non-polymorphic types"); "Unable to cast down inheritance hierarchy with non-polymorphic types");
} }
bool bidir() const noexcept override bool bidir() const noexcept override { return false; }
{
return false;
}
Boxed_Value convert(const Boxed_Value &t_derived) const override Boxed_Value convert(const Boxed_Value &t_derived) const override { return Static_Caster<Derived, Base>::cast(t_derived); }
{
return Static_Caster<Derived, Base>::cast(t_derived);
}
}; };
template<typename Callable> template<typename Callable>
class Type_Conversion_Impl : public Type_Conversion_Base class Type_Conversion_Impl : public Type_Conversion_Base {
{
public: public:
Type_Conversion_Impl(Type_Info t_from, Type_Info t_to, Callable t_func) Type_Conversion_Impl(Type_Info t_from, Type_Info t_to, Callable t_func)
: Type_Conversion_Base(t_to, t_from), : Type_Conversion_Base(t_to, t_from)
m_func(std::move(t_func)) , m_func(std::move(t_func)) {
{
} }
Boxed_Value convert_down(const Boxed_Value &) const override Boxed_Value convert_down(const Boxed_Value &) const override {
{
throw chaiscript::exception::bad_boxed_type_cast("No conversion exists"); throw chaiscript::exception::bad_boxed_type_cast("No conversion exists");
} }
Boxed_Value convert(const Boxed_Value &t_from) const override Boxed_Value convert(const Boxed_Value &t_from) const override {
{
/// \todo better handling of errors from the conversion function /// \todo better handling of errors from the conversion function
return m_func(t_from); return m_func(t_from);
} }
bool bidir() const noexcept override bool bidir() const noexcept override { return false; }
{
return false;
}
private: private:
Callable m_func; Callable m_func;
}; };
} } // namespace detail
class Type_Conversions class Type_Conversions {
{
public: public:
struct Conversion_Saves struct Conversion_Saves {
{
bool enabled = false; bool enabled = false;
std::vector<Boxed_Value> saves; std::vector<Boxed_Value> saves;
}; };
struct Less_Than struct Less_Than {
{ bool operator()(const std::type_info *t_lhs, const std::type_info *t_rhs) const noexcept {
bool operator()(const std::type_info *t_lhs, const std::type_info *t_rhs) const noexcept
{
return *t_lhs != *t_rhs && t_lhs->before(*t_rhs); return *t_lhs != *t_rhs && t_lhs->before(*t_rhs);
} }
}; };
Type_Conversions() Type_Conversions()
: m_mutex(), : m_mutex()
m_conversions(), , m_conversions()
m_convertableTypes(), , m_convertableTypes()
m_num_types(0) , m_num_types(0) {
{
} }
Type_Conversions(const Type_Conversions &t_other) = delete; Type_Conversions(const Type_Conversions &t_other) = delete;
@ -360,11 +277,9 @@ namespace chaiscript
Type_Conversions &operator=(const Type_Conversions &) = delete; Type_Conversions &operator=(const Type_Conversions &) = delete;
Type_Conversions &operator=(Type_Conversions &&) = delete; Type_Conversions &operator=(Type_Conversions &&) = delete;
const std::set<const std::type_info *, Less_Than> &thread_cache() const const std::set<const std::type_info *, Less_Than> &thread_cache() const {
{
auto &cache = *m_thread_cache; auto &cache = *m_thread_cache;
if (cache.size() != m_num_types) if (cache.size() != m_num_types) {
{
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex); chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
cache = m_convertableTypes; cache = m_convertableTypes;
} }
@ -372,13 +287,10 @@ namespace chaiscript
return cache; return cache;
} }
void add_conversion(const std::shared_ptr<detail::Type_Conversion_Base> &conversion) {
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); chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
if (find_bidir(conversion->to(), conversion->from()) != m_conversions.end()) { if (find_bidir(conversion->to(), conversion->from()) != m_conversions.end()) {
throw exception::conversion_error(conversion->to(), conversion->from(), throw exception::conversion_error(conversion->to(), conversion->from(), "Trying to re-insert an existing conversion!");
"Trying to re-insert an existing conversion!");
} }
m_conversions.insert(conversion); m_conversions.insert(conversion);
m_convertableTypes.insert({conversion->to().bare_type_info(), conversion->from().bare_type_info()}); m_convertableTypes.insert({conversion->to().bare_type_info(), conversion->from().bare_type_info()});
@ -386,23 +298,19 @@ namespace chaiscript
} }
template<typename T> template<typename T>
bool convertable_type() const noexcept bool convertable_type() const noexcept {
{
const auto type = user_type<T>().bare_type_info(); const auto type = user_type<T>().bare_type_info();
return thread_cache().count(type) != 0; return thread_cache().count(type) != 0;
} }
template<typename To, typename From> template<typename To, typename From>
bool converts() const noexcept bool converts() const noexcept {
{
return converts(user_type<To>(), user_type<From>()); return converts(user_type<To>(), user_type<From>());
} }
bool converts(const Type_Info &to, const Type_Info &from) const noexcept bool converts(const Type_Info &to, const Type_Info &from) const noexcept {
{
const auto &types = thread_cache(); const auto &types = thread_cache();
if (types.count(to.bare_type_info()) != 0 && types.count(from.bare_type_info()) != 0) if (types.count(to.bare_type_info()) != 0 && types.count(from.bare_type_info()) != 0) {
{
return has_conversion(to, from); return has_conversion(to, from);
} else { } else {
return false; return false;
@ -410,23 +318,21 @@ namespace chaiscript
} }
template<typename To> template<typename To>
Boxed_Value boxed_type_conversion(Conversion_Saves &t_saves, const Boxed_Value &from) const Boxed_Value boxed_type_conversion(Conversion_Saves &t_saves, const Boxed_Value &from) const {
{
return boxed_type_conversion(user_type<To>(), t_saves, from); return boxed_type_conversion(user_type<To>(), t_saves, from);
} }
template<typename From> template<typename From>
Boxed_Value boxed_type_down_conversion(Conversion_Saves &t_saves, const Boxed_Value &to) const Boxed_Value boxed_type_down_conversion(Conversion_Saves &t_saves, const Boxed_Value &to) const {
{
return boxed_type_down_conversion(user_type<From>(), t_saves, to); return boxed_type_down_conversion(user_type<From>(), t_saves, to);
} }
Boxed_Value boxed_type_conversion(const Type_Info &to, Conversion_Saves &t_saves, const Boxed_Value &from) const {
Boxed_Value boxed_type_conversion(const Type_Info &to, Conversion_Saves &t_saves, const Boxed_Value &from) const
{
try { try {
Boxed_Value ret = get_conversion(to, from.get_type_info())->convert(from); Boxed_Value ret = get_conversion(to, from.get_type_info())->convert(from);
if (t_saves.enabled) { t_saves.saves.push_back(ret); } if (t_saves.enabled) {
t_saves.saves.push_back(ret);
}
return ret; return ret;
} catch (const std::out_of_range &) { } catch (const std::out_of_range &) {
throw exception::bad_boxed_dynamic_cast(from.get_type_info(), *to.bare_type_info(), "No known conversion"); throw exception::bad_boxed_dynamic_cast(from.get_type_info(), *to.bare_type_info(), "No known conversion");
@ -435,11 +341,12 @@ namespace chaiscript
} }
} }
Boxed_Value boxed_type_down_conversion(const Type_Info &from, Conversion_Saves &t_saves, const Boxed_Value &to) const Boxed_Value boxed_type_down_conversion(const Type_Info &from, Conversion_Saves &t_saves, const Boxed_Value &to) const {
{
try { try {
Boxed_Value ret = get_conversion(to.get_type_info(), from)->convert_down(to); Boxed_Value ret = get_conversion(to.get_type_info(), from)->convert_down(to);
if (t_saves.enabled) { t_saves.saves.push_back(ret); } if (t_saves.enabled) {
t_saves.saves.push_back(ret);
}
return ret; return ret;
} catch (const std::out_of_range &) { } catch (const std::out_of_range &) {
throw exception::bad_boxed_dynamic_cast(to.get_type_info(), *from.bare_type_info(), "No known conversion"); throw exception::bad_boxed_dynamic_cast(to.get_type_info(), *from.bare_type_info(), "No known conversion");
@ -448,75 +355,57 @@ namespace chaiscript
} }
} }
static void enable_conversion_saves(Conversion_Saves &t_saves, bool t_val) static void enable_conversion_saves(Conversion_Saves &t_saves, bool t_val) { t_saves.enabled = t_val; }
{
t_saves.enabled = t_val;
}
std::vector<Boxed_Value> take_saves(Conversion_Saves &t_saves) std::vector<Boxed_Value> take_saves(Conversion_Saves &t_saves) {
{
std::vector<Boxed_Value> ret; std::vector<Boxed_Value> ret;
std::swap(ret, t_saves.saves); std::swap(ret, t_saves.saves);
return ret; return ret;
} }
bool has_conversion(const Type_Info &to, const Type_Info &from) const 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); chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
return find_bidir(to, from) != m_conversions.end(); return find_bidir(to, from) != m_conversions.end();
} }
std::shared_ptr<detail::Type_Conversion_Base> get_conversion(const Type_Info &to, const Type_Info &from) const 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); chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
const auto itr = find(to, from); const auto itr = find(to, from);
if (itr != m_conversions.end()) if (itr != m_conversions.end()) {
{
return *itr; return *itr;
} else { } else {
throw std::out_of_range(std::string("No such conversion exists from ") + from.bare_name() + " to " + to.bare_name()); throw std::out_of_range(std::string("No such conversion exists from ") + from.bare_name() + " to " + to.bare_name());
} }
} }
Conversion_Saves &conversion_saves() const noexcept { Conversion_Saves &conversion_saves() const noexcept { return *m_conversion_saves; }
return *m_conversion_saves;
}
private: private:
std::set<std::shared_ptr<detail::Type_Conversion_Base> >::const_iterator find_bidir( std::set<std::shared_ptr<detail::Type_Conversion_Base>>::const_iterator find_bidir(const Type_Info &to, const Type_Info &from) const {
const Type_Info &to, const Type_Info &from) const return std::find_if(m_conversions.begin(),
{ m_conversions.end(),
return std::find_if(m_conversions.begin(), m_conversions.end(), [&to, &from](const std::shared_ptr<detail::Type_Conversion_Base> &conversion) -> bool {
[&to, &from](const std::shared_ptr<detail::Type_Conversion_Base> &conversion) -> bool
{
return (conversion->to().bare_equal(to) && conversion->from().bare_equal(from)) return (conversion->to().bare_equal(to) && conversion->from().bare_equal(from))
|| (conversion->bidir() && conversion->from().bare_equal(to) && conversion->to().bare_equal(from)); || (conversion->bidir() && conversion->from().bare_equal(to) && conversion->to().bare_equal(from));
} });
);
} }
std::set<std::shared_ptr<detail::Type_Conversion_Base> >::const_iterator find( std::set<std::shared_ptr<detail::Type_Conversion_Base>>::const_iterator find(const Type_Info &to, const Type_Info &from) const {
const Type_Info &to, const Type_Info &from) const return std::find_if(m_conversions.begin(),
{ m_conversions.end(),
return std::find_if(m_conversions.begin(), m_conversions.end(), [&to, &from](const std::shared_ptr<detail::Type_Conversion_Base> &conversion) {
[&to, &from](const std::shared_ptr<detail::Type_Conversion_Base> &conversion)
{
return conversion->to().bare_equal(to) && conversion->from().bare_equal(from); return conversion->to().bare_equal(to) && conversion->from().bare_equal(from);
} });
);
} }
std::set<std::shared_ptr<detail::Type_Conversion_Base>> get_conversions() const 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); chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
return m_conversions; return m_conversions;
} }
mutable chaiscript::detail::threading::shared_mutex m_mutex; mutable chaiscript::detail::threading::shared_mutex m_mutex;
std::set<std::shared_ptr<detail::Type_Conversion_Base>> m_conversions; std::set<std::shared_ptr<detail::Type_Conversion_Base>> m_conversions;
std::set<const std::type_info *, Less_Than> m_convertableTypes; std::set<const std::type_info *, Less_Than> m_convertableTypes;
@ -525,27 +414,18 @@ namespace chaiscript
mutable chaiscript::detail::threading::Thread_Storage<Conversion_Saves> m_conversion_saves; mutable chaiscript::detail::threading::Thread_Storage<Conversion_Saves> m_conversion_saves;
}; };
class Type_Conversions_State class Type_Conversions_State {
{
public: public:
Type_Conversions_State(const Type_Conversions &t_conversions, Type_Conversions_State(const Type_Conversions &t_conversions, Type_Conversions::Conversion_Saves &t_saves)
Type_Conversions::Conversion_Saves &t_saves) : m_conversions(t_conversions)
: m_conversions(t_conversions), , m_saves(t_saves) {
m_saves(t_saves)
{
} }
const Type_Conversions *operator->() const noexcept { const Type_Conversions *operator->() const noexcept { return &m_conversions.get(); }
return &m_conversions.get();
}
const Type_Conversions *get() const noexcept { const Type_Conversions *get() const noexcept { return &m_conversions.get(); }
return &m_conversions.get();
}
Type_Conversions::Conversion_Saves &saves() const noexcept { Type_Conversions::Conversion_Saves &saves() const noexcept { return m_saves; }
return m_saves;
}
private: private:
std::reference_wrapper<const Type_Conversions> m_conversions; std::reference_wrapper<const Type_Conversions> m_conversions;
@ -576,53 +456,50 @@ namespace chaiscript
/// \endcode /// \endcode
/// ///
template<typename Base, typename Derived> template<typename Base, typename Derived>
Type_Conversion base_class() Type_Conversion base_class() {
{ // Can only be used with related polymorphic types
//Can only be used with related polymorphic types // may be expanded some day to support conversions other than child -> parent
//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_base_of<Base,Derived>::value, "Classes are not related by inheritance");
if constexpr(std::is_polymorphic<Base>::value && std::is_polymorphic<Derived>::value) { if constexpr (std::is_polymorphic<Base>::value && std::is_polymorphic<Derived>::value) {
return chaiscript::make_shared<detail::Type_Conversion_Base, detail::Dynamic_Conversion_Impl<Base, Derived>>(); return chaiscript::make_shared<detail::Type_Conversion_Base, detail::Dynamic_Conversion_Impl<Base, Derived>>();
} else { } else {
return chaiscript::make_shared<detail::Type_Conversion_Base, detail::Static_Conversion_Impl<Base, Derived>>(); return chaiscript::make_shared<detail::Type_Conversion_Base, detail::Static_Conversion_Impl<Base, Derived>>();
} }
} }
template<typename Callable> template<typename Callable>
Type_Conversion type_conversion(const Type_Info &t_from, const Type_Info &t_to, Type_Conversion type_conversion(const Type_Info &t_from, const Type_Info &t_to, const Callable &t_func) {
const Callable &t_func)
{
return chaiscript::make_shared<detail::Type_Conversion_Base, detail::Type_Conversion_Impl<Callable>>(t_from, t_to, t_func); return chaiscript::make_shared<detail::Type_Conversion_Base, detail::Type_Conversion_Impl<Callable>>(t_from, t_to, t_func);
} }
template<typename From, typename To, typename Callable> template<typename From, typename To, typename Callable>
Type_Conversion type_conversion(const Callable &t_function) Type_Conversion type_conversion(const Callable &t_function) {
{
auto func = [t_function](const Boxed_Value &t_bv) -> Boxed_Value { 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 // 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 chaiscript::Boxed_Value(t_function(detail::Cast_Helper<const From &>::cast(t_bv, nullptr)));
}; };
return chaiscript::make_shared<detail::Type_Conversion_Base, detail::Type_Conversion_Impl<decltype(func)>>(user_type<From>(), user_type<To>(), func); return chaiscript::make_shared<detail::Type_Conversion_Base, detail::Type_Conversion_Impl<decltype(func)>>(user_type<From>(),
user_type<To>(),
func);
} }
template<typename From, typename To> template<typename From, typename To>
Type_Conversion type_conversion() Type_Conversion type_conversion() {
{
static_assert(std::is_convertible<From, To>::value, "Types are not automatically convertible"); static_assert(std::is_convertible<From, To>::value, "Types are not automatically convertible");
auto func = [](const Boxed_Value &t_bv) -> Boxed_Value { 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 // not even attempting to call boxed_cast so that we don't get caught in some call recursion
return chaiscript::Boxed_Value(To(detail::Cast_Helper<From>::cast(t_bv, nullptr))); return chaiscript::Boxed_Value(To(detail::Cast_Helper<From>::cast(t_bv, nullptr)));
}; };
return chaiscript::make_shared<detail::Type_Conversion_Base, detail::Type_Conversion_Impl<decltype(func)>>(user_type<From>(), user_type<To>(), func); return chaiscript::make_shared<detail::Type_Conversion_Base, detail::Type_Conversion_Impl<decltype(func)>>(user_type<From>(),
user_type<To>(),
func);
} }
template<typename To> template<typename To>
Type_Conversion vector_conversion() Type_Conversion vector_conversion() {
{
auto func = [](const Boxed_Value &t_bv) -> Boxed_Value { auto func = [](const Boxed_Value &t_bv) -> Boxed_Value {
const std::vector<Boxed_Value> &from_vec = detail::Cast_Helper<const std::vector<Boxed_Value> &>::cast(t_bv, nullptr); const std::vector<Boxed_Value> &from_vec = detail::Cast_Helper<const std::vector<Boxed_Value> &>::cast(t_bv, nullptr);
@ -635,14 +512,16 @@ namespace chaiscript
return Boxed_Value(std::move(vec)); return Boxed_Value(std::move(vec));
}; };
return chaiscript::make_shared<detail::Type_Conversion_Base, detail::Type_Conversion_Impl<decltype(func)>>(user_type<std::vector<Boxed_Value>>(), user_type<To>(), func); return chaiscript::make_shared<detail::Type_Conversion_Base, detail::Type_Conversion_Impl<decltype(func)>>(user_type<std::vector<Boxed_Value>>(),
user_type<To>(),
func);
} }
template<typename To> template<typename To>
Type_Conversion map_conversion() Type_Conversion map_conversion() {
{
auto func = [](const Boxed_Value &t_bv) -> Boxed_Value { auto func = [](const Boxed_Value &t_bv) -> Boxed_Value {
const std::map<std::string, Boxed_Value> &from_map = detail::Cast_Helper<const std::map<std::string, Boxed_Value> &>::cast(t_bv, nullptr); const std::map<std::string, Boxed_Value> &from_map
= detail::Cast_Helper<const std::map<std::string, Boxed_Value> &>::cast(t_bv, nullptr);
To map; To map;
for (const std::pair<const std::string, Boxed_Value> &p : from_map) { for (const std::pair<const std::string, Boxed_Value> &p : from_map) {
@ -652,9 +531,9 @@ namespace chaiscript
return Boxed_Value(std::move(map)); return Boxed_Value(std::move(map));
}; };
return chaiscript::make_shared<detail::Type_Conversion_Base, detail::Type_Conversion_Impl<decltype(func)>>(user_type<std::map<std::string, Boxed_Value>>(), user_type<To>(), func); return chaiscript::make_shared<detail::Type_Conversion_Base, detail::Type_Conversion_Impl<decltype(func)>>(
user_type<std::map<std::string, Boxed_Value>>(), user_type<To>(), func);
} }
} } // namespace chaiscript
#endif #endif

View File

@ -7,81 +7,58 @@
// This is an open source non-commercial project. Dear PVS-Studio, please check it. // This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com // PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_TYPE_INFO_HPP_ #ifndef CHAISCRIPT_TYPE_INFO_HPP_
#define CHAISCRIPT_TYPE_INFO_HPP_ #define CHAISCRIPT_TYPE_INFO_HPP_
#include <memory> #include <memory>
#include <string>
#include <type_traits> #include <type_traits>
#include <typeinfo> #include <typeinfo>
#include <string>
namespace chaiscript namespace chaiscript {
{ namespace detail {
namespace detail
{
template<typename T> template<typename T>
struct Bare_Type struct Bare_Type {
{
using type = typename std::remove_cv<typename std::remove_pointer<typename std::remove_reference<T>::type>::type>::type; using type = typename std::remove_cv<typename std::remove_pointer<typename std::remove_reference<T>::type>::type>::type;
}; };
} } // namespace detail
/// \brief Compile time deduced information about a type /// \brief Compile time deduced information about a type
class Type_Info class Type_Info {
{
public: public:
constexpr Type_Info(const bool t_is_const, const bool t_is_reference, const bool t_is_pointer, const bool t_is_void, constexpr Type_Info(const bool t_is_const,
const bool t_is_arithmetic, const std::type_info *t_ti, const std::type_info *t_bare_ti) noexcept const bool t_is_reference,
: m_type_info(t_ti), m_bare_type_info(t_bare_ti), const bool t_is_pointer,
m_flags((static_cast<unsigned int>(t_is_const) << is_const_flag) const bool t_is_void,
+ (static_cast<unsigned int>(t_is_reference) << is_reference_flag) const bool t_is_arithmetic,
+ (static_cast<unsigned int>(t_is_pointer) << is_pointer_flag) const std::type_info *t_ti,
+ (static_cast<unsigned int>(t_is_void) << is_void_flag) const std::type_info *t_bare_ti) noexcept
+ (static_cast<unsigned int>(t_is_arithmetic) << is_arithmetic_flag)) : m_type_info(t_ti)
{ , m_bare_type_info(t_bare_ti)
, m_flags((static_cast<unsigned int>(t_is_const) << is_const_flag) + (static_cast<unsigned int>(t_is_reference) << is_reference_flag)
+ (static_cast<unsigned int>(t_is_pointer) << is_pointer_flag) + (static_cast<unsigned int>(t_is_void) << is_void_flag)
+ (static_cast<unsigned int>(t_is_arithmetic) << is_arithmetic_flag)) {
} }
constexpr Type_Info() noexcept = default; constexpr Type_Info() noexcept = default;
bool operator<(const Type_Info &ti) const noexcept bool operator<(const Type_Info &ti) const noexcept { return m_type_info->before(*ti.m_type_info); }
{
return m_type_info->before(*ti.m_type_info); constexpr bool operator!=(const Type_Info &ti) const noexcept { return !(operator==(ti)); }
constexpr bool operator!=(const std::type_info &ti) const noexcept { return !(operator==(ti)); }
constexpr bool operator==(const Type_Info &ti) const noexcept {
return ti.m_type_info == m_type_info || *ti.m_type_info == *m_type_info;
} }
constexpr bool operator!=(const Type_Info &ti) const noexcept constexpr bool operator==(const std::type_info &ti) const noexcept { return !is_undef() && (*m_type_info) == ti; }
{
return !(operator==(ti)); constexpr bool bare_equal(const Type_Info &ti) const noexcept {
return ti.m_bare_type_info == m_bare_type_info || *ti.m_bare_type_info == *m_bare_type_info;
} }
constexpr bool operator!=(const std::type_info &ti) const noexcept constexpr bool bare_equal_type_info(const std::type_info &ti) const noexcept { return !is_undef() && (*m_bare_type_info) == ti; }
{
return !(operator==(ti));
}
constexpr bool operator==(const Type_Info &ti) const noexcept
{
return ti.m_type_info == m_type_info
|| *ti.m_type_info == *m_type_info;
}
constexpr bool operator==(const std::type_info &ti) const noexcept
{
return !is_undef() && (*m_type_info) == ti;
}
constexpr bool bare_equal(const Type_Info &ti) const noexcept
{
return ti.m_bare_type_info == m_bare_type_info
|| *ti.m_bare_type_info == *m_bare_type_info;
}
constexpr bool bare_equal_type_info(const std::type_info &ti) const noexcept
{
return !is_undef() && (*m_bare_type_info) == ti;
}
constexpr bool is_const() const noexcept { return (m_flags & (1 << is_const_flag)) != 0; } constexpr bool is_const() const noexcept { return (m_flags & (1 << is_const_flag)) != 0; }
constexpr bool is_reference() const noexcept { return (m_flags & (1 << is_reference_flag)) != 0; } constexpr bool is_reference() const noexcept { return (m_flags & (1 << is_reference_flag)) != 0; }
@ -90,33 +67,27 @@ namespace chaiscript
constexpr bool is_undef() const noexcept { return (m_flags & (1 << is_undef_flag)) != 0; } constexpr bool is_undef() const noexcept { return (m_flags & (1 << is_undef_flag)) != 0; }
constexpr bool is_pointer() const noexcept { return (m_flags & (1 << is_pointer_flag)) != 0; } constexpr bool is_pointer() const noexcept { return (m_flags & (1 << is_pointer_flag)) != 0; }
const char * name() const noexcept const char *name() const noexcept {
{ if (!is_undef()) {
if (!is_undef())
{
return m_type_info->name(); return m_type_info->name();
} else { } else {
return ""; return "";
} }
} }
const char * bare_name() const noexcept const char *bare_name() const noexcept {
{ if (!is_undef()) {
if (!is_undef())
{
return m_bare_type_info->name(); return m_bare_type_info->name();
} else { } else {
return ""; return "";
} }
} }
constexpr const std::type_info *bare_type_info() const noexcept constexpr const std::type_info *bare_type_info() const noexcept { return m_bare_type_info; }
{
return m_bare_type_info;
}
private: private:
struct Unknown_Type {}; struct Unknown_Type {
};
const std::type_info *m_type_info = &typeid(Unknown_Type); const std::type_info *m_type_info = &typeid(Unknown_Type);
const std::type_info *m_bare_type_info = &typeid(Unknown_Type); const std::type_info *m_bare_type_info = &typeid(Unknown_Type);
@ -129,16 +100,14 @@ namespace chaiscript
unsigned int m_flags = (1 << is_undef_flag); unsigned int m_flags = (1 << is_undef_flag);
}; };
namespace detail namespace detail {
{
/// Helper used to create a Type_Info object /// Helper used to create a Type_Info object
template<typename T> template<typename T>
struct Get_Type_Info struct Get_Type_Info {
{ constexpr static Type_Info get() noexcept {
constexpr static Type_Info get() noexcept
{
return Type_Info(std::is_const<typename std::remove_pointer<typename std::remove_reference<T>::type>::type>::value, return Type_Info(std::is_const<typename std::remove_pointer<typename std::remove_reference<T>::type>::type>::value,
std::is_reference<T>::value, std::is_pointer<T>::value, std::is_reference<T>::value,
std::is_pointer<T>::value,
std::is_void<T>::value, std::is_void<T>::value,
(std::is_arithmetic<T>::value || std::is_arithmetic<typename std::remove_reference<T>::type>::value) (std::is_arithmetic<T>::value || std::is_arithmetic<typename std::remove_reference<T>::type>::value)
&& !std::is_same<typename std::remove_const<typename std::remove_reference<T>::type>::type, bool>::value, && !std::is_same<typename std::remove_const<typename std::remove_reference<T>::type>::type, bool>::value,
@ -148,63 +117,66 @@ namespace chaiscript
}; };
template<typename T> template<typename T>
struct Get_Type_Info<std::shared_ptr<T> > struct Get_Type_Info<std::shared_ptr<T>> {
{ constexpr static Type_Info get() noexcept {
constexpr static Type_Info get() noexcept return Type_Info(std::is_const<T>::value,
{ std::is_reference<T>::value,
return Type_Info(std::is_const<T>::value, std::is_reference<T>::value, std::is_pointer<T>::value, std::is_pointer<T>::value,
std::is_void<T>::value, std::is_void<T>::value,
std::is_arithmetic<T>::value && !std::is_same<typename std::remove_const<typename std::remove_reference<T>::type>::type, bool>::value, std::is_arithmetic<T>::value
&typeid(std::shared_ptr<T> ), && !std::is_same<typename std::remove_const<typename std::remove_reference<T>::type>::type, bool>::value,
&typeid(std::shared_ptr<T>),
&typeid(typename Bare_Type<T>::type)); &typeid(typename Bare_Type<T>::type));
} }
}; };
template<typename T> template<typename T>
struct Get_Type_Info<std::shared_ptr<T> &> : Get_Type_Info<std::shared_ptr<T>> struct Get_Type_Info<std::shared_ptr<T> &> : Get_Type_Info<std::shared_ptr<T>> {
{
}; };
template<typename T> template<typename T>
struct Get_Type_Info<const std::shared_ptr<T> &> struct Get_Type_Info<const std::shared_ptr<T> &> {
{ constexpr static Type_Info get() noexcept {
constexpr static Type_Info get() noexcept return Type_Info(std::is_const<T>::value,
{ std::is_reference<T>::value,
return Type_Info(std::is_const<T>::value, std::is_reference<T>::value, std::is_pointer<T>::value, std::is_pointer<T>::value,
std::is_void<T>::value, std::is_void<T>::value,
std::is_arithmetic<T>::value && !std::is_same<typename std::remove_const<typename std::remove_reference<T>::type>::type, bool>::value, std::is_arithmetic<T>::value
&& !std::is_same<typename std::remove_const<typename std::remove_reference<T>::type>::type, bool>::value,
&typeid(const std::shared_ptr<T> &), &typeid(const std::shared_ptr<T> &),
&typeid(typename Bare_Type<T>::type)); &typeid(typename Bare_Type<T>::type));
} }
}; };
template<typename T> template<typename T>
struct Get_Type_Info<std::reference_wrapper<T> > struct Get_Type_Info<std::reference_wrapper<T>> {
{ constexpr static Type_Info get() noexcept {
constexpr static Type_Info get() noexcept return Type_Info(std::is_const<T>::value,
{ std::is_reference<T>::value,
return Type_Info(std::is_const<T>::value, std::is_reference<T>::value, std::is_pointer<T>::value, std::is_pointer<T>::value,
std::is_void<T>::value, std::is_void<T>::value,
std::is_arithmetic<T>::value && !std::is_same<typename std::remove_const<typename std::remove_reference<T>::type>::type, bool>::value, std::is_arithmetic<T>::value
&typeid(std::reference_wrapper<T> ), && !std::is_same<typename std::remove_const<typename std::remove_reference<T>::type>::type, bool>::value,
&typeid(std::reference_wrapper<T>),
&typeid(typename Bare_Type<T>::type)); &typeid(typename Bare_Type<T>::type));
} }
}; };
template<typename T> template<typename T>
struct Get_Type_Info<const std::reference_wrapper<T> &> struct Get_Type_Info<const std::reference_wrapper<T> &> {
{ constexpr static Type_Info get() noexcept {
constexpr static Type_Info get() noexcept return Type_Info(std::is_const<T>::value,
{ std::is_reference<T>::value,
return Type_Info(std::is_const<T>::value, std::is_reference<T>::value, std::is_pointer<T>::value, std::is_pointer<T>::value,
std::is_void<T>::value, std::is_void<T>::value,
std::is_arithmetic<T>::value && !std::is_same<typename std::remove_const<typename std::remove_reference<T>::type>::type, bool>::value, std::is_arithmetic<T>::value
&& !std::is_same<typename std::remove_const<typename std::remove_reference<T>::type>::type, bool>::value,
&typeid(const std::reference_wrapper<T> &), &typeid(const std::reference_wrapper<T> &),
&typeid(typename Bare_Type<T>::type)); &typeid(typename Bare_Type<T>::type));
} }
}; };
} } // namespace detail
/// \brief Creates a Type_Info object representing the type passed in /// \brief Creates a Type_Info object representing the type passed in
/// \tparam T Type of object to get a Type_Info for, derived from the passed in parameter /// \tparam T Type of object to get a Type_Info for, derived from the passed in parameter
@ -216,12 +188,10 @@ namespace chaiscript
/// chaiscript::Type_Info ti = chaiscript::user_type(i); /// chaiscript::Type_Info ti = chaiscript::user_type(i);
/// \endcode /// \endcode
template<typename T> template<typename T>
constexpr Type_Info user_type(const T &/*t*/) noexcept constexpr Type_Info user_type(const T & /*t*/) noexcept {
{
return detail::Get_Type_Info<T>::get(); return detail::Get_Type_Info<T>::get();
} }
/// \brief Creates a Type_Info object representing the templated type /// \brief Creates a Type_Info object representing the templated type
/// \tparam T Type of object to get a Type_Info for /// \tparam T Type of object to get a Type_Info for
/// \return Type_Info for T /// \return Type_Info for T
@ -231,12 +201,10 @@ namespace chaiscript
/// chaiscript::Type_Info ti = chaiscript::user_type<int>(); /// chaiscript::Type_Info ti = chaiscript::user_type<int>();
/// \endcode /// \endcode
template<typename T> template<typename T>
constexpr Type_Info user_type() noexcept constexpr Type_Info user_type() noexcept {
{
return detail::Get_Type_Info<T>::get(); return detail::Get_Type_Info<T>::get();
} }
} } // namespace chaiscript
#endif #endif

View File

@ -7,7 +7,6 @@
// This is an open source non-commercial project. Dear PVS-Studio, please check it. // This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com // PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_ALGEBRAIC_HPP_ #ifndef CHAISCRIPT_ALGEBRAIC_HPP_
#define CHAISCRIPT_ALGEBRAIC_HPP_ #define CHAISCRIPT_ALGEBRAIC_HPP_
@ -15,43 +14,51 @@
#include <string> #include <string>
namespace chaiscript namespace chaiscript {
{
struct Operators { struct Operators {
enum class Opers enum class Opers {
{ equals,
equals, less_than, greater_than, less_than_equal, greater_than_equal, not_equal, less_than,
assign, pre_increment, pre_decrement, assign_product, assign_sum, greater_than,
assign_quotient, assign_difference, less_than_equal,
assign_bitwise_and, assign_bitwise_or, assign_shift_left, assign_shift_right, greater_than_equal,
assign_remainder, assign_bitwise_xor, not_equal,
shift_left, shift_right, remainder, bitwise_and, bitwise_or, bitwise_xor, bitwise_complement, assign,
sum, quotient, product, difference, unary_plus, unary_minus, pre_increment,
pre_decrement,
assign_product,
assign_sum,
assign_quotient,
assign_difference,
assign_bitwise_and,
assign_bitwise_or,
assign_shift_left,
assign_shift_right,
assign_remainder,
assign_bitwise_xor,
shift_left,
shift_right,
remainder,
bitwise_and,
bitwise_or,
bitwise_xor,
bitwise_complement,
sum,
quotient,
product,
difference,
unary_plus,
unary_minus,
invalid invalid
}; };
constexpr static const char *to_string(Opers t_oper) noexcept { constexpr static const char *to_string(Opers t_oper) noexcept {
constexpr const char *opers[] = { constexpr const char *opers[]
"", = {"", "==", "<", ">", "<=", ">=", "!=", "", "=", "++", "--", "*=", "+=", "/=", "-=", "", "&=", "|=", "<<=", ">>=", "%=", "^=", "", "<<", ">>", "%", "&", "|", "^", "~", "", "+", "/", "*", "-", "+", "-", ""};
"==", "<", ">", "<=", ">=", "!=",
"",
"=", "++", "--", "*=", "+=",
"/=", "-=",
"",
"&=", "|=", "<<=", ">>=",
"%=", "^=",
"",
"<<", ">>", "%", "&", "|", "^", "~",
"",
"+", "/", "*", "-", "+", "-",
""
};
return opers[static_cast<int>(t_oper)]; return opers[static_cast<int>(t_oper)];
} }
constexpr static Opers to_operator(std::string_view t_str, bool t_is_unary = false) noexcept constexpr static Opers to_operator(std::string_view t_str, bool t_is_unary = false) noexcept {
{
#ifdef CHAISCRIPT_MSVC #ifdef CHAISCRIPT_MSVC
#pragma warning(push) #pragma warning(push)
#pragma warning(disable : 4307) #pragma warning(disable : 4307)
@ -59,45 +66,102 @@ namespace chaiscript
const auto op_hash = utility::hash(t_str); const auto op_hash = utility::hash(t_str);
switch (op_hash) { switch (op_hash) {
case utility::hash("=="): { return Opers::equals; } case utility::hash("=="): {
case utility::hash("<"): { return Opers::less_than; } return Opers::equals;
case utility::hash(">"): { return Opers::greater_than; } }
case utility::hash("<="): { return Opers::less_than_equal; } case utility::hash("<"): {
case utility::hash(">="): { return Opers::greater_than_equal; } return Opers::less_than;
case utility::hash("!="): { return Opers::not_equal; } }
case utility::hash("="): { return Opers::assign; } case utility::hash(">"): {
case utility::hash("++"): { return Opers::pre_increment; } return Opers::greater_than;
case utility::hash("--"): { return Opers::pre_decrement; } }
case utility::hash("*="): { return Opers::assign_product; } case utility::hash("<="): {
case utility::hash("+="): { return Opers::assign_sum; } return Opers::less_than_equal;
case utility::hash("-="): { return Opers::assign_difference; } }
case utility::hash("&="): { return Opers::assign_bitwise_and; } case utility::hash(">="): {
case utility::hash("|="): { return Opers::assign_bitwise_or; } return Opers::greater_than_equal;
case utility::hash("<<="): { return Opers::assign_shift_left; } }
case utility::hash(">>="): { return Opers::assign_shift_right; } case utility::hash("!="): {
case utility::hash("%="): { return Opers::assign_remainder; } return Opers::not_equal;
case utility::hash("^="): { return Opers::assign_bitwise_xor; } }
case utility::hash("<<"): { return Opers::shift_left; } case utility::hash("="): {
case utility::hash(">>"): { return Opers::shift_right; } return Opers::assign;
case utility::hash("%"): { return Opers::remainder; } }
case utility::hash("&"): { return Opers::bitwise_and; } case utility::hash("++"): {
case utility::hash("|"): { return Opers::bitwise_or; } return Opers::pre_increment;
case utility::hash("^"): { return Opers::bitwise_xor; } }
case utility::hash("~"): { return Opers::bitwise_complement; } case utility::hash("--"): {
case utility::hash("+"): { return t_is_unary ? Opers::unary_plus : Opers::sum; } return Opers::pre_decrement;
case utility::hash("-"): { return t_is_unary ? Opers::unary_minus : Opers::difference; } }
case utility::hash("/"): { return Opers::quotient; } case utility::hash("*="): {
case utility::hash("*"): { return Opers::product; } return Opers::assign_product;
default: { return Opers::invalid; } }
case utility::hash("+="): {
return Opers::assign_sum;
}
case utility::hash("-="): {
return Opers::assign_difference;
}
case utility::hash("&="): {
return Opers::assign_bitwise_and;
}
case utility::hash("|="): {
return Opers::assign_bitwise_or;
}
case utility::hash("<<="): {
return Opers::assign_shift_left;
}
case utility::hash(">>="): {
return Opers::assign_shift_right;
}
case utility::hash("%="): {
return Opers::assign_remainder;
}
case utility::hash("^="): {
return Opers::assign_bitwise_xor;
}
case utility::hash("<<"): {
return Opers::shift_left;
}
case utility::hash(">>"): {
return Opers::shift_right;
}
case utility::hash("%"): {
return Opers::remainder;
}
case utility::hash("&"): {
return Opers::bitwise_and;
}
case utility::hash("|"): {
return Opers::bitwise_or;
}
case utility::hash("^"): {
return Opers::bitwise_xor;
}
case utility::hash("~"): {
return Opers::bitwise_complement;
}
case utility::hash("+"): {
return t_is_unary ? Opers::unary_plus : Opers::sum;
}
case utility::hash("-"): {
return t_is_unary ? Opers::unary_minus : Opers::difference;
}
case utility::hash("/"): {
return Opers::quotient;
}
case utility::hash("*"): {
return Opers::product;
}
default: {
return Opers::invalid;
}
} }
#ifdef CHAISCRIPT_MSVC #ifdef CHAISCRIPT_MSVC
#pragma warning(pop) #pragma warning(pop)
#endif #endif
} }
}; };
} } // namespace chaiscript
#endif /* _CHAISCRIPT_ALGEBRAIC_HPP */ #endif /* _CHAISCRIPT_ALGEBRAIC_HPP */

View File

@ -7,7 +7,6 @@
// This is an open source non-commercial project. Dear PVS-Studio, please check it. // This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com // PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_COMMON_HPP_ #ifndef CHAISCRIPT_COMMON_HPP_
#define CHAISCRIPT_COMMON_HPP_ #define CHAISCRIPT_COMMON_HPP_
@ -26,53 +25,26 @@
#include <unordered_set> #include <unordered_set>
namespace chaiscript { namespace chaiscript {
struct AST_Node; struct AST_Node;
} // namespace chaiscript } // namespace chaiscript
namespace chaiscript namespace chaiscript {
{
struct Name_Validator { struct Name_Validator {
template<typename T> template<typename T>
static bool is_reserved_word(const T &s) noexcept static bool is_reserved_word(const T &s) noexcept {
{ const static std::unordered_set<std::uint32_t>
const static std::unordered_set<std::uint32_t> words{ words{utility::hash("def"), utility::hash("fun"), utility::hash("while"), utility::hash("for"), utility::hash("if"), utility::hash("else"), utility::hash("&&"), utility::hash("||"), utility::hash(","), utility::hash("auto"), utility::hash("return"), utility::hash("break"), utility::hash("true"), utility::hash("false"), utility::hash("class"), utility::hash("attr"), utility::hash("var"), utility::hash("global"), utility::hash("GLOBAL"), utility::hash("_"), utility::hash("__LINE__"), utility::hash("__FILE__"), utility::hash("__FUNC__"), utility::hash("__CLASS__")};
utility::hash("def"),
utility::hash("fun"),
utility::hash("while"),
utility::hash("for"),
utility::hash("if"),
utility::hash("else"),
utility::hash("&&"),
utility::hash("||"),
utility::hash(","),
utility::hash("auto"),
utility::hash("return"),
utility::hash("break"),
utility::hash("true"),
utility::hash("false"),
utility::hash("class"),
utility::hash("attr"),
utility::hash("var"),
utility::hash("global"),
utility::hash("GLOBAL"),
utility::hash("_"),
utility::hash("__LINE__"),
utility::hash("__FILE__"),
utility::hash("__FUNC__"),
utility::hash("__CLASS__")};
return words.count(utility::hash(s)) == 1; return words.count(utility::hash(s)) == 1;
} }
template<typename T> template<typename T>
static bool valid_object_name(const T &name) noexcept static bool valid_object_name(const T &name) noexcept {
{
return name.find("::") == std::string::npos && !is_reserved_word(name); return name.find("::") == std::string::npos && !is_reserved_word(name);
} }
template<typename T> template<typename T>
static void validate_object_name(const T &name) static void validate_object_name(const T &name) {
{
if (is_reserved_word(name)) { if (is_reserved_word(name)) {
throw exception::reserved_word_error(std::string(name)); throw exception::reserved_word_error(std::string(name));
} }
@ -86,32 +58,78 @@ namespace chaiscript
/// Signature of module entry point that all binary loadable modules must implement. /// Signature of module entry point that all binary loadable modules must implement.
using Create_Module_Func = ModulePtr (*)(); using Create_Module_Func = ModulePtr (*)();
/// Types of AST nodes available to the parser and eval /// Types of AST nodes available to the parser and eval
enum class AST_Node_Type { Id, Fun_Call, Unused_Return_Fun_Call, Arg_List, Equation, Var_Decl, Assign_Decl, enum class AST_Node_Type {
Array_Call, Dot_Access, Id,
Lambda, Block, Scopeless_Block, Def, While, If, For, Ranged_For, Inline_Array, Inline_Map, Return, File, Prefix, Break, Continue, Map_Pair, Value_Range, Fun_Call,
Inline_Range, Try, Catch, Finally, Method, Attr_Decl, Unused_Return_Fun_Call,
Logical_And, Logical_Or, Reference, Switch, Case, Default, Noop, Class, Binary, Arg, Global_Decl, Constant, Compiled Arg_List,
Equation,
Var_Decl,
Assign_Decl,
Array_Call,
Dot_Access,
Lambda,
Block,
Scopeless_Block,
Def,
While,
If,
For,
Ranged_For,
Inline_Array,
Inline_Map,
Return,
File,
Prefix,
Break,
Continue,
Map_Pair,
Value_Range,
Inline_Range,
Try,
Catch,
Finally,
Method,
Attr_Decl,
Logical_And,
Logical_Or,
Reference,
Switch,
Case,
Default,
Noop,
Class,
Binary,
Arg,
Global_Decl,
Constant,
Compiled
}; };
enum class Operator_Precedence { Ternary_Cond, Logical_Or, enum class Operator_Precedence {
Logical_And, Bitwise_Or, Bitwise_Xor, Bitwise_And, Ternary_Cond,
Equality, Comparison, Shift, Addition, Multiplication, Prefix }; Logical_Or,
Logical_And,
Bitwise_Or,
Bitwise_Xor,
Bitwise_And,
Equality,
Comparison,
Shift,
Addition,
Multiplication,
Prefix
};
namespace namespace {
{
/// Helper lookup to get the name of each node type /// Helper lookup to get the name of each node type
constexpr const char *ast_node_type_to_string(AST_Node_Type ast_node_type) noexcept { constexpr const char *ast_node_type_to_string(AST_Node_Type ast_node_type) noexcept {
constexpr const char * const ast_node_types[] = { "Id", "Fun_Call", "Unused_Return_Fun_Call", "Arg_List", "Equation", "Var_Decl", "Assign_Decl", constexpr const char *const ast_node_types[] = {"Id", "Fun_Call", "Unused_Return_Fun_Call", "Arg_List", "Equation", "Var_Decl", "Assign_Decl", "Array_Call", "Dot_Access", "Lambda", "Block", "Scopeless_Block", "Def", "While", "If", "For", "Ranged_For", "Inline_Array", "Inline_Map", "Return", "File", "Prefix", "Break", "Continue", "Map_Pair", "Value_Range", "Inline_Range", "Try", "Catch", "Finally", "Method", "Attr_Decl", "Logical_And", "Logical_Or", "Reference", "Switch", "Case", "Default", "Noop", "Class", "Binary", "Arg", "Global_Decl", "Constant", "Compiled"};
"Array_Call", "Dot_Access",
"Lambda", "Block", "Scopeless_Block", "Def", "While", "If", "For", "Ranged_For", "Inline_Array", "Inline_Map", "Return", "File", "Prefix", "Break", "Continue", "Map_Pair", "Value_Range",
"Inline_Range", "Try", "Catch", "Finally", "Method", "Attr_Decl",
"Logical_And", "Logical_Or", "Reference", "Switch", "Case", "Default", "Noop", "Class", "Binary", "Arg", "Global_Decl", "Constant", "Compiled"};
return ast_node_types[static_cast<int>(ast_node_type)]; return ast_node_types[static_cast<int>(ast_node_type)];
} }
} } // namespace
/// \brief Convenience type for file positions /// \brief Convenience type for file positions
struct File_Position { struct File_Position {
@ -119,64 +137,57 @@ namespace chaiscript
int column = 0; int column = 0;
constexpr File_Position(int t_file_line, int t_file_column) noexcept constexpr File_Position(int t_file_line, int t_file_column) noexcept
: line(t_file_line), column(t_file_column) { } : line(t_file_line)
, column(t_file_column) {
}
constexpr File_Position() noexcept = default; constexpr File_Position() noexcept = default;
}; };
struct Parse_Location { struct Parse_Location {
Parse_Location(std::string t_fname="", const int t_start_line=0, const int t_start_col=0, Parse_Location(std::string t_fname = "", const int t_start_line = 0, const int t_start_col = 0, const int t_end_line = 0, const int t_end_col = 0)
const int t_end_line=0, const int t_end_col=0) : start(t_start_line, t_start_col)
: start(t_start_line, t_start_col), , end(t_end_line, t_end_col)
end(t_end_line, t_end_col), , filename(std::make_shared<std::string>(std::move(t_fname))) {
filename(std::make_shared<std::string>(std::move(t_fname)))
{
} }
Parse_Location(std::shared_ptr<std::string> t_fname, const int t_start_line=0, const int t_start_col=0, Parse_Location(std::shared_ptr<std::string> t_fname,
const int t_end_line=0, const int t_end_col=0) const int t_start_line = 0,
: start(t_start_line, t_start_col), const int t_start_col = 0,
end(t_end_line, t_end_col), const int t_end_line = 0,
filename(std::move(t_fname)) const int t_end_col = 0)
{ : start(t_start_line, t_start_col)
, end(t_end_line, t_end_col)
, filename(std::move(t_fname)) {
} }
File_Position start; File_Position start;
File_Position end; File_Position end;
std::shared_ptr<std::string> filename; std::shared_ptr<std::string> filename;
}; };
/// \brief Typedef for pointers to AST_Node objects. Used in building of the AST_Node tree /// \brief Typedef for pointers to AST_Node objects. Used in building of the AST_Node tree
using AST_NodePtr = std::unique_ptr<AST_Node>; using AST_NodePtr = std::unique_ptr<AST_Node>;
using AST_NodePtr_Const = std::unique_ptr<const AST_Node>; using AST_NodePtr_Const = std::unique_ptr<const AST_Node>;
struct AST_Node_Trace; struct AST_Node_Trace;
/// \brief Classes which may be thrown during error cases when ChaiScript is executing. /// \brief Classes which may be thrown during error cases when ChaiScript is executing.
namespace exception namespace exception {
{
/// \brief Thrown if an error occurs while attempting to load a binary module /// \brief Thrown if an error occurs while attempting to load a binary module
struct load_module_error : std::runtime_error struct load_module_error : std::runtime_error {
{
explicit load_module_error(const std::string &t_reason) explicit load_module_error(const std::string &t_reason)
: std::runtime_error(t_reason) : std::runtime_error(t_reason) {
{
} }
load_module_error(const std::string &t_name, const std::vector<load_module_error> &t_errors) load_module_error(const std::string &t_name, const std::vector<load_module_error> &t_errors)
: std::runtime_error(format_error(t_name, t_errors)) : std::runtime_error(format_error(t_name, t_errors)) {
{
} }
load_module_error(const load_module_error &) = default; load_module_error(const load_module_error &) = default;
~load_module_error() noexcept override = default; ~load_module_error() noexcept override = default;
static std::string format_error(const std::string &t_name, const std::vector<load_module_error> &t_errors) static std::string format_error(const std::string &t_name, const std::vector<load_module_error> &t_errors) {
{
std::stringstream ss; std::stringstream ss;
ss << "Error loading module '" << t_name << "'\n" ss << "Error loading module '" << t_name << "'\n"
<< " The following locations were searched:\n"; << " The following locations were searched:\n";
@ -189,7 +200,6 @@ namespace chaiscript
} }
}; };
/// Errors generated during parsing or evaluation /// Errors generated during parsing or evaluation
struct eval_error : std::runtime_error { struct eval_error : std::runtime_error {
std::string reason; std::string reason;
@ -198,48 +208,55 @@ namespace chaiscript
std::string detail; std::string detail;
std::vector<AST_Node_Trace> call_stack; std::vector<AST_Node_Trace> call_stack;
eval_error(const std::string &t_why, const File_Position &t_where, const std::string &t_fname, eval_error(const std::string &t_why,
const std::vector<Boxed_Value> &t_parameters, const std::vector<chaiscript::Const_Proxy_Function> &t_functions, const File_Position &t_where,
const std::string &t_fname,
const std::vector<Boxed_Value> &t_parameters,
const std::vector<chaiscript::Const_Proxy_Function> &t_functions,
bool t_dot_notation, bool t_dot_notation,
const chaiscript::detail::Dispatch_Engine &t_ss) noexcept : const chaiscript::detail::Dispatch_Engine &t_ss) noexcept
std::runtime_error(format(t_why, t_where, t_fname, t_parameters, t_dot_notation, t_ss)), : std::runtime_error(format(t_why, t_where, t_fname, t_parameters, t_dot_notation, t_ss))
reason(t_why), start_position(t_where), filename(t_fname), detail(format_detail(t_functions, t_dot_notation, t_ss)) , reason(t_why)
{} , start_position(t_where)
, filename(t_fname)
, detail(format_detail(t_functions, t_dot_notation, t_ss)) {
}
eval_error(const std::string &t_why, eval_error(const std::string &t_why,
const std::vector<Boxed_Value> &t_parameters, const std::vector<chaiscript::Const_Proxy_Function> &t_functions, const std::vector<Boxed_Value> &t_parameters,
const std::vector<chaiscript::Const_Proxy_Function> &t_functions,
bool t_dot_notation, bool t_dot_notation,
const chaiscript::detail::Dispatch_Engine &t_ss) noexcept : const chaiscript::detail::Dispatch_Engine &t_ss) noexcept
std::runtime_error(format(t_why, t_parameters, t_dot_notation, t_ss)), : std::runtime_error(format(t_why, t_parameters, t_dot_notation, t_ss))
reason(t_why), detail(format_detail(t_functions, t_dot_notation, t_ss)) , reason(t_why)
{} , detail(format_detail(t_functions, t_dot_notation, t_ss)) {
}
eval_error(const std::string &t_why, const File_Position &t_where, const std::string &t_fname) noexcept
eval_error(const std::string &t_why, const File_Position &t_where, const std::string &t_fname) noexcept : : std::runtime_error(format(t_why, t_where, t_fname))
std::runtime_error(format(t_why, t_where, t_fname)), , reason(t_why)
reason(t_why), start_position(t_where), filename(t_fname) , start_position(t_where)
{} , filename(t_fname) {
}
explicit eval_error(const std::string &t_why) noexcept explicit eval_error(const std::string &t_why) noexcept
: std::runtime_error("Error: \"" + t_why + "\" "), : std::runtime_error("Error: \"" + t_why + "\" ")
reason(t_why) , reason(t_why) {
{} }
eval_error(const eval_error &) = default; eval_error(const eval_error &) = default;
std::string pretty_print() const std::string pretty_print() const {
{
std::ostringstream ss; std::ostringstream ss;
ss << what(); ss << what();
if (!call_stack.empty()) { if (!call_stack.empty()) {
ss << "during evaluation at (" << fname(call_stack[0]) << " " << startpos(call_stack[0]) << ")\n"; ss << "during evaluation at (" << fname(call_stack[0]) << " " << startpos(call_stack[0]) << ")\n";
ss << '\n' << detail << '\n'; ss << '\n'
<< detail << '\n';
ss << " " << fname(call_stack[0]) << " (" << startpos(call_stack[0]) << ") '" << pretty(call_stack[0]) << "'"; ss << " " << fname(call_stack[0]) << " (" << startpos(call_stack[0]) << ") '" << pretty(call_stack[0]) << "'";
for (size_t j = 1; j < call_stack.size(); ++j) { for (size_t j = 1; j < call_stack.size(); ++j) {
if (id(call_stack[j]) != chaiscript::AST_Node_Type::Block if (id(call_stack[j]) != chaiscript::AST_Node_Type::Block && id(call_stack[j]) != chaiscript::AST_Node_Type::File) {
&& id(call_stack[j]) != chaiscript::AST_Node_Type::File)
{
ss << '\n'; ss << '\n';
ss << " from " << fname(call_stack[j]) << " (" << startpos(call_stack[j]) << ") '" << pretty(call_stack[j]) << "'"; ss << " from " << fname(call_stack[j]) << " (" << startpos(call_stack[j]) << ") '" << pretty(call_stack[j]) << "'";
} }
@ -252,52 +269,39 @@ namespace chaiscript
~eval_error() noexcept override = default; ~eval_error() noexcept override = default;
private: private:
template<typename T> template<typename T>
static AST_Node_Type id(const T& t) noexcept static AST_Node_Type id(const T &t) noexcept {
{
return t.identifier; return t.identifier;
} }
template<typename T> template<typename T>
static std::string pretty(const T& t) static std::string pretty(const T &t) {
{
return t.pretty_print(); return t.pretty_print();
} }
template<typename T> template<typename T>
static const std::string &fname(const T& t) noexcept static const std::string &fname(const T &t) noexcept {
{
return t.filename(); return t.filename();
} }
template<typename T> template<typename T>
static std::string startpos(const T& t) static std::string startpos(const T &t) {
{
std::ostringstream oss; std::ostringstream oss;
oss << t.start().line << ", " << t.start().column; oss << t.start().line << ", " << t.start().column;
return oss.str(); return oss.str();
} }
static std::string format_why(const std::string &t_why) static std::string format_why(const std::string &t_why) { return "Error: \"" + t_why + "\""; }
{
return "Error: \"" + t_why + "\"";
}
static std::string format_types(const Const_Proxy_Function &t_func, static std::string format_types(const Const_Proxy_Function &t_func, bool t_dot_notation, const chaiscript::detail::Dispatch_Engine &t_ss) {
bool t_dot_notation,
const chaiscript::detail::Dispatch_Engine &t_ss)
{
assert(t_func); assert(t_func);
int arity = t_func->get_arity(); int arity = t_func->get_arity();
std::vector<Type_Info> types = t_func->get_param_types(); std::vector<Type_Info> types = t_func->get_param_types();
std::string retval; std::string retval;
if (arity == -1) if (arity == -1) {
{
retval = "(...)"; retval = "(...)";
if (t_dot_notation) if (t_dot_notation) {
{
retval = "(Object)." + retval; retval = "(Object)." + retval;
} }
} else if (types.size() <= 1) { } else if (types.size() <= 1) {
@ -308,18 +312,13 @@ namespace chaiscript
std::string paramstr; std::string paramstr;
for (size_t index = 1; for (size_t index = 1; index != types.size(); ++index) {
index != types.size(); paramstr += (types[index].is_const() ? "const " : "");
++index)
{
paramstr += (types[index].is_const()?"const ":"");
paramstr += t_ss.get_type_name(types[index]); paramstr += t_ss.get_type_name(types[index]);
if (index == 1 && t_dot_notation) if (index == 1 && t_dot_notation) {
{
paramstr += ").("; paramstr += ").(";
if (types.size() == 2) if (types.size() == 2) {
{
paramstr += ", "; paramstr += ", ";
} }
} else { } else {
@ -333,19 +332,15 @@ namespace chaiscript
retval = ss.str(); retval = ss.str();
} }
std::shared_ptr<const dispatch::Dynamic_Proxy_Function> dynfun std::shared_ptr<const dispatch::Dynamic_Proxy_Function> dynfun
= std::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(t_func); = std::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(t_func);
if (dynfun && dynfun->has_parse_tree()) if (dynfun && dynfun->has_parse_tree()) {
{
Proxy_Function f = dynfun->get_guard(); Proxy_Function f = dynfun->get_guard();
if (f) if (f) {
{
auto dynfunguard = std::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(f); auto dynfunguard = std::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(f);
if (dynfunguard && dynfunguard->has_parse_tree()) if (dynfunguard && dynfunguard->has_parse_tree()) {
{
retval += " : " + format_guard(dynfunguard->get_parse_tree()); retval += " : " + format_guard(dynfunguard->get_parse_tree());
} }
} }
@ -357,14 +352,12 @@ namespace chaiscript
} }
template<typename T> template<typename T>
static std::string format_guard(const T &t) static std::string format_guard(const T &t) {
{
return t.pretty_print(); return t.pretty_print();
} }
template<typename T> template<typename T>
static std::string format_location(const T &t) static std::string format_location(const T &t) {
{
std::ostringstream oss; std::ostringstream oss;
oss << "(" << t.filename() << " " << t.start().line << ", " << t.start().column << ")"; oss << "(" << t.filename() << " " << t.start().line << ", " << t.start().column << ")";
return oss.str(); return oss.str();
@ -372,50 +365,37 @@ namespace chaiscript
static std::string format_detail(const std::vector<chaiscript::Const_Proxy_Function> &t_functions, static std::string format_detail(const std::vector<chaiscript::Const_Proxy_Function> &t_functions,
bool t_dot_notation, bool t_dot_notation,
const chaiscript::detail::Dispatch_Engine &t_ss) const chaiscript::detail::Dispatch_Engine &t_ss) {
{
std::stringstream ss; std::stringstream ss;
if (t_functions.size() == 1) if (t_functions.size() == 1) {
{
assert(t_functions[0]); assert(t_functions[0]);
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) << '\n';
} else { } else {
ss << " " << t_functions.size() << " overloads available:\n"; ss << " " << t_functions.size() << " overloads available:\n";
for (const auto & t_function : t_functions) 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) << '\n';
} }
} }
return ss.str(); return ss.str();
} }
static std::string format_parameters(const std::vector<Boxed_Value> &t_parameters, static std::string
bool t_dot_notation, format_parameters(const std::vector<Boxed_Value> &t_parameters, bool t_dot_notation, const chaiscript::detail::Dispatch_Engine &t_ss) {
const chaiscript::detail::Dispatch_Engine &t_ss)
{
std::stringstream ss; std::stringstream ss;
ss << "("; ss << "(";
if (!t_parameters.empty()) if (!t_parameters.empty()) {
{
std::string paramstr; std::string paramstr;
for (auto itr = t_parameters.begin(); for (auto itr = t_parameters.begin(); itr != t_parameters.end(); ++itr) {
itr != t_parameters.end(); paramstr += (itr->is_const() ? "const " : "");
++itr)
{
paramstr += (itr->is_const()?"const ":"");
paramstr += t_ss.type_name(*itr); paramstr += t_ss.type_name(*itr);
if (itr == t_parameters.begin() && t_dot_notation) if (itr == t_parameters.begin() && t_dot_notation) {
{
paramstr += ").("; paramstr += ").(";
if (t_parameters.size() == 1) if (t_parameters.size() == 1) {
{
paramstr += ", "; paramstr += ", ";
} }
} else { } else {
@ -430,12 +410,10 @@ namespace chaiscript
return ss.str(); return ss.str();
} }
static std::string format_filename(const std::string &t_fname) static std::string format_filename(const std::string &t_fname) {
{
std::stringstream ss; std::stringstream ss;
if (t_fname != "__EVAL__") if (t_fname != "__EVAL__") {
{
ss << "in '" << t_fname << "' "; ss << "in '" << t_fname << "' ";
} else { } else {
ss << "during evaluation "; ss << "during evaluation ";
@ -444,16 +422,18 @@ namespace chaiscript
return ss.str(); return ss.str();
} }
static std::string format_location(const File_Position &t_where) static std::string format_location(const File_Position &t_where) {
{
std::stringstream ss; std::stringstream ss;
ss << "at (" << t_where.line << ", " << t_where.column << ")"; ss << "at (" << t_where.line << ", " << t_where.column << ")";
return ss.str(); return ss.str();
} }
static std::string format(const std::string &t_why, const File_Position &t_where, const std::string &t_fname, static std::string format(const std::string &t_why,
const std::vector<Boxed_Value> &t_parameters, bool t_dot_notation, const chaiscript::detail::Dispatch_Engine &t_ss) const File_Position &t_where,
{ const std::string &t_fname,
const std::vector<Boxed_Value> &t_parameters,
bool t_dot_notation,
const chaiscript::detail::Dispatch_Engine &t_ss) {
std::stringstream ss; std::stringstream ss;
ss << format_why(t_why); ss << format_why(t_why);
@ -473,8 +453,7 @@ namespace chaiscript
static std::string format(const std::string &t_why, static std::string format(const std::string &t_why,
const std::vector<Boxed_Value> &t_parameters, const std::vector<Boxed_Value> &t_parameters,
bool t_dot_notation, bool t_dot_notation,
const chaiscript::detail::Dispatch_Engine &t_ss) const chaiscript::detail::Dispatch_Engine &t_ss) {
{
std::stringstream ss; std::stringstream ss;
ss << format_why(t_why); ss << format_why(t_why);
@ -486,8 +465,7 @@ namespace chaiscript
return ss.str(); return ss.str();
} }
static std::string format(const std::string &t_why, const File_Position &t_where, const std::string &t_fname) static std::string format(const std::string &t_why, const File_Position &t_where, const std::string &t_fname) {
{
std::stringstream ss; std::stringstream ss;
ss << format_why(t_why); ss << format_why(t_why);
@ -502,13 +480,12 @@ namespace chaiscript
} }
}; };
/// Errors generated when loading a file /// Errors generated when loading a file
struct file_not_found_error : std::runtime_error { struct file_not_found_error : std::runtime_error {
explicit file_not_found_error(const std::string &t_filename) explicit file_not_found_error(const std::string &t_filename)
: std::runtime_error("File Not Found: " + t_filename), : std::runtime_error("File Not Found: " + t_filename)
filename(t_filename) , filename(t_filename) {
{ } }
file_not_found_error(const file_not_found_error &) = default; file_not_found_error(const file_not_found_error &) = default;
~file_not_found_error() noexcept override = default; ~file_not_found_error() noexcept override = default;
@ -516,8 +493,7 @@ namespace chaiscript
std::string filename; std::string filename;
}; };
} } // namespace exception
/// \brief Struct that doubles as both a parser ast_node and an AST node. /// \brief Struct that doubles as both a parser ast_node and an AST node.
struct AST_Node { struct AST_Node {
@ -526,25 +502,18 @@ namespace chaiscript
const std::string text; const std::string text;
Parse_Location location; Parse_Location location;
const std::string &filename() const noexcept { const std::string &filename() const noexcept { return *location.filename; }
return *location.filename;
}
const File_Position &start() const noexcept { const File_Position &start() const noexcept { return location.start; }
return location.start;
}
const File_Position &end() const noexcept { const File_Position &end() const noexcept { return location.end; }
return location.end;
}
std::string pretty_print() const std::string pretty_print() const {
{
std::ostringstream oss; std::ostringstream oss;
oss << text; oss << text;
for (auto & elem : get_children()) { for (auto &elem : get_children()) {
oss << elem.get().pretty_print() << ' '; oss << elem.get().pretty_print() << ' ';
} }
@ -554,99 +523,81 @@ namespace chaiscript
virtual std::vector<std::reference_wrapper<AST_Node>> get_children() const = 0; virtual std::vector<std::reference_wrapper<AST_Node>> get_children() const = 0;
virtual Boxed_Value eval(const chaiscript::detail::Dispatch_State &t_e) const = 0; virtual Boxed_Value eval(const chaiscript::detail::Dispatch_State &t_e) const = 0;
/// Prints the contents of an AST node, including its children, recursively /// Prints the contents of an AST node, including its children, recursively
std::string to_string(const std::string &t_prepend = "") const { std::string to_string(const std::string &t_prepend = "") const {
std::ostringstream oss; std::ostringstream oss;
oss << t_prepend << "(" << ast_node_type_to_string(this->identifier) << ") " oss << t_prepend << "(" << ast_node_type_to_string(this->identifier) << ") " << this->text << " : " << this->location.start.line
<< this->text << " : " << this->location.start.line << ", " << this->location.start.column << '\n'; << ", " << this->location.start.column << '\n';
for (auto & elem : get_children()) { for (auto &elem : get_children()) {
oss << elem.get().to_string(t_prepend + " "); oss << elem.get().to_string(t_prepend + " ");
} }
return oss.str(); return oss.str();
} }
static bool get_bool_condition(const Boxed_Value &t_bv, const chaiscript::detail::Dispatch_State &t_ss) { static bool get_bool_condition(const Boxed_Value &t_bv, const chaiscript::detail::Dispatch_State &t_ss) {
try { try {
return t_ss->boxed_cast<bool>(t_bv); return t_ss->boxed_cast<bool>(t_bv);
} } catch (const exception::bad_boxed_cast &) {
catch (const exception::bad_boxed_cast &) {
throw exception::eval_error("Condition not boolean"); throw exception::eval_error("Condition not boolean");
} }
} }
virtual ~AST_Node() noexcept = default; virtual ~AST_Node() noexcept = default;
AST_Node(AST_Node &&) = default; AST_Node(AST_Node &&) = default;
AST_Node &operator=(AST_Node &&) = delete; AST_Node &operator=(AST_Node &&) = delete;
AST_Node(const AST_Node &) = delete; AST_Node(const AST_Node &) = delete;
AST_Node& operator=(const AST_Node &) = delete; AST_Node &operator=(const AST_Node &) = delete;
protected: protected:
AST_Node(std::string t_ast_node_text, AST_Node_Type t_id, Parse_Location t_loc) AST_Node(std::string t_ast_node_text, AST_Node_Type t_id, Parse_Location t_loc)
: identifier(t_id), text(std::move(t_ast_node_text)), : identifier(t_id)
location(std::move(t_loc)) , text(std::move(t_ast_node_text))
{ , location(std::move(t_loc)) {
} }
}; };
struct AST_Node_Trace struct AST_Node_Trace {
{
const AST_Node_Type identifier; const AST_Node_Type identifier;
const std::string text; const std::string text;
Parse_Location location; Parse_Location location;
const std::string &filename() const noexcept { const std::string &filename() const noexcept { return *location.filename; }
return *location.filename;
}
const File_Position &start() const noexcept { const File_Position &start() const noexcept { return location.start; }
return location.start;
}
const File_Position &end() const noexcept { const File_Position &end() const noexcept { return location.end; }
return location.end;
}
std::string pretty_print() const std::string pretty_print() const {
{
std::ostringstream oss; std::ostringstream oss;
oss << text; oss << text;
for (const auto & elem : children) { for (const auto &elem : children) {
oss << elem.pretty_print() << ' '; oss << elem.pretty_print() << ' ';
} }
return oss.str(); return oss.str();
} }
std::vector<AST_Node_Trace> get_children(const AST_Node &node) std::vector<AST_Node_Trace> get_children(const AST_Node &node) {
{
const auto node_children = node.get_children(); const auto node_children = node.get_children();
return std::vector<AST_Node_Trace>(node_children.begin(), node_children.end()); return std::vector<AST_Node_Trace>(node_children.begin(), node_children.end());
} }
AST_Node_Trace(const AST_Node &node) AST_Node_Trace(const AST_Node &node)
: identifier(node.identifier), text(node.text), : identifier(node.identifier)
location(node.location), children(get_children(node)) , text(node.text)
{ , location(node.location)
, children(get_children(node)) {
} }
std::vector<AST_Node_Trace> children; std::vector<AST_Node_Trace> children;
}; };
namespace parser { namespace parser {
class ChaiScript_Parser_Base class ChaiScript_Parser_Base {
{
public: public:
virtual AST_NodePtr parse(const std::string &t_input, const std::string &t_fname) = 0; virtual AST_NodePtr parse(const std::string &t_input, const std::string &t_fname) = 0;
virtual void debug_print(const AST_Node &t, std::string prepend = "") const = 0; virtual void debug_print(const AST_Node &t, std::string prepend = "") const = 0;
@ -658,116 +609,88 @@ namespace chaiscript
ChaiScript_Parser_Base &operator=(const ChaiScript_Parser_Base &&) = delete; ChaiScript_Parser_Base &operator=(const ChaiScript_Parser_Base &&) = delete;
template<typename T> template<typename T>
T &get_tracer() noexcept T &get_tracer() noexcept {
{
// to do type check this somehow? // to do type check this somehow?
return *static_cast<T*>(get_tracer_ptr()); return *static_cast<T *>(get_tracer_ptr());
} }
protected: protected:
ChaiScript_Parser_Base(const ChaiScript_Parser_Base &) = default; ChaiScript_Parser_Base(const ChaiScript_Parser_Base &) = default;
}; };
} } // namespace parser
namespace eval namespace eval {
{ namespace detail {
namespace detail
{
/// Special type for returned values /// Special type for returned values
struct Return_Value { struct Return_Value {
Boxed_Value retval; Boxed_Value retval;
}; };
/// Special type indicating a call to 'break' /// Special type indicating a call to 'break'
struct Break_Loop { struct Break_Loop {
}; };
/// Special type indicating a call to 'continue' /// Special type indicating a call to 'continue'
struct Continue_Loop { struct Continue_Loop {
}; };
/// Creates a new scope then pops it on destruction /// Creates a new scope then pops it on destruction
struct Scope_Push_Pop struct Scope_Push_Pop {
{
Scope_Push_Pop(Scope_Push_Pop &&) = default; Scope_Push_Pop(Scope_Push_Pop &&) = default;
Scope_Push_Pop& operator=(Scope_Push_Pop &&) = delete; Scope_Push_Pop &operator=(Scope_Push_Pop &&) = delete;
Scope_Push_Pop(const Scope_Push_Pop &) = delete; Scope_Push_Pop(const Scope_Push_Pop &) = delete;
Scope_Push_Pop& operator=(const Scope_Push_Pop &) = delete; Scope_Push_Pop &operator=(const Scope_Push_Pop &) = delete;
explicit Scope_Push_Pop(const chaiscript::detail::Dispatch_State &t_ds) explicit Scope_Push_Pop(const chaiscript::detail::Dispatch_State &t_ds)
: m_ds(t_ds) : m_ds(t_ds) {
{
m_ds->new_scope(m_ds.stack_holder()); m_ds->new_scope(m_ds.stack_holder());
} }
~Scope_Push_Pop() ~Scope_Push_Pop() { m_ds->pop_scope(m_ds.stack_holder()); }
{
m_ds->pop_scope(m_ds.stack_holder());
}
private: private:
const chaiscript::detail::Dispatch_State &m_ds; const chaiscript::detail::Dispatch_State &m_ds;
}; };
/// Creates a new function call and pops it on destruction /// Creates a new function call and pops it on destruction
struct Function_Push_Pop struct Function_Push_Pop {
{
Function_Push_Pop(Function_Push_Pop &&) = default; Function_Push_Pop(Function_Push_Pop &&) = default;
Function_Push_Pop& operator=(Function_Push_Pop &&) = delete; Function_Push_Pop &operator=(Function_Push_Pop &&) = delete;
Function_Push_Pop(const Function_Push_Pop &) = delete; Function_Push_Pop(const Function_Push_Pop &) = delete;
Function_Push_Pop& operator=(const Function_Push_Pop &) = delete; Function_Push_Pop &operator=(const Function_Push_Pop &) = delete;
explicit Function_Push_Pop(const chaiscript::detail::Dispatch_State &t_ds) explicit Function_Push_Pop(const chaiscript::detail::Dispatch_State &t_ds)
: m_ds(t_ds) : m_ds(t_ds) {
{
m_ds->new_function_call(m_ds.stack_holder(), m_ds.conversion_saves()); m_ds->new_function_call(m_ds.stack_holder(), m_ds.conversion_saves());
} }
~Function_Push_Pop() ~Function_Push_Pop() { m_ds->pop_function_call(m_ds.stack_holder(), m_ds.conversion_saves()); }
{
m_ds->pop_function_call(m_ds.stack_holder(), m_ds.conversion_saves());
}
void save_params(const Function_Params &t_params)
{
m_ds->save_function_params(t_params);
}
void save_params(const Function_Params &t_params) { m_ds->save_function_params(t_params); }
private: private:
const chaiscript::detail::Dispatch_State &m_ds; const chaiscript::detail::Dispatch_State &m_ds;
}; };
/// Creates a new scope then pops it on destruction /// Creates a new scope then pops it on destruction
struct Stack_Push_Pop struct Stack_Push_Pop {
{
Stack_Push_Pop(Stack_Push_Pop &&) = default; Stack_Push_Pop(Stack_Push_Pop &&) = default;
Stack_Push_Pop& operator=(Stack_Push_Pop &&) = delete; Stack_Push_Pop &operator=(Stack_Push_Pop &&) = delete;
Stack_Push_Pop(const Stack_Push_Pop &) = delete; Stack_Push_Pop(const Stack_Push_Pop &) = delete;
Stack_Push_Pop& operator=(const Stack_Push_Pop &) = delete; Stack_Push_Pop &operator=(const Stack_Push_Pop &) = delete;
explicit Stack_Push_Pop(const chaiscript::detail::Dispatch_State &t_ds) explicit Stack_Push_Pop(const chaiscript::detail::Dispatch_State &t_ds)
: m_ds(t_ds) : m_ds(t_ds) {
{
m_ds->new_stack(m_ds.stack_holder()); m_ds->new_stack(m_ds.stack_holder());
} }
~Stack_Push_Pop() ~Stack_Push_Pop() { m_ds->pop_stack(m_ds.stack_holder()); }
{
m_ds->pop_stack(m_ds.stack_holder());
}
private: private:
const chaiscript::detail::Dispatch_State &m_ds; const chaiscript::detail::Dispatch_State &m_ds;
}; };
} } // namespace detail
} } // namespace eval
} } // namespace chaiscript
#endif /* _CHAISCRIPT_COMMON_HPP */ #endif /* _CHAISCRIPT_COMMON_HPP */

View File

@ -7,11 +7,11 @@
// This is an open source non-commercial project. Dear PVS-Studio, please check it. // This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com // PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_ENGINE_HPP_ #ifndef CHAISCRIPT_ENGINE_HPP_
#define CHAISCRIPT_ENGINE_HPP_ #define CHAISCRIPT_ENGINE_HPP_
#include <cassert> #include <cassert>
#include <cstring>
#include <exception> #include <exception>
#include <fstream> #include <fstream>
#include <functional> #include <functional>
@ -21,15 +21,15 @@
#include <set> #include <set>
#include <stdexcept> #include <stdexcept>
#include <vector> #include <vector>
#include <cstring>
#include "../chaiscript_defines.hpp" #include "../chaiscript_defines.hpp"
#include "../chaiscript_threading.hpp" #include "../chaiscript_threading.hpp"
#include "../dispatchkit/boxed_cast_helper.hpp" #include "../dispatchkit/boxed_cast_helper.hpp"
#include "../dispatchkit/boxed_value.hpp" #include "../dispatchkit/boxed_value.hpp"
#include "../dispatchkit/dispatchkit.hpp" #include "../dispatchkit/dispatchkit.hpp"
#include "../dispatchkit/type_conversions.hpp"
#include "../dispatchkit/proxy_functions.hpp" #include "../dispatchkit/proxy_functions.hpp"
#include "../dispatchkit/register_function.hpp"
#include "../dispatchkit/type_conversions.hpp"
#include "chaiscript_common.hpp" #include "chaiscript_common.hpp"
#if defined(__linux__) || defined(__unix__) || defined(__APPLE__) || defined(__HAIKU__) #if defined(__linux__) || defined(__unix__) || defined(__APPLE__) || defined(__HAIKU__)
@ -50,23 +50,18 @@
#include "chaiscript_unknown.hpp" #include "chaiscript_unknown.hpp"
#endif #endif
#include "../dispatchkit/exception_specification.hpp" #include "../dispatchkit/exception_specification.hpp"
namespace chaiscript namespace chaiscript {
{
/// Namespace alias to provide cleaner and more explicit syntax to users. /// Namespace alias to provide cleaner and more explicit syntax to users.
using Namespace = dispatch::Dynamic_Object; using Namespace = dispatch::Dynamic_Object;
namespace detail namespace detail {
{
using Loadable_Module_Ptr = std::shared_ptr<Loadable_Module>; using Loadable_Module_Ptr = std::shared_ptr<Loadable_Module>;
} }
/// \brief The main object that the ChaiScript user will use. /// \brief The main object that the ChaiScript user will use.
class ChaiScript_Basic { class ChaiScript_Basic {
mutable chaiscript::detail::threading::shared_mutex m_mutex; mutable chaiscript::detail::threading::shared_mutex m_mutex;
mutable chaiscript::detail::threading::recursive_mutex m_use_mutex; mutable chaiscript::detail::threading::recursive_mutex m_use_mutex;
@ -81,26 +76,21 @@ namespace chaiscript
chaiscript::detail::Dispatch_Engine m_engine; chaiscript::detail::Dispatch_Engine m_engine;
std::map<std::string, std::function<Namespace&()>> m_namespace_generators; std::map<std::string, std::function<Namespace &()>> m_namespace_generators;
/// Evaluates the given string in by parsing it and running the results through the evaluator /// Evaluates the given string in by parsing it and running the results through the evaluator
Boxed_Value do_eval(const std::string &t_input, const std::string &t_filename = "__EVAL__", bool /* t_internal*/ = false) Boxed_Value do_eval(const std::string &t_input, const std::string &t_filename = "__EVAL__", bool /* t_internal*/ = false) {
{
try { try {
const auto p = m_parser->parse(t_input, t_filename); const auto p = m_parser->parse(t_input, t_filename);
return p->eval(chaiscript::detail::Dispatch_State(m_engine)); return p->eval(chaiscript::detail::Dispatch_State(m_engine));
} } catch (chaiscript::eval::detail::Return_Value &rv) {
catch (chaiscript::eval::detail::Return_Value &rv) {
return rv.retval; return rv.retval;
} }
} }
/// Evaluates the given file and looks in the 'use' paths /// Evaluates the given file and looks in the 'use' paths
Boxed_Value internal_eval_file(const std::string &t_filename) { Boxed_Value internal_eval_file(const std::string &t_filename) {
for (const auto &path : m_use_paths) for (const auto &path : m_use_paths) {
{
try { try {
const auto appendedpath = path + t_filename; const auto appendedpath = path + t_filename;
return do_eval(load_file(appendedpath), appendedpath, true); return do_eval(load_file(appendedpath), appendedpath, true);
@ -113,11 +103,8 @@ namespace chaiscript
// failed to load by any name // failed to load by any name
throw exception::file_not_found_error(t_filename); throw exception::file_not_found_error(t_filename);
} }
/// Evaluates the given string, used during eval() inside of a script /// Evaluates the given string, used during eval() inside of a script
Boxed_Value internal_eval(const std::string &t_e) { Boxed_Value internal_eval(const std::string &t_e) {
try { try {
@ -128,81 +115,70 @@ namespace chaiscript
} }
/// Returns the current evaluation m_engine /// Returns the current evaluation m_engine
chaiscript::detail::Dispatch_Engine &get_eval_engine() noexcept { chaiscript::detail::Dispatch_Engine &get_eval_engine() noexcept { return m_engine; }
return m_engine;
}
/// Builds all the requirements for ChaiScript, including its evaluator and a run of its prelude. /// Builds all the requirements for ChaiScript, including its evaluator and a run of its prelude.
void build_eval_system(const ModulePtr &t_lib, const std::vector<Options> &t_opts) { void build_eval_system(const ModulePtr &t_lib, const std::vector<Options> &t_opts) {
if (t_lib) if (t_lib) {
{
add(t_lib); add(t_lib);
} }
m_engine.add(fun([this](){ m_engine.dump_system(); }), "dump_system"); m_engine.add(fun([this]() { m_engine.dump_system(); }), "dump_system");
m_engine.add(fun([this](const Boxed_Value &t_bv){ m_engine.dump_object(t_bv); }), "dump_object"); m_engine.add(fun([this](const Boxed_Value &t_bv) { m_engine.dump_object(t_bv); }), "dump_object");
m_engine.add(fun([this](const Boxed_Value &t_bv, const std::string &t_type){ return m_engine.is_type(t_bv, t_type); }), "is_type"); m_engine.add(fun([this](const Boxed_Value &t_bv, const std::string &t_type) { return m_engine.is_type(t_bv, t_type); }), "is_type");
m_engine.add(fun([this](const Boxed_Value &t_bv){ return m_engine.type_name(t_bv); }), "type_name"); m_engine.add(fun([this](const Boxed_Value &t_bv) { return m_engine.type_name(t_bv); }), "type_name");
m_engine.add(fun([this](const std::string &t_f){ return m_engine.function_exists(t_f); }), "function_exists"); m_engine.add(fun([this](const std::string &t_f) { return m_engine.function_exists(t_f); }), "function_exists");
m_engine.add(fun([this](){ return m_engine.get_function_objects(); }), "get_functions"); m_engine.add(fun([this]() { return m_engine.get_function_objects(); }), "get_functions");
m_engine.add(fun([this](){ return m_engine.get_scripting_objects(); }), "get_objects"); m_engine.add(fun([this]() { return m_engine.get_scripting_objects(); }), "get_objects");
m_engine.add( m_engine.add(dispatch::make_dynamic_proxy_function([this](const Function_Params &t_params) { return m_engine.call_exists(t_params); }),
dispatch::make_dynamic_proxy_function( "call_exists");
[this](const Function_Params &t_params) {
return m_engine.call_exists(t_params);
})
, "call_exists");
m_engine.add(fun([this](const dispatch::Proxy_Function_Base &t_fun, const std::vector<Boxed_Value> &t_params) -> Boxed_Value {
m_engine.add(fun(
[this](const dispatch::Proxy_Function_Base &t_fun, const std::vector<Boxed_Value> &t_params) -> Boxed_Value {
Type_Conversions_State s(this->m_engine.conversions(), this->m_engine.conversions().conversion_saves()); Type_Conversions_State s(this->m_engine.conversions(), this->m_engine.conversions().conversion_saves());
return t_fun(Function_Params{t_params}, s); return t_fun(Function_Params{t_params}, s);
}), "call"); }),
"call");
m_engine.add(fun([this](const Type_Info &t_ti) { return m_engine.get_type_name(t_ti); }), "name");
m_engine.add(fun([this](const Type_Info &t_ti){ return m_engine.get_type_name(t_ti); }), "name"); m_engine.add(fun([this](const std::string &t_type_name, bool t_throw) { return m_engine.get_type(t_type_name, t_throw); }), "type");
m_engine.add(fun([this](const std::string &t_type_name) { return m_engine.get_type(t_type_name, true); }), "type");
m_engine.add(fun([this](const std::string &t_type_name, bool t_throw){ return m_engine.get_type(t_type_name, t_throw); }), "type"); m_engine.add(fun([this](const Type_Info &t_from, const Type_Info &t_to, const std::function<Boxed_Value(const Boxed_Value &)> &t_func) {
m_engine.add(fun([this](const std::string &t_type_name){ return m_engine.get_type(t_type_name, true); }), "type");
m_engine.add(fun(
[this](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)); m_engine.add(chaiscript::type_conversion(t_from, t_to, t_func));
} }),
), "add_type_conversion"); "add_type_conversion");
if (std::find(t_opts.begin(), t_opts.end(), Options::No_Load_Modules) == t_opts.end() if (std::find(t_opts.begin(), t_opts.end(), Options::No_Load_Modules) == t_opts.end()
&& std::find(t_opts.begin(), t_opts.end(), Options::Load_Modules) != t_opts.end()) && std::find(t_opts.begin(), t_opts.end(), Options::Load_Modules) != t_opts.end()) {
{ m_engine.add(fun([this](const std::string &t_module, const std::string &t_file) { load_module(t_module, t_file); }), "load_module");
m_engine.add(fun([this](const std::string &t_module, const std::string &t_file){ load_module(t_module, t_file); }), "load_module"); m_engine.add(fun([this](const std::string &t_module) { return load_module(t_module); }), "load_module");
m_engine.add(fun([this](const std::string &t_module){ return load_module(t_module); }), "load_module");
} }
if (std::find(t_opts.begin(), t_opts.end(), Options::No_External_Scripts) == t_opts.end() if (std::find(t_opts.begin(), t_opts.end(), Options::No_External_Scripts) == t_opts.end()
&& std::find(t_opts.begin(), t_opts.end(), Options::External_Scripts) != t_opts.end()) && std::find(t_opts.begin(), t_opts.end(), Options::External_Scripts) != t_opts.end()) {
{ m_engine.add(fun([this](const std::string &t_file) { return use(t_file); }), "use");
m_engine.add(fun([this](const std::string &t_file){ return use(t_file); }), "use"); m_engine.add(fun([this](const std::string &t_file) { return internal_eval_file(t_file); }), "eval_file");
m_engine.add(fun([this](const std::string &t_file){ return internal_eval_file(t_file); }), "eval_file");
} }
m_engine.add(fun([this](const std::string &t_str){ return internal_eval(t_str); }), "eval"); m_engine.add(fun([this](const std::string &t_str) { return internal_eval(t_str); }), "eval");
m_engine.add(fun([this](const AST_Node &t_ast){ return eval(t_ast); }), "eval"); m_engine.add(fun([this](const AST_Node &t_ast) { return eval(t_ast); }), "eval");
m_engine.add(fun([this](const std::string &t_str, const bool t_dump){ return parse(t_str, t_dump); }), "parse"); m_engine.add(fun([this](const std::string &t_str, const bool t_dump) { return parse(t_str, t_dump); }), "parse");
m_engine.add(fun([this](const std::string &t_str){ return parse(t_str); }), "parse"); m_engine.add(fun([this](const std::string &t_str) { return parse(t_str); }), "parse");
m_engine.add(fun([this](const Boxed_Value &t_bv, const std::string &t_name) { add_global_const(t_bv, t_name); }), "add_global_const");
m_engine.add(fun([this](const Boxed_Value &t_bv, const std::string &t_name){ add_global_const(t_bv, t_name); }), "add_global_const"); m_engine.add(fun([this](const Boxed_Value &t_bv, const std::string &t_name) { add_global(t_bv, t_name); }), "add_global");
m_engine.add(fun([this](const Boxed_Value &t_bv, const std::string &t_name){ add_global(t_bv, t_name); }), "add_global"); m_engine.add(fun([this](const Boxed_Value &t_bv, const std::string &t_name) { set_global(t_bv, t_name); }), "set_global");
m_engine.add(fun([this](const Boxed_Value &t_bv, const std::string &t_name){ set_global(t_bv, t_name); }), "set_global");
// why this unused parameter to Namespace? // why this unused parameter to Namespace?
m_engine.add(fun([this](const std::string& t_namespace_name) { register_namespace([] (Namespace& /*space*/) noexcept {}, t_namespace_name); import(t_namespace_name); }), "namespace"); m_engine.add(fun([this](const std::string &t_namespace_name) {
m_engine.add(fun([this](const std::string& t_namespace_name) { import(t_namespace_name); }), "import"); register_namespace([](Namespace & /*space*/) noexcept {}, t_namespace_name);
import(t_namespace_name);
}),
"namespace");
m_engine.add(fun([this](const std::string &t_namespace_name) { import(t_namespace_name); }), "import");
} }
/// Skip BOM at the beginning of file /// Skip BOM at the beginning of file
@ -214,10 +190,7 @@ namespace chaiscript
infile.read(buffer, static_cast<std::streamsize>(bytes_needed)); infile.read(buffer, static_cast<std::streamsize>(bytes_needed));
if ((buffer[0] == '\xef') if ((buffer[0] == '\xef') && (buffer[1] == '\xbb') && (buffer[2] == '\xbf')) {
&& (buffer[1] == '\xbb')
&& (buffer[2] == '\xbf')) {
infile.seekg(3); infile.seekg(3);
return true; return true;
} }
@ -229,7 +202,7 @@ namespace chaiscript
/// Helper function for loading a file /// Helper function for loading a file
static std::string load_file(const std::string &t_filename) { static std::string load_file(const std::string &t_filename) {
std::ifstream infile(t_filename.c_str(), std::ios::in | std::ios::ate | std::ios::binary ); std::ifstream infile(t_filename.c_str(), std::ios::in | std::ios::ate | std::ios::binary);
if (!infile.is_open()) { if (!infile.is_open()) {
throw chaiscript::exception::file_not_found_error(t_filename); throw chaiscript::exception::file_not_found_error(t_filename);
@ -241,12 +214,11 @@ namespace chaiscript
assert(size >= 0); assert(size >= 0);
if (skip_bom(infile)) { if (skip_bom(infile)) {
size-=3; // decrement the BOM size from file size, otherwise we'll get parsing errors size -= 3; // decrement the BOM size from file size, otherwise we'll get parsing errors
assert(size >= 0); //and check if there's more text assert(size >= 0); // and check if there's more text
} }
if (size == std::streampos(0)) if (size == std::streampos(0)) {
{
return std::string(); return std::string();
} else { } else {
std::vector<char> v(static_cast<size_t>(size)); std::vector<char> v(static_cast<size_t>(size));
@ -255,14 +227,15 @@ namespace chaiscript
} }
} }
std::vector<std::string> ensure_minimum_path_vec(std::vector<std::string> paths) std::vector<std::string> ensure_minimum_path_vec(std::vector<std::string> paths) {
{ if (paths.empty()) {
if (paths.empty()) { return {""}; } return {""};
else { return paths; } } else {
return paths;
}
} }
public: public:
/// \brief Constructor for ChaiScript /// \brief Constructor for ChaiScript
/// \param[in] t_lib Standard library to apply to this ChaiScript instance /// \param[in] t_lib Standard library to apply to this ChaiScript instance
/// \param[in] t_modulepaths Vector of paths to search when attempting to load a binary module /// \param[in] t_modulepaths Vector of paths to search when attempting to load a binary module
@ -272,42 +245,38 @@ namespace chaiscript
std::vector<std::string> t_module_paths = {}, std::vector<std::string> t_module_paths = {},
std::vector<std::string> t_use_paths = {}, std::vector<std::string> t_use_paths = {},
const std::vector<chaiscript::Options> &t_opts = chaiscript::default_options()) const std::vector<chaiscript::Options> &t_opts = chaiscript::default_options())
: m_module_paths(ensure_minimum_path_vec(std::move(t_module_paths))), : m_module_paths(ensure_minimum_path_vec(std::move(t_module_paths)))
m_use_paths(ensure_minimum_path_vec(std::move(t_use_paths))), , m_use_paths(ensure_minimum_path_vec(std::move(t_use_paths)))
m_parser(std::move(parser)), , m_parser(std::move(parser))
m_engine(*m_parser) , m_engine(*m_parser) {
{
#if !defined(CHAISCRIPT_NO_DYNLOAD) && defined(_POSIX_VERSION) && !defined(__CYGWIN__) #if !defined(CHAISCRIPT_NO_DYNLOAD) && defined(_POSIX_VERSION) && !defined(__CYGWIN__)
// If on Unix, add the path of the current executable to the module search path // If on Unix, add the path of the current executable to the module search path
// as windows would do // as windows would do
union cast_union union cast_union {
{ Boxed_Value (ChaiScript_Basic::*in_ptr)(const std::string &);
Boxed_Value (ChaiScript_Basic::*in_ptr)(const std::string&);
void *out_ptr; void *out_ptr;
}; };
Dl_info rInfo; Dl_info rInfo;
memset( &rInfo, 0, sizeof(rInfo) ); memset(&rInfo, 0, sizeof(rInfo));
cast_union u; cast_union u;
u.in_ptr = &ChaiScript_Basic::use; u.in_ptr = &ChaiScript_Basic::use;
if ( (dladdr(static_cast<void*>(u.out_ptr), &rInfo) != 0) && (rInfo.dli_fname != nullptr) ) { if ((dladdr(static_cast<void *>(u.out_ptr), &rInfo) != 0) && (rInfo.dli_fname != nullptr)) {
std::string dllpath(rInfo.dli_fname); std::string dllpath(rInfo.dli_fname);
const size_t lastslash = dllpath.rfind('/'); const size_t lastslash = dllpath.rfind('/');
if (lastslash != std::string::npos) if (lastslash != std::string::npos) {
{
dllpath.erase(lastslash); dllpath.erase(lastslash);
} }
// Let's see if this is a link that we should expand // Let's see if this is a link that we should expand
std::vector<char> buf(2048); std::vector<char> buf(2048);
const auto pathlen = readlink(dllpath.c_str(), &buf.front(), buf.size()); const auto pathlen = readlink(dllpath.c_str(), &buf.front(), buf.size());
if (pathlen > 0 && static_cast<size_t>(pathlen) < buf.size()) if (pathlen > 0 && static_cast<size_t>(pathlen) < buf.size()) {
{
dllpath = std::string(&buf.front(), static_cast<size_t>(pathlen)); dllpath = std::string(&buf.front(), static_cast<size_t>(pathlen));
} }
m_module_paths.insert(m_module_paths.begin(), dllpath+"/"); m_module_paths.insert(m_module_paths.begin(), dllpath + "/");
} }
#endif #endif
build_eval_system(t_lib, t_opts); build_eval_system(t_lib, t_opts);
@ -325,20 +294,18 @@ namespace chaiscript
std::vector<std::string> t_module_paths = {}, std::vector<std::string> t_module_paths = {},
std::vector<std::string> t_use_paths = {}, std::vector<std::string> t_use_paths = {},
const std::vector<chaiscript::Options> &t_opts = chaiscript::default_options()) const std::vector<chaiscript::Options> &t_opts = chaiscript::default_options())
: ChaiScript_Basic({}, std::move(parser), t_module_paths, t_use_paths, t_opts) : ChaiScript_Basic({}, std::move(parser), t_module_paths, t_use_paths, t_opts) {
{
try { try {
// attempt to load the stdlib // attempt to load the stdlib
load_module("chaiscript_stdlib-" + Build_Info::version()); load_module("chaiscript_stdlib-" + Build_Info::version());
} catch (const exception::load_module_error &t_err) { } catch (const exception::load_module_error &t_err) {
std::cout << "An error occured while trying to load the chaiscript standard library.\n" std::cout << "An error occurred while trying to load the chaiscript standard library.\n"
<< "\n" "\n"
<< "You must either provide a standard library, or compile it in.\n" "You must either provide a standard library, or compile it in.\n"
<< "For an example of compiling the standard library in,\n" "For an example of compiling the standard library in,\n"
<< "see: https://gist.github.com/lefticus/9456197\n" "see: https://gist.github.com/lefticus/9456197\n"
<< "Compiling the stdlib in is the recommended and MOST SUPPORTED method.\n" "Compiling the stdlib in is the recommended and MOST SUPPORTED method.\n"
<< "\n" "\n\n"
<< "\n"
<< t_err.what(); << t_err.what();
throw; throw;
} }
@ -347,16 +314,15 @@ namespace chaiscript
explicit ChaiScript_Basic(std::unique_ptr<parser::ChaiScript_Parser_Base> &&parser, explicit ChaiScript_Basic(std::unique_ptr<parser::ChaiScript_Parser_Base> &&parser,
std::vector<std::string> t_module_paths = {}, std::vector<std::string> t_module_paths = {},
std::vector<std::string> t_use_paths = {}, std::vector<std::string> t_use_paths = {},
const std::vector<chaiscript::Options> &t_opts = chaiscript::default_options()) = delete; const std::vector<chaiscript::Options> &t_opts = chaiscript::default_options())
= delete;
#endif #endif
parser::ChaiScript_Parser_Base &get_parser() noexcept parser::ChaiScript_Parser_Base &get_parser() noexcept {
{
return *m_parser; return *m_parser;
} }
const Boxed_Value eval(const AST_Node &t_ast) const Boxed_Value eval(const AST_Node &t_ast) {
{
try { try {
return t_ast.eval(chaiscript::detail::Dispatch_State(m_engine)); return t_ast.eval(chaiscript::detail::Dispatch_State(m_engine));
} catch (const exception::eval_error &t_ee) { } catch (const exception::eval_error &t_ee) {
@ -364,8 +330,7 @@ namespace chaiscript
} }
} }
AST_NodePtr parse(const std::string &t_input, const bool t_debug_print = false) AST_NodePtr parse(const std::string &t_input, const bool t_debug_print = false) {
{
auto ast = m_parser->parse(t_input, "PARSE"); auto ast = m_parser->parse(t_input, "PARSE");
if (t_debug_print) { if (t_debug_print) {
m_parser->debug_print(*ast); m_parser->debug_print(*ast);
@ -373,38 +338,28 @@ namespace chaiscript
return ast; return ast;
} }
std::string get_type_name(const Type_Info &ti) const { return m_engine.get_type_name(ti); }
std::string get_type_name(const Type_Info &ti) const
{
return m_engine.get_type_name(ti);
}
template<typename T> template<typename T>
std::string get_type_name() const std::string get_type_name() const {
{
return get_type_name(user_type<T>()); return get_type_name(user_type<T>());
} }
/// \brief Loads and parses a file. If the file is already open, it is not /// \brief Loads and parses a file. If the file is already open, it is not
/// reloaded. The use paths specified at ChaiScript construction time are /// reloaded. The use paths specified at ChaiScript construction time are
/// searched for the requested file. /// searched for the requested file.
/// ///
/// \param[in] t_filename Filename to load and evaluate /// \param[in] t_filename Filename to load and evaluate
Boxed_Value use(const std::string &t_filename) Boxed_Value use(const std::string &t_filename) {
{ for (const auto &path : m_use_paths) {
for (const auto &path : m_use_paths)
{
const auto appendedpath = path + t_filename; const auto appendedpath = path + t_filename;
try { try {
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::recursive_mutex> l(m_use_mutex); chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::recursive_mutex> l(m_use_mutex);
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l2(m_mutex); chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l2(m_mutex);
Boxed_Value retval; Boxed_Value retval;
if (m_used_files.count(appendedpath) == 0) if (m_used_files.count(appendedpath) == 0) {
{
l2.unlock(); l2.unlock();
retval = eval_file(appendedpath); retval = eval_file(appendedpath);
l2.lock(); l2.lock();
@ -430,8 +385,7 @@ namespace chaiscript
/// \param[in] t_name Name of the value to add /// \param[in] t_name Name of the value to add
/// \throw chaiscript::exception::global_non_const If t_bv is not a constant object /// \throw chaiscript::exception::global_non_const If t_bv is not a constant object
/// \sa Boxed_Value::is_const /// \sa Boxed_Value::is_const
ChaiScript_Basic &add_global_const(const Boxed_Value &t_bv, const std::string &t_name) ChaiScript_Basic &add_global_const(const Boxed_Value &t_bv, const std::string &t_name) {
{
Name_Validator::validate_object_name(t_name); Name_Validator::validate_object_name(t_name);
m_engine.add_global_const(t_bv, t_name); m_engine.add_global_const(t_bv, t_name);
return *this; return *this;
@ -442,15 +396,13 @@ namespace chaiscript
/// \param[in] t_name Name of the value to add /// \param[in] t_name Name of the value to add
/// \warning The user is responsible for making sure the object is thread-safe if necessary /// \warning The user is responsible for making sure the object is thread-safe if necessary
/// ChaiScript is thread-safe but provides no threading locking mechanism to the script /// ChaiScript is thread-safe but provides no threading locking mechanism to the script
ChaiScript_Basic &add_global(const Boxed_Value &t_bv, const std::string &t_name) ChaiScript_Basic &add_global(const Boxed_Value &t_bv, const std::string &t_name) {
{
Name_Validator::validate_object_name(t_name); Name_Validator::validate_object_name(t_name);
m_engine.add_global(t_bv, t_name); m_engine.add_global(t_bv, t_name);
return *this; return *this;
} }
ChaiScript_Basic &set_global(const Boxed_Value &t_bv, const std::string &t_name) ChaiScript_Basic &set_global(const Boxed_Value &t_bv, const std::string &t_name) {
{
Name_Validator::validate_object_name(t_name); Name_Validator::validate_object_name(t_name);
m_engine.set_global(t_bv, t_name); m_engine.set_global(t_bv, t_name);
return *this; return *this;
@ -461,8 +413,7 @@ namespace chaiscript
/// are left out due to performance considerations involved in tracking the state /// are left out due to performance considerations involved in tracking the state
/// \sa ChaiScript::get_state /// \sa ChaiScript::get_state
/// \sa ChaiScript::set_state /// \sa ChaiScript::set_state
struct State struct State {
{
std::set<std::string> used_files; std::set<std::string> used_files;
chaiscript::detail::Dispatch_Engine::State engine_state; chaiscript::detail::Dispatch_Engine::State engine_state;
std::set<std::string> active_loaded_modules; std::set<std::string> active_loaded_modules;
@ -481,8 +432,7 @@ namespace chaiscript
/// chaiscript::ChaiScript chai; /// chaiscript::ChaiScript chai;
/// chaiscript::ChaiScript::State s = chai.get_state(); // represents bootstrapped initial state /// chaiscript::ChaiScript::State s = chai.get_state(); // represents bootstrapped initial state
/// \endcode /// \endcode
State get_state() const State get_state() const {
{
chaiscript::detail::threading::lock_guard<chaiscript::detail::threading::recursive_mutex> l(m_use_mutex); 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); chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l2(m_mutex);
@ -507,8 +457,7 @@ namespace chaiscript
/// chai.add(chaiscript::fun(&somefunction), "somefunction"); /// chai.add(chaiscript::fun(&somefunction), "somefunction");
/// chai.set_state(s); // restore initial state, which does not have the recently added "somefunction" /// chai.set_state(s); // restore initial state, which does not have the recently added "somefunction"
/// \endcode /// \endcode
void set_state(const State &t_state) void set_state(const State &t_state) {
{
chaiscript::detail::threading::lock_guard<chaiscript::detail::threading::recursive_mutex> l(m_use_mutex); 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); chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l2(m_mutex);
@ -518,20 +467,14 @@ namespace chaiscript
} }
/// \returns All values in the local thread state, added through the add() function /// \returns All values in the local thread state, added through the add() function
std::map<std::string, Boxed_Value> get_locals() const std::map<std::string, Boxed_Value> get_locals() const { return m_engine.get_locals(); }
{
return m_engine.get_locals();
}
/// \brief Sets all of the locals for the current thread state. /// \brief Sets all of the locals for the current thread state.
/// ///
/// \param[in] t_locals The map<name, value> set of variables to replace the current state with /// \param[in] t_locals The map<name, value> set of variables to replace the current state with
/// ///
/// Any existing locals are removed and the given set of variables is added /// 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) void set_locals(const std::map<std::string, Boxed_Value> &t_locals) { m_engine.set_locals(t_locals); }
{
m_engine.set_locals(t_locals);
}
/// \brief Adds a type, function or object to ChaiScript. Objects are added to the local thread state. /// \brief Adds a type, function or object to ChaiScript. Objects are added to the local thread state.
/// \param[in] t_t Item to add /// \param[in] t_t Item to add
@ -549,8 +492,7 @@ namespace chaiscript
/// ///
/// \sa \ref adding_items /// \sa \ref adding_items
template<typename T> template<typename T>
ChaiScript_Basic &add(const T &t_t, const std::string &t_name) ChaiScript_Basic &add(const T &t_t, const std::string &t_name) {
{
Name_Validator::validate_object_name(t_name); Name_Validator::validate_object_name(t_name);
m_engine.add(t_t, t_name); m_engine.add(t_t, t_name);
return *this; return *this;
@ -565,8 +507,7 @@ namespace chaiscript
/// chaiscript::ChaiScript chai; /// chaiscript::ChaiScript chai;
/// chai.add(chaiscript::base_class<std::runtime_error, chaiscript::dispatch_error>()); /// chai.add(chaiscript::base_class<std::runtime_error, chaiscript::dispatch_error>());
/// \endcode /// \endcode
ChaiScript_Basic &add(const Type_Conversion &d) ChaiScript_Basic &add(const Type_Conversion &d) {
{
m_engine.add(d); m_engine.add(d);
return *this; return *this;
} }
@ -574,8 +515,7 @@ namespace chaiscript
/// \brief Adds all elements of a module to ChaiScript runtime /// \brief Adds all elements of a module to ChaiScript runtime
/// \param[in] t_p The module to add. /// \param[in] t_p The module to add.
/// \sa chaiscript::Module /// \sa chaiscript::Module
ChaiScript_Basic &add(const ModulePtr &t_p) ChaiScript_Basic &add(const ModulePtr &t_p) {
{
t_p->apply(*this, this->get_eval_engine()); t_p->apply(*this, this->get_eval_engine());
return *this; return *this;
} }
@ -592,16 +532,14 @@ namespace chaiscript
/// (the symbol mentioned above), an exception is thrown. /// (the symbol mentioned above), an exception is thrown.
/// ///
/// \throw chaiscript::exception::load_module_error In the event that no matching module can be found. /// \throw chaiscript::exception::load_module_error In the event that no matching module can be found.
std::string load_module(const std::string &t_module_name) std::string load_module(const std::string &t_module_name) {
{
#ifdef CHAISCRIPT_NO_DYNLOAD #ifdef CHAISCRIPT_NO_DYNLOAD
throw chaiscript::exception::load_module_error("Loadable module support was disabled (CHAISCRIPT_NO_DYNLOAD)"); throw chaiscript::exception::load_module_error("Loadable module support was disabled (CHAISCRIPT_NO_DYNLOAD)");
#else #else
std::vector<exception::load_module_error> errors; std::vector<exception::load_module_error> errors;
std::string version_stripped_name = t_module_name; std::string version_stripped_name = t_module_name;
size_t version_pos = version_stripped_name.find("-" + Build_Info::version()); size_t version_pos = version_stripped_name.find("-" + Build_Info::version());
if (version_pos != std::string::npos) if (version_pos != std::string::npos) {
{
version_stripped_name.erase(version_pos); version_stripped_name.erase(version_pos);
} }
@ -609,12 +547,9 @@ namespace chaiscript
std::vector<std::string> postfixes{".dll", ".so", ".bundle", ""}; std::vector<std::string> postfixes{".dll", ".so", ".bundle", ""};
for (auto & elem : m_module_paths) for (auto &elem : m_module_paths) {
{ for (auto &prefix : prefixes) {
for (auto & prefix : prefixes) for (auto &postfix : postfixes) {
{
for (auto & postfix : postfixes)
{
try { try {
const auto name = elem + prefix + t_module_name + postfix; const auto name = elem + prefix + t_module_name + postfix;
// std::cerr << "trying location: " << name << '\n'; // std::cerr << "trying location: " << name << '\n';
@ -640,12 +575,10 @@ namespace chaiscript
/// \param[in] t_filename Ignore normal filename search process and use specific filename /// \param[in] t_filename Ignore normal filename search process and use specific filename
/// ///
/// \sa ChaiScript::load_module(const std::string &t_module_name) /// \sa ChaiScript::load_module(const std::string &t_module_name)
void load_module(const std::string &t_module_name, const std::string &t_filename) void load_module(const std::string &t_module_name, const std::string &t_filename) {
{
chaiscript::detail::threading::lock_guard<chaiscript::detail::threading::recursive_mutex> l(m_use_mutex); chaiscript::detail::threading::lock_guard<chaiscript::detail::threading::recursive_mutex> l(m_use_mutex);
if (m_loaded_modules.count(t_module_name) == 0) if (m_loaded_modules.count(t_module_name) == 0) {
{
detail::Loadable_Module_Ptr lm(new detail::Loadable_Module(t_module_name, t_filename)); detail::Loadable_Module_Ptr lm(new detail::Loadable_Module(t_module_name, t_filename));
m_loaded_modules[t_module_name] = lm; m_loaded_modules[t_module_name] = lm;
m_active_loaded_modules.insert(t_module_name); m_active_loaded_modules.insert(t_module_name);
@ -656,7 +589,6 @@ namespace chaiscript
} }
} }
/// \brief Evaluates a string. Equivalent to ChaiScript::eval. /// \brief Evaluates a string. Equivalent to ChaiScript::eval.
/// ///
/// \param[in] t_script Script to execute /// \param[in] t_script Script to execute
@ -665,8 +597,7 @@ namespace chaiscript
/// \return result of the script execution /// \return result of the script execution
/// ///
/// \throw chaiscript::exception::eval_error In the case that evaluation fails. /// \throw chaiscript::exception::eval_error In the case that evaluation fails.
Boxed_Value operator()(const std::string &t_script, const Exception_Handler &t_handler = Exception_Handler()) Boxed_Value operator()(const std::string &t_script, const Exception_Handler &t_handler = Exception_Handler()) {
{
return eval(t_script, t_handler); return eval(t_script, t_handler);
} }
@ -684,19 +615,16 @@ namespace chaiscript
/// \throw chaiscript::exception::bad_boxed_cast In the case that evaluation succeeds but the result value cannot be converted /// \throw chaiscript::exception::bad_boxed_cast In the case that evaluation succeeds but the result value cannot be converted
/// to the requested type. /// to the requested type.
template<typename T> template<typename T>
T eval(const std::string &t_input, const Exception_Handler &t_handler = Exception_Handler(), const std::string &t_filename="__EVAL__") T eval(const std::string &t_input, const Exception_Handler &t_handler = Exception_Handler(), const std::string &t_filename = "__EVAL__") {
{
return m_engine.boxed_cast<T>(eval(t_input, t_handler, t_filename)); return m_engine.boxed_cast<T>(eval(t_input, t_handler, t_filename));
} }
/// \brief casts an object while applying any Dynamic_Conversion available /// \brief casts an object while applying any Dynamic_Conversion available
template<typename Type> template<typename Type>
decltype(auto) boxed_cast(const Boxed_Value &bv) const decltype(auto) boxed_cast(const Boxed_Value &bv) const {
{ return (m_engine.boxed_cast<Type>(bv));
return(m_engine.boxed_cast<Type>(bv));
} }
/// \brief Evaluates a string. /// \brief Evaluates a string.
/// ///
/// \param[in] t_input Script to execute /// \param[in] t_input Script to execute
@ -707,8 +635,8 @@ namespace chaiscript
/// \return result of the script execution /// \return result of the script execution
/// ///
/// \throw exception::eval_error In the case that evaluation fails. /// \throw exception::eval_error In the case that evaluation fails.
Boxed_Value eval(const std::string &t_input, const Exception_Handler &t_handler = Exception_Handler(), const std::string &t_filename="__EVAL__") Boxed_Value
{ eval(const std::string &t_input, const Exception_Handler &t_handler = Exception_Handler(), const std::string &t_filename = "__EVAL__") {
try { try {
return do_eval(t_input, t_filename); return do_eval(t_input, t_filename);
} catch (Boxed_Value &bv) { } catch (Boxed_Value &bv) {
@ -744,39 +672,35 @@ namespace chaiscript
/// \brief Imports a namespace object into the global scope of this ChaiScript instance. /// \brief Imports a namespace object into the global scope of this ChaiScript instance.
/// \param[in] t_namespace_name Name of the namespace to import. /// \param[in] t_namespace_name Name of the namespace to import.
/// \throw std::runtime_error In the case that the namespace name was never registered. /// \throw std::runtime_error In the case that the namespace name was never registered.
void import(const std::string& t_namespace_name) void import(const std::string &t_namespace_name) {
{
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::recursive_mutex> l(m_use_mutex); chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::recursive_mutex> l(m_use_mutex);
if (m_engine.get_scripting_objects().count(t_namespace_name)) { if (m_engine.get_scripting_objects().count(t_namespace_name)) {
throw std::runtime_error("Namespace: " + t_namespace_name + " was already defined"); throw std::runtime_error("Namespace: " + t_namespace_name + " was already defined");
} } else if (m_namespace_generators.count(t_namespace_name)) {
else if (m_namespace_generators.count(t_namespace_name)) {
m_engine.add_global(var(std::ref(m_namespace_generators[t_namespace_name]())), t_namespace_name); m_engine.add_global(var(std::ref(m_namespace_generators[t_namespace_name]())), t_namespace_name);
} } else {
else {
throw std::runtime_error("No registered namespace: " + t_namespace_name); throw std::runtime_error("No registered namespace: " + t_namespace_name);
} }
} }
/// \brief Registers a namespace generator, which delays generation of the namespace until it is imported, saving memory if it is never used. /// \brief Registers a namespace generator, which delays generation of the namespace until it is imported, saving memory if it is never
/// \param[in] t_namespace_generator Namespace generator function. /// used. \param[in] t_namespace_generator Namespace generator function. \param[in] t_namespace_name Name of the Namespace function
/// \param[in] t_namespace_name Name of the Namespace function being registered. /// being registered. \throw std::runtime_error In the case that the namespace name was already registered.
/// \throw std::runtime_error In the case that the namespace name was already registered. void register_namespace(const std::function<void(Namespace &)> &t_namespace_generator, const std::string &t_namespace_name) {
void register_namespace(const std::function<void(Namespace&)>& t_namespace_generator, const std::string& t_namespace_name)
{
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::recursive_mutex> l(m_use_mutex); chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::recursive_mutex> l(m_use_mutex);
if (!m_namespace_generators.count(t_namespace_name)) { if (!m_namespace_generators.count(t_namespace_name)) {
// contain the namespace object memory within the m_namespace_generators map // contain the namespace object memory within the m_namespace_generators map
m_namespace_generators.emplace(std::make_pair(t_namespace_name, [=, space = Namespace()]() mutable -> Namespace& { t_namespace_generator(space); return space; })); m_namespace_generators.emplace(std::make_pair(t_namespace_name, [=, space = Namespace()]() mutable -> Namespace & {
} t_namespace_generator(space);
else { return space;
}));
} else {
throw std::runtime_error("Namespace: " + t_namespace_name + " was already registered."); throw std::runtime_error("Namespace: " + t_namespace_name + " was already registered.");
} }
} }
}; };
} } // namespace chaiscript
#endif /* CHAISCRIPT_ENGINE_HPP_ */ #endif /* CHAISCRIPT_ENGINE_HPP_ */

File diff suppressed because it is too large Load Diff

View File

@ -9,22 +9,18 @@
#include "chaiscript_eval.hpp" #include "chaiscript_eval.hpp"
namespace chaiscript { namespace chaiscript {
namespace optimizer { namespace optimizer {
template<typename... T>
template<typename ... T> struct Optimizer : T... {
struct Optimizer : T...
{
Optimizer() = default; Optimizer() = default;
explicit Optimizer(T ... t) explicit Optimizer(T... t)
: T(std::move(t))... : T(std::move(t))... {
{
} }
template<typename Tracer> template<typename Tracer>
auto optimize(eval::AST_Node_Impl_Ptr<Tracer> p) { auto optimize(eval::AST_Node_Impl_Ptr<Tracer> p) {
( (p = static_cast<T&>(*this).optimize(std::move(p))), ... ); ((p = static_cast<T &>(*this).optimize(std::move(p))), ...);
return p; return p;
} }
}; };
@ -46,7 +42,6 @@ namespace chaiscript {
return *node.children[offset]; return *node.children[offset];
} }
/* /*
if (node->identifier == AST_Node_Type::Compiled) { if (node->identifier == AST_Node_Type::Compiled) {
return dynamic_cast<const eval::Compiled_AST_Node<T>&>(*node).m_original_node->children[offset]; return dynamic_cast<const eval::Compiled_AST_Node<T>&>(*node).m_original_node->children[offset];
@ -59,26 +54,23 @@ namespace chaiscript {
template<typename T> template<typename T>
auto child_count(const eval::AST_Node_Impl<T> &node) noexcept { auto child_count(const eval::AST_Node_Impl<T> &node) noexcept {
if (node.identifier == AST_Node_Type::Compiled) { if (node.identifier == AST_Node_Type::Compiled) {
return dynamic_cast<const eval::Compiled_AST_Node<T>&>(node).m_original_node->children.size(); return dynamic_cast<const eval::Compiled_AST_Node<T> &>(node).m_original_node->children.size();
} else { } else {
return node.children.size(); return node.children.size();
} }
} }
template<typename T, typename Callable> template<typename T, typename Callable>
auto make_compiled_node(eval::AST_Node_Impl_Ptr<T> original_node, std::vector<eval::AST_Node_Impl_Ptr<T>> children, Callable callable) auto make_compiled_node(eval::AST_Node_Impl_Ptr<T> original_node, std::vector<eval::AST_Node_Impl_Ptr<T>> children, Callable callable) {
{ return chaiscript::make_unique<eval::AST_Node_Impl<T>, eval::Compiled_AST_Node<T>>(std::move(original_node),
return chaiscript::make_unique<eval::AST_Node_Impl<T>, eval::Compiled_AST_Node<T>>(std::move(original_node), std::move(children), std::move(callable)); std::move(children),
std::move(callable));
} }
struct Return { struct Return {
template<typename T> template<typename T>
auto optimize(eval::AST_Node_Impl_Ptr<T> p) auto optimize(eval::AST_Node_Impl_Ptr<T> p) {
{ if ((p->identifier == AST_Node_Type::Def || p->identifier == AST_Node_Type::Lambda) && !p->children.empty()) {
if ( (p->identifier == AST_Node_Type::Def || p->identifier == AST_Node_Type::Lambda)
&& !p->children.empty())
{
auto &last_child = p->children.back(); auto &last_child = p->children.back();
if (last_child->identifier == AST_Node_Type::Block) { if (last_child->identifier == AST_Node_Type::Block) {
auto &block_last_child = last_child->children.back(); auto &block_last_child = last_child->children.back();
@ -95,9 +87,9 @@ namespace chaiscript {
}; };
template<typename T> template<typename T>
bool contains_var_decl_in_scope(const eval::AST_Node_Impl<T> &node) noexcept bool contains_var_decl_in_scope(const eval::AST_Node_Impl<T> &node) noexcept {
{ if (node.identifier == AST_Node_Type::Var_Decl || node.identifier == AST_Node_Type::Assign_Decl
if (node.identifier == AST_Node_Type::Var_Decl || node.identifier == AST_Node_Type::Assign_Decl || node.identifier == AST_Node_Type::Reference) { || node.identifier == AST_Node_Type::Reference) {
return true; return true;
} }
@ -105,10 +97,8 @@ namespace chaiscript {
for (size_t i = 0; i < num; ++i) { for (size_t i = 0; i < num; ++i) {
const auto &child = child_at(node, i); const auto &child = child_at(node, i);
if (child.identifier != AST_Node_Type::Block if (child.identifier != AST_Node_Type::Block && child.identifier != AST_Node_Type::For
&& child.identifier != AST_Node_Type::For && child.identifier != AST_Node_Type::Ranged_For && contains_var_decl_in_scope(child)) {
&& child.identifier != AST_Node_Type::Ranged_For
&& contains_var_decl_in_scope(child)) {
return true; return true;
} }
} }
@ -119,14 +109,13 @@ namespace chaiscript {
struct Block { struct Block {
template<typename T> template<typename T>
auto optimize(eval::AST_Node_Impl_Ptr<T> node) { auto optimize(eval::AST_Node_Impl_Ptr<T> node) {
if (node->identifier == AST_Node_Type::Block) if (node->identifier == AST_Node_Type::Block) {
{ if (!contains_var_decl_in_scope(*node)) {
if (!contains_var_decl_in_scope(*node))
{
if (node->children.size() == 1) { if (node->children.size() == 1) {
return std::move(node->children[0]); return std::move(node->children[0]);
} else { } else {
return chaiscript::make_unique<eval::AST_Node_Impl<T>, eval::Scopeless_Block_AST_Node<T>>(node->text, node->location, return chaiscript::make_unique<eval::AST_Node_Impl<T>, eval::Scopeless_Block_AST_Node<T>>(node->text,
node->location,
std::move(node->children)); std::move(node->children));
} }
} }
@ -139,16 +128,14 @@ namespace chaiscript {
struct Dead_Code { struct Dead_Code {
template<typename T> template<typename T>
auto optimize(eval::AST_Node_Impl_Ptr<T> node) { auto optimize(eval::AST_Node_Impl_Ptr<T> node) {
if (node->identifier == AST_Node_Type::Block) if (node->identifier == AST_Node_Type::Block) {
{
std::vector<size_t> keepers; std::vector<size_t> keepers;
const auto num_children = node->children.size(); const auto num_children = node->children.size();
keepers.reserve(num_children); keepers.reserve(num_children);
for (size_t i = 0; i < num_children; ++i) { for (size_t i = 0; i < num_children; ++i) {
const auto &child = *node->children[i]; const auto &child = *node->children[i];
if ( (child.identifier != AST_Node_Type::Id if ((child.identifier != AST_Node_Type::Id && child.identifier != AST_Node_Type::Constant
&& child.identifier != AST_Node_Type::Constant
&& child.identifier != AST_Node_Type::Noop) && child.identifier != AST_Node_Type::Noop)
|| i == num_children - 1) { || i == num_children - 1) {
keepers.push_back(i); keepers.push_back(i);
@ -158,10 +145,9 @@ namespace chaiscript {
if (keepers.size() == num_children) { if (keepers.size() == num_children) {
return node; return node;
} else { } else {
const auto new_children = [&](){ const auto new_children = [&]() {
std::vector<eval::AST_Node_Impl_Ptr<T>> retval; std::vector<eval::AST_Node_Impl_Ptr<T>> retval;
for (const auto x : keepers) for (const auto x : keepers) {
{
retval.push_back(std::move(node->children[x])); retval.push_back(std::move(node->children[x]));
} }
return retval; return retval;
@ -178,29 +164,25 @@ namespace chaiscript {
struct Unused_Return { struct Unused_Return {
template<typename T> template<typename T>
auto optimize(eval::AST_Node_Impl_Ptr<T> node) { auto optimize(eval::AST_Node_Impl_Ptr<T> node) {
if ((node->identifier == AST_Node_Type::Block if ((node->identifier == AST_Node_Type::Block || node->identifier == AST_Node_Type::Scopeless_Block) && !node->children.empty()) {
|| node->identifier == AST_Node_Type::Scopeless_Block) for (size_t i = 0; i < node->children.size() - 1; ++i) {
&& !node->children.empty())
{
for (size_t i = 0; i < node->children.size()-1; ++i) {
auto child = node->children[i].get(); auto child = node->children[i].get();
if (child->identifier == AST_Node_Type::Fun_Call) { if (child->identifier == AST_Node_Type::Fun_Call) {
node->children[i] = chaiscript::make_unique<eval::AST_Node_Impl<T>, eval::Unused_Return_Fun_Call_AST_Node<T>>(child->text, child->location, node->children[i]
= chaiscript::make_unique<eval::AST_Node_Impl<T>, eval::Unused_Return_Fun_Call_AST_Node<T>>(child->text,
child->location,
std::move(child->children)); std::move(child->children));
} }
} }
} else if ((node->identifier == AST_Node_Type::For } else if ((node->identifier == AST_Node_Type::For || node->identifier == AST_Node_Type::While) && child_count(*node) > 0) {
|| node->identifier == AST_Node_Type::While)
&& child_count(*node) > 0) {
auto &child = child_at(*node, child_count(*node) - 1); auto &child = child_at(*node, child_count(*node) - 1);
if (child.identifier == AST_Node_Type::Block if (child.identifier == AST_Node_Type::Block || child.identifier == AST_Node_Type::Scopeless_Block) {
|| child.identifier == AST_Node_Type::Scopeless_Block)
{
auto num_sub_children = child_count(child); auto num_sub_children = child_count(child);
for (size_t i = 0; i < num_sub_children; ++i) { for (size_t i = 0; i < num_sub_children; ++i) {
auto &sub_child = child_at(child, i); auto &sub_child = child_at(child, i);
if (sub_child.identifier == AST_Node_Type::Fun_Call) { if (sub_child.identifier == AST_Node_Type::Fun_Call) {
child.children[i] = chaiscript::make_unique<eval::AST_Node_Impl<T>, eval::Unused_Return_Fun_Call_AST_Node<T>>(sub_child.text, sub_child.location, std::move(sub_child.children)); child.children[i] = chaiscript::make_unique<eval::AST_Node_Impl<T>, eval::Unused_Return_Fun_Call_AST_Node<T>>(
sub_child.text, sub_child.location, std::move(sub_child.children));
} }
} }
} }
@ -212,31 +194,24 @@ namespace chaiscript {
struct Assign_Decl { struct Assign_Decl {
template<typename T> template<typename T>
auto optimize(eval::AST_Node_Impl_Ptr<T> node) { auto optimize(eval::AST_Node_Impl_Ptr<T> node) {
if ((node->identifier == AST_Node_Type::Equation) if ((node->identifier == AST_Node_Type::Equation) && node->text == "=" && node->children.size() == 2
&& node->text == "=" && node->children[0]->identifier == AST_Node_Type::Var_Decl) {
&& node->children.size() == 2
&& node->children[0]->identifier == AST_Node_Type::Var_Decl
)
{
std::vector<eval::AST_Node_Impl_Ptr<T>> new_children; std::vector<eval::AST_Node_Impl_Ptr<T>> new_children;
new_children.push_back(std::move(node->children[0]->children[0])); new_children.push_back(std::move(node->children[0]->children[0]));
new_children.push_back(std::move(node->children[1])); new_children.push_back(std::move(node->children[1]));
return chaiscript::make_unique<eval::AST_Node_Impl<T>, eval::Assign_Decl_AST_Node<T>>(node->text, return chaiscript::make_unique<eval::AST_Node_Impl<T>, eval::Assign_Decl_AST_Node<T>>(node->text,
node->location, std::move(new_children) ); node->location,
std::move(new_children));
} }
return node; return node;
} }
}; };
struct If { struct If {
template<typename T> template<typename T>
auto optimize(eval::AST_Node_Impl_Ptr<T> node) { auto optimize(eval::AST_Node_Impl_Ptr<T> node) {
if ((node->identifier == AST_Node_Type::If) if ((node->identifier == AST_Node_Type::If) && node->children.size() >= 2 && node->children[0]->identifier == AST_Node_Type::Constant) {
&& node->children.size() >= 2
&& node->children[0]->identifier == AST_Node_Type::Constant)
{
const auto condition = dynamic_cast<eval::Constant_AST_Node<T> *>(node->children[0].get())->m_value; const auto condition = dynamic_cast<eval::Constant_AST_Node<T> *>(node->children[0].get())->m_value;
if (condition.get_type_info().bare_equal_type_info(typeid(bool))) { if (condition.get_type_info().bare_equal_type_info(typeid(bool))) {
if (boxed_cast<bool>(condition)) { if (boxed_cast<bool>(condition)) {
@ -254,25 +229,21 @@ namespace chaiscript {
struct Partial_Fold { struct Partial_Fold {
template<typename T> template<typename T>
auto optimize(eval::AST_Node_Impl_Ptr<T> node) { auto optimize(eval::AST_Node_Impl_Ptr<T> node) {
// Fold right side // Fold right side
if (node->identifier == AST_Node_Type::Binary if (node->identifier == AST_Node_Type::Binary && node->children.size() == 2
&& node->children.size() == 2 && node->children[0]->identifier != AST_Node_Type::Constant && node->children[1]->identifier == AST_Node_Type::Constant) {
&& node->children[0]->identifier != AST_Node_Type::Constant
&& node->children[1]->identifier == AST_Node_Type::Constant)
{
try { try {
const auto &oper = node->text; const auto &oper = node->text;
const auto parsed = Operators::to_operator(oper); const auto parsed = Operators::to_operator(oper);
if (parsed != Operators::Opers::invalid) { if (parsed != Operators::Opers::invalid) {
const auto rhs = dynamic_cast<eval::Constant_AST_Node<T> *>(node->children[1].get())->m_value; const auto rhs = dynamic_cast<eval::Constant_AST_Node<T> *>(node->children[1].get())->m_value;
if (rhs.get_type_info().is_arithmetic()) { if (rhs.get_type_info().is_arithmetic()) {
return chaiscript::make_unique<eval::AST_Node_Impl<T>, eval::Fold_Right_Binary_Operator_AST_Node<T>>(node->text, node->location, return chaiscript::make_unique<eval::AST_Node_Impl<T>, eval::Fold_Right_Binary_Operator_AST_Node<T>>(
std::move(node->children), rhs); node->text, node->location, std::move(node->children), rhs);
} }
} }
} catch (const std::exception &) { } catch (const std::exception &) {
//failure to fold, that's OK // failure to fold, that's OK
} }
} }
@ -283,11 +254,7 @@ namespace chaiscript {
struct Constant_Fold { struct Constant_Fold {
template<typename T> template<typename T>
auto optimize(eval::AST_Node_Impl_Ptr<T> node) { auto optimize(eval::AST_Node_Impl_Ptr<T> node) {
if (node->identifier == AST_Node_Type::Prefix && node->children.size() == 1 && node->children[0]->identifier == AST_Node_Type::Constant) {
if (node->identifier == AST_Node_Type::Prefix
&& node->children.size() == 1
&& node->children[0]->identifier == AST_Node_Type::Constant)
{
try { try {
const auto &oper = node->text; const auto &oper = node->text;
const auto parsed = Operators::to_operator(oper, true); const auto parsed = Operators::to_operator(oper, true);
@ -296,38 +263,42 @@ namespace chaiscript {
if (parsed != Operators::Opers::invalid && parsed != Operators::Opers::bitwise_and && lhs.get_type_info().is_arithmetic()) { if (parsed != Operators::Opers::invalid && parsed != Operators::Opers::bitwise_and && lhs.get_type_info().is_arithmetic()) {
const auto val = Boxed_Number::do_oper(parsed, lhs); const auto val = Boxed_Number::do_oper(parsed, lhs);
return chaiscript::make_unique<eval::AST_Node_Impl<T>, eval::Constant_AST_Node<T>>(std::move(match), node->location, std::move(val)); return chaiscript::make_unique<eval::AST_Node_Impl<T>, eval::Constant_AST_Node<T>>(std::move(match),
node->location,
std::move(val));
} else if (lhs.get_type_info().bare_equal_type_info(typeid(bool)) && oper == "!") { } else if (lhs.get_type_info().bare_equal_type_info(typeid(bool)) && oper == "!") {
return chaiscript::make_unique<eval::AST_Node_Impl<T>, eval::Constant_AST_Node<T>>(std::move(match), node->location, Boxed_Value(!boxed_cast<bool>(lhs))); return chaiscript::make_unique<eval::AST_Node_Impl<T>, eval::Constant_AST_Node<T>>(std::move(match),
node->location,
Boxed_Value(!boxed_cast<bool>(lhs)));
} }
} catch (const std::exception &) { } catch (const std::exception &) {
//failure to fold, that's OK // failure to fold, that's OK
} }
} else if ((node->identifier == AST_Node_Type::Logical_And || node->identifier == AST_Node_Type::Logical_Or) } else if ((node->identifier == AST_Node_Type::Logical_And || node->identifier == AST_Node_Type::Logical_Or)
&& node->children.size() == 2 && node->children.size() == 2 && node->children[0]->identifier == AST_Node_Type::Constant
&& node->children[0]->identifier == AST_Node_Type::Constant && node->children[1]->identifier == AST_Node_Type::Constant) {
&& node->children[1]->identifier == AST_Node_Type::Constant)
{
try { try {
const auto lhs = dynamic_cast<const eval::Constant_AST_Node<T> &>(*node->children[0]).m_value; const auto lhs = dynamic_cast<const eval::Constant_AST_Node<T> &>(*node->children[0]).m_value;
const auto rhs = dynamic_cast<const eval::Constant_AST_Node<T> &>(*node->children[1]).m_value; const auto rhs = dynamic_cast<const eval::Constant_AST_Node<T> &>(*node->children[1]).m_value;
if (lhs.get_type_info().bare_equal_type_info(typeid(bool)) && rhs.get_type_info().bare_equal_type_info(typeid(bool))) { if (lhs.get_type_info().bare_equal_type_info(typeid(bool)) && rhs.get_type_info().bare_equal_type_info(typeid(bool))) {
const auto match = node->children[0]->text + " " + node->text + " " + node->children[1]->text; const auto match = node->children[0]->text + " " + node->text + " " + node->children[1]->text;
const auto val = [lhs_val = boxed_cast<bool>(lhs), rhs_val = boxed_cast<bool>(rhs), id = node->identifier] { const auto val = [lhs_val = boxed_cast<bool>(lhs), rhs_val = boxed_cast<bool>(rhs), id = node->identifier] {
if (id == AST_Node_Type::Logical_And) { return Boxed_Value(lhs_val && rhs_val); } if (id == AST_Node_Type::Logical_And) {
else { return Boxed_Value(lhs_val || rhs_val); } return Boxed_Value(lhs_val && rhs_val);
} else {
return Boxed_Value(lhs_val || rhs_val);
}
}(); }();
return chaiscript::make_unique<eval::AST_Node_Impl<T>, eval::Constant_AST_Node<T>>(std::move(match), node->location, std::move(val)); return chaiscript::make_unique<eval::AST_Node_Impl<T>, eval::Constant_AST_Node<T>>(std::move(match),
node->location,
std::move(val));
} }
} catch (const std::exception &) { } catch (const std::exception &) {
//failure to fold, that's OK // failure to fold, that's OK
} }
} else if (node->identifier == AST_Node_Type::Binary } else if (node->identifier == AST_Node_Type::Binary && node->children.size() == 2
&& node->children.size() == 2 && node->children[0]->identifier == AST_Node_Type::Constant && node->children[1]->identifier == AST_Node_Type::Constant) {
&& node->children[0]->identifier == AST_Node_Type::Constant
&& node->children[1]->identifier == AST_Node_Type::Constant)
{
try { try {
const auto &oper = node->text; const auto &oper = node->text;
const auto parsed = Operators::to_operator(oper); const auto parsed = Operators::to_operator(oper);
@ -337,26 +308,26 @@ namespace chaiscript {
if (lhs.get_type_info().is_arithmetic() && rhs.get_type_info().is_arithmetic()) { if (lhs.get_type_info().is_arithmetic() && rhs.get_type_info().is_arithmetic()) {
const auto val = Boxed_Number::do_oper(parsed, lhs, rhs); const auto val = Boxed_Number::do_oper(parsed, lhs, rhs);
const auto match = node->children[0]->text + " " + oper + " " + node->children[1]->text; const auto match = node->children[0]->text + " " + oper + " " + node->children[1]->text;
return chaiscript::make_unique<eval::AST_Node_Impl<T>, eval::Constant_AST_Node<T>>(std::move(match), node->location, std::move(val)); return chaiscript::make_unique<eval::AST_Node_Impl<T>, eval::Constant_AST_Node<T>>(std::move(match),
node->location,
std::move(val));
} }
} }
} catch (const std::exception &) { } catch (const std::exception &) {
//failure to fold, that's OK // failure to fold, that's OK
} }
} else if (node->identifier == AST_Node_Type::Fun_Call } else if (node->identifier == AST_Node_Type::Fun_Call && node->children.size() == 2
&& node->children.size() == 2 && node->children[0]->identifier == AST_Node_Type::Id && node->children[1]->identifier == AST_Node_Type::Arg_List
&& node->children[0]->identifier == AST_Node_Type::Id && node->children[1]->children.size() == 1 && node->children[1]->children[0]->identifier == AST_Node_Type::Constant) {
&& node->children[1]->identifier == AST_Node_Type::Arg_List
&& node->children[1]->children.size() == 1
&& node->children[1]->children[0]->identifier == AST_Node_Type::Constant) {
const auto arg = dynamic_cast<const eval::Constant_AST_Node<T> &>(*node->children[1]->children[0]).m_value; const auto arg = dynamic_cast<const eval::Constant_AST_Node<T> &>(*node->children[1]->children[0]).m_value;
if (arg.get_type_info().is_arithmetic()) { if (arg.get_type_info().is_arithmetic()) {
const auto &fun_name = node->children[0]->text; const auto &fun_name = node->children[0]->text;
const auto make_constant = [&node, &fun_name](auto val){ const auto make_constant = [&node, &fun_name](auto val) {
const auto match = fun_name + "(" + node->children[1]->children[0]->text + ")"; const auto match = fun_name + "(" + node->children[1]->children[0]->text + ")";
return chaiscript::make_unique<eval::AST_Node_Impl<T>, eval::Constant_AST_Node<T>>(std::move(match), node->location, const_var(val)); return chaiscript::make_unique<eval::AST_Node_Impl<T>, eval::Constant_AST_Node<T>>(std::move(match),
node->location,
const_var(val));
}; };
if (fun_name == "double") { if (fun_name == "double") {
@ -370,10 +341,7 @@ namespace chaiscript {
} else if (fun_name == "size_t") { } else if (fun_name == "size_t") {
return make_constant(Boxed_Number(arg).get_as<size_t>()); return make_constant(Boxed_Number(arg).get_as<size_t>());
} }
} }
} }
return node; return node;
@ -383,7 +351,6 @@ namespace chaiscript {
struct For_Loop { struct For_Loop {
template<typename T> template<typename T>
auto optimize(eval::AST_Node_Impl_Ptr<T> for_node) { auto optimize(eval::AST_Node_Impl_Ptr<T> for_node) {
if (for_node->identifier != AST_Node_Type::For) { if (for_node->identifier != AST_Node_Type::For) {
return for_node; return for_node;
} }
@ -392,30 +359,18 @@ namespace chaiscript {
const auto &binary_node = child_at(*for_node, 1); const auto &binary_node = child_at(*for_node, 1);
const auto &prefix_node = child_at(*for_node, 2); const auto &prefix_node = child_at(*for_node, 2);
if (child_count(*for_node) == 4 if (child_count(*for_node) == 4 && eq_node.identifier == AST_Node_Type::Assign_Decl && child_count(eq_node) == 2
&& eq_node.identifier == AST_Node_Type::Assign_Decl && child_at(eq_node, 0).identifier == AST_Node_Type::Id && child_at(eq_node, 1).identifier == AST_Node_Type::Constant
&& child_count(eq_node) == 2 && binary_node.identifier == AST_Node_Type::Binary && binary_node.text == "<" && child_count(binary_node) == 2
&& child_at(eq_node, 0).identifier == AST_Node_Type::Id && child_at(binary_node, 0).identifier == AST_Node_Type::Id && child_at(binary_node, 0).text == child_at(eq_node, 0).text
&& child_at(eq_node, 1).identifier == AST_Node_Type::Constant && child_at(binary_node, 1).identifier == AST_Node_Type::Constant && prefix_node.identifier == AST_Node_Type::Prefix
&& binary_node.identifier == AST_Node_Type::Binary && prefix_node.text == "++" && child_count(prefix_node) == 1 && child_at(prefix_node, 0).identifier == AST_Node_Type::Id
&& binary_node.text == "<" && child_at(prefix_node, 0).text == child_at(eq_node, 0).text) {
&& child_count(binary_node) == 2
&& child_at(binary_node, 0).identifier == AST_Node_Type::Id
&& child_at(binary_node, 0).text == child_at(eq_node,0).text
&& child_at(binary_node, 1).identifier == AST_Node_Type::Constant
&& prefix_node.identifier == AST_Node_Type::Prefix
&& prefix_node.text == "++"
&& child_count(prefix_node) == 1
&& child_at(prefix_node, 0).identifier == AST_Node_Type::Id
&& child_at(prefix_node, 0).text == child_at(eq_node,0).text)
{
const Boxed_Value &begin = dynamic_cast<const eval::Constant_AST_Node<T> &>(child_at(eq_node, 1)).m_value; const Boxed_Value &begin = dynamic_cast<const eval::Constant_AST_Node<T> &>(child_at(eq_node, 1)).m_value;
const Boxed_Value &end = dynamic_cast<const eval::Constant_AST_Node<T> &>(child_at(binary_node, 1)).m_value; const Boxed_Value &end = dynamic_cast<const eval::Constant_AST_Node<T> &>(child_at(binary_node, 1)).m_value;
const std::string &id = child_at(prefix_node, 0).text; const std::string &id = child_at(prefix_node, 0).text;
if (begin.get_type_info().bare_equal(user_type<int>()) if (begin.get_type_info().bare_equal(user_type<int>()) && end.get_type_info().bare_equal(user_type<int>())) {
&& end.get_type_info().bare_equal(user_type<int>())) {
const auto start_int = boxed_cast<int>(begin); const auto start_int = boxed_cast<int>(begin);
const auto end_int = boxed_cast<int>(end); const auto end_int = boxed_cast<int>(end);
@ -426,8 +381,10 @@ namespace chaiscript {
for_node->children.pop_back(); for_node->children.pop_back();
body_vector.emplace_back(std::move(body_child)); body_vector.emplace_back(std::move(body_child));
return make_compiled_node(std::move(for_node), std::move(body_vector), return make_compiled_node(std::move(for_node),
[id, start_int, end_int](const std::vector<eval::AST_Node_Impl_Ptr<T>> &children, const chaiscript::detail::Dispatch_State &t_ss) { std::move(body_vector),
[id, start_int, end_int](const std::vector<eval::AST_Node_Impl_Ptr<T>> &children,
const chaiscript::detail::Dispatch_State &t_ss) {
assert(children.size() == 1); assert(children.size() == 1);
chaiscript::eval::detail::Scope_Push_Pop spp(t_ss); chaiscript::eval::detail::Scope_Push_Pop spp(t_ss);
@ -450,8 +407,7 @@ namespace chaiscript {
} }
return void_var(); return void_var();
} });
);
} else { } else {
return for_node; return for_node;
} }
@ -461,12 +417,17 @@ namespace chaiscript {
} }
}; };
using Optimizer_Default = Optimizer<optimizer::Partial_Fold, optimizer::Unused_Return, optimizer::Constant_Fold, using Optimizer_Default = Optimizer<optimizer::Partial_Fold,
optimizer::If, optimizer::Return, optimizer::Dead_Code, optimizer::Block, optimizer::For_Loop, optimizer::Assign_Decl>; optimizer::Unused_Return,
optimizer::Constant_Fold,
} optimizer::If,
} optimizer::Return,
optimizer::Dead_Code,
optimizer::Block,
optimizer::For_Loop,
optimizer::Assign_Decl>;
} // namespace optimizer
} // namespace chaiscript
#endif #endif

File diff suppressed because it is too large Load Diff

View File

@ -7,19 +7,12 @@
#ifndef CHAISCRIPT_POSIX_HPP_ #ifndef CHAISCRIPT_POSIX_HPP_
#define CHAISCRIPT_POSIX_HPP_ #define CHAISCRIPT_POSIX_HPP_
namespace chaiscript namespace chaiscript::detail {
{ struct Loadable_Module {
namespace detail struct DLModule {
{
struct Loadable_Module
{
struct DLModule
{
explicit DLModule(const std::string &t_filename) explicit DLModule(const std::string &t_filename)
: m_data(dlopen(t_filename.c_str(), RTLD_NOW)) : m_data(dlopen(t_filename.c_str(), RTLD_NOW)) {
{ if (m_data == nullptr) {
if (m_data == nullptr)
{
throw chaiscript::exception::load_module_error(dlerror()); throw chaiscript::exception::load_module_error(dlerror());
} }
} }
@ -29,22 +22,16 @@ namespace chaiscript
DLModule(const DLModule &) = delete; DLModule(const DLModule &) = delete;
DLModule &operator=(const DLModule &) = delete; DLModule &operator=(const DLModule &) = delete;
~DLModule() ~DLModule() { dlclose(m_data); }
{
dlclose(m_data);
}
void *m_data; void *m_data;
}; };
template<typename T> template<typename T>
struct DLSym struct DLSym {
{
DLSym(DLModule &t_mod, const std::string &t_symbol) DLSym(DLModule &t_mod, const std::string &t_symbol)
: m_symbol(reinterpret_cast<T>(dlsym(t_mod.m_data, t_symbol.c_str()))) : m_symbol(reinterpret_cast<T>(dlsym(t_mod.m_data, t_symbol.c_str()))) {
{ if (!m_symbol) {
if (!m_symbol)
{
throw chaiscript::exception::load_module_error(dlerror()); throw chaiscript::exception::load_module_error(dlerror());
} }
} }
@ -53,16 +40,14 @@ namespace chaiscript
}; };
Loadable_Module(const std::string &t_module_name, const std::string &t_filename) Loadable_Module(const std::string &t_module_name, const std::string &t_filename)
: m_dlmodule(t_filename), m_func(m_dlmodule, "create_chaiscript_module_" + t_module_name), : m_dlmodule(t_filename)
m_moduleptr(m_func.m_symbol()) , m_func(m_dlmodule, "create_chaiscript_module_" + t_module_name)
{ , m_moduleptr(m_func.m_symbol()) {
} }
DLModule m_dlmodule; DLModule m_dlmodule;
DLSym<Create_Module_Func> m_func; DLSym<Create_Module_Func> m_func;
ModulePtr m_moduleptr; ModulePtr m_moduleptr;
}; };
} } // namespace chaiscript::detail
}
#endif #endif

View File

@ -8,8 +8,9 @@
#define CHAISCRIPT_PRELUDE_HPP_ #define CHAISCRIPT_PRELUDE_HPP_
namespace chaiscript { namespace chaiscript {
struct ChaiScript_Prelude { struct ChaiScript_Prelude {
static std::string chaiscript_prelude() { return R"chaiscript( static std::string chaiscript_prelude() {
return R"chaiscript(
def lt(l, r) { def lt(l, r) {
if (call_exists(`<`, l, r)) { if (call_exists(`<`, l, r)) {
@ -554,9 +555,8 @@ def find(container, value) {
)chaiscript"; )chaiscript";
} }
};
}; } // namespace chaiscript
}
#endif /* CHAISCRIPT_PRELUDE_HPP_ */ #endif /* CHAISCRIPT_PRELUDE_HPP_ */

View File

@ -2,26 +2,22 @@
/// regarding the ChaiScript standard runtime library. /// regarding the ChaiScript standard runtime library.
/// \brief Items in this namespace exist in the ChaiScript language runtime. They are not part of the C++ API /// \brief Items in this namespace exist in the ChaiScript language runtime. They are not part of the C++ API
namespace ChaiScript_Language namespace ChaiScript_Language {
{ /// \page LangStandardLibraryRef ChaiScript Language Standard Library Reference
///
/// ChaiScript, at its core, has some very functional programming-inspired habits. Few places show this off as clearly
/// as the prelude, itself a name taken as a nod to the popular functional language Haskell. This prelude is available
/// to all standard ChaiScript applications, and provides a simple foundation for using numbers, strings, and ranges
/// (the general category of Range cs and their iteration).
///
/// \page LangStandardLibraryRef ChaiScript Language Standard Library Reference /// \brief Generic concept of a value in ChaiScript.
/// ///
/// ChaiScript, at its core, has some very functional programming-inspired habits. Few places show this off as clearly /// The Object type exists merely as a concept. All objects in ChaiScript support this concept
/// as the prelude, itself a name taken as a nod to the popular functional language Haskell. This prelude is available /// and have the following methods available to them. All objects are stored internally as chaiscript::Boxed_Value types.
/// to all standard ChaiScript applications, and provides a simple foundation for using numbers, strings, and ranges ///
/// (the general category of Range cs and their iteration). /// \sa chaiscript::Boxed_Value
/// class Object {
/// \brief Generic concept of a value in ChaiScript.
///
/// The Object type exists merely as a concept. All objects in ChaiScript support this concept
/// and have the following methods available to them. All objects are stored internally as chaiscript::Boxed_Value types.
///
/// \sa chaiscript::Boxed_Value
class Object
{
public: public:
/// \brief Returns the Type_Info value for this Object /// \brief Returns the Type_Info value for this Object
Type_Info get_type_info() const; Type_Info get_type_info() const;
@ -51,42 +47,39 @@ class Object
/// ///
/// \sa Type_Info::name(); /// \sa Type_Info::name();
string type_name() const; string type_name() const;
}; };
/// \brief Item returned from a Range object from a Map /// \brief Item returned from a Range object from a Map
class Map_Pair class Map_Pair {
{
public: public:
/// \brief Returns the key of the Map entry /// \brief Returns the key of the Map entry
const string first(); const string first();
/// \brief Returns the value Object of the Map entry /// \brief Returns the value Object of the Map entry
Object second(); Object second();
}; };
/// \brief Maps strings to Objects
/// \brief Maps strings to Objects ///
/// /// ChaiScript has a built in shortcut for generating Map objects:
/// ChaiScript has a built in shortcut for generating Map objects: ///
/// /// Example:
/// Example: /// \code
/// \code /// eval> var m = ["a":1, "b":2];
/// eval> var m = ["a":1, "b":2]; /// [<a,1>, <b,2>]
/// [<a,1>, <b,2>] /// eval> m.count("a");
/// eval> m.count("a"); /// 1
/// 1 /// eval> m.count("c");
/// eval> m.count("c"); /// 0
/// 0 /// eval> m.size();
/// eval> m.size(); /// 2
/// 2 /// \endcode
/// \endcode ///
/// /// Implemented as std::map<Boxed_Value>
/// Implemented as std::map<Boxed_Value> ///
/// /// \sa Map_Pair
/// \sa Map_Pair /// \sa chaiscript::bootstrap::standard_library::map_type
/// \sa chaiscript::bootstrap::standard_library::map_type class Map {
class Map
{
public: public:
/// \brief Returns an object that implements the Range concept for the Map_Pair's in this Map /// \brief Returns an object that implements the Range concept for the Map_Pair's in this Map
Range range(); Range range();
@ -108,64 +101,57 @@ class Map
/// \brief Returns true if the map contains no items /// \brief Returns true if the map contains no items
bool empty() const; bool empty() const;
};
}; /// \brief A concept implemented by string, Vector and Map. It is convertible to Range, default constructable and back_insertable
class Container {
/// \brief A concept implemented by string, Vector and Map. It is convertible to Range, default constructable and back_insertable
class Container
{
public: public:
void push_back(Object); void push_back(Object);
Range range(); Range range();
Const_Range range() const; Const_Range range() const;
}; };
/// \brief Converts o into a string.
///
/// \code
/// eval> to_string(3).is_type("string") <br>
/// true<br>
/// \endcode
string to_string(Object o);
/// \brief Converts o into a string. /// \brief Prints o to the terminal, without a trailing carriage return. Applies conversions to string automatically.
/// /// \code
/// \code /// eval> puts("hi, "); puts("there")
/// eval> to_string(3).is_type("string") <br> /// hi, thereeval>
/// true<br> /// \endcode
/// \endcode /// \sa to_string
string to_string(Object o); /// \sa print
void puts(Object o);
/// \brief Prints o to the terminal, with a trailing carriage return. Applies conversions to string automatically
/// \code
/// eval> print("hello")
/// hello
/// eval>
/// \endcode
/// \sa to_string
/// \sa puts
void print(Object o);
/// \brief Prints o to the terminal, without a trailing carriage return. Applies conversions to string automatically. /// \brief ChaiScript representation of std::string. It is an std::string but only some member are exposed to ChaiScript.
/// \code ///
/// eval> puts("hi, "); puts("there") /// Because the ChaiScript string object is an std::string, it is directly convertible to and from std::string
/// hi, thereeval> /// using the chaiscript::boxed_cast and chaiscript::var functions.
/// \endcode ///
/// \sa to_string /// With the exception of string::trim, string::rtrim, string::ltrim, all members are direct pass-throughs to the
/// \sa print /// std::string of the same name.
void puts(Object o); ///
/// \note Object and function notations are equivalent in ChaiScript. This means that
/// \c "bob".find("b") and \c find("bob", "b") are exactly the same. Most examples below follow the
/// \brief Prints o to the terminal, with a trailing carriage return. Applies conversions to string automatically /// second formation of the function calls.
/// \code /// \sa \ref keyworddef for extending existing C++ classes in ChaiScript
/// eval> print("hello") /// \sa chaiscript::bootstrap::standard_library::string_type
/// hello class string {
/// eval>
/// \endcode
/// \sa to_string
/// \sa puts
void print(Object o);
/// \brief ChaiScript representation of std::string. It is an std::string but only some member are exposed to ChaiScript.
///
/// Because the ChaiScript string object is an std::string, it is directly convertible to and from std::string
/// using the chaiscript::boxed_cast and chaiscript::var functions.
///
/// With the exception of string::trim, string::rtrim, string::ltrim, all members are direct pass-throughs to the
/// std::string of the same name.
///
/// \note Object and function notations are equivalent in ChaiScript. This means that
/// \c "bob".find("b") and \c find("bob", "b") are exactly the same. Most examples below follow the
/// second formation of the function calls.
/// \sa \ref keyworddef for extending existing C++ classes in ChaiScript
/// \sa chaiscript::bootstrap::standard_library::string_type
class string
{
public: public:
/// \brief Finds the first instance of substr. /// \brief Finds the first instance of substr.
/// \code /// \code
@ -174,7 +160,6 @@ class string
/// \endcode /// \endcode
int find(string s) const; int find(string s) const;
/// \brief Finds the last instance of substr. /// \brief Finds the last instance of substr.
/// \code /// \code
/// eval> rfind("abab", "ab") /// eval> rfind("abab", "ab")
@ -281,16 +266,15 @@ class string
/// \brief Returns an object that implements the Const_Range concept for the characters of this string /// \brief Returns an object that implements the Const_Range concept for the characters of this string
Const_Range range() const; Const_Range range() const;
}; };
/// \brief A concept in ChaiScript that is implemented by \ref string, Vector and Map. It provides /// \brief A concept in ChaiScript that is implemented by \ref string, Vector and Map. It provides
/// easy iteration over the elements in a container. /// easy iteration over the elements in a container.
/// ///
/// Implemented by the template chaiscript::bootstrap::standard_library::Bidir_Range /// Implemented by the template chaiscript::bootstrap::standard_library::Bidir_Range
/// ///
/// \sa Const_Range /// \sa Const_Range
class Range class Range {
{
public: public:
/// \brief Returns the last item of the range /// \brief Returns the last item of the range
Object back(); Object back();
@ -311,17 +295,15 @@ class Range
/// ///
/// \post front() returns the element at front() + 1; /// \post front() returns the element at front() + 1;
void pop_front(); void pop_front();
};
}; /// \brief A concept in ChaiScript that is implemented by \ref string, Vector and Map. It provides
/// easy iteration over the elements in a container. Contained values are const.
/// \brief A concept in ChaiScript that is implemented by \ref string, Vector and Map. It provides ///
/// easy iteration over the elements in a container. Contained values are const. /// Implemented by the template chaiscript::bootstrap::standard_library::Const_Bidir_Range
/// ///
/// Implemented by the template chaiscript::bootstrap::standard_library::Const_Bidir_Range /// \sa Range
/// class Const_Range {
/// \sa Range
class Const_Range
{
public: public:
/// \brief Returns the last item of the range /// \brief Returns the last item of the range
const Object back(); const Object back();
@ -342,28 +324,26 @@ class Const_Range
/// ///
/// \post front() returns the element at front() + 1; /// \post front() returns the element at front() + 1;
void pop_front(); void pop_front();
};
}; /// \brief A vector of Objects
///
/// \brief A vector of Objects /// ChaiScript includes a shortcut for creating a Vector of Objects
/// ///
/// ChaiScript includes a shortcut for creating a Vector of Objects /// Example:
/// /// \code
/// Example: /// eval> var v = [1,2,3,4]
/// \code /// [1, 2, 3, 4]
/// eval> var v = [1,2,3,4] /// eval> v[0];
/// [1, 2, 3, 4] /// 1
/// eval> v[0]; /// eval> v.size();
/// 1 /// 4
/// eval> v.size(); /// \endcode
/// 4 ///
/// \endcode /// Implemented with std::vector<chaiscript::Boxed_Value>
/// ///
/// Implemented with std::vector<chaiscript::Boxed_Value> /// \sa chaiscript::bootstrap::standard_library::vector_type
/// class Vector {
/// \sa chaiscript::bootstrap::standard_library::vector_type
class Vector
{
public: public:
/// \brief returns the Object at the given index. Throws an exception if the index does not exist /// \brief returns the Object at the given index. Throws an exception if the index does not exist
Object operator[](int t_index); Object operator[](int t_index);
@ -417,11 +397,9 @@ class Vector
/// \brief Returns the number of elements in the Vector /// \brief Returns the number of elements in the Vector
int size() const; int size() const;
};
}; class Type_Info {
class Type_Info
{
public: public:
/// \brief Compares this Type_Info object with another one and returns true if the two types are the same /// \brief Compares this Type_Info object with another one and returns true if the two types are the same
/// after const, pointer, reference are removed. /// after const, pointer, reference are removed.
@ -450,32 +428,29 @@ class Type_Info
/// \brief Returns the ChaiScript registered name for the type if one exists. /// \brief Returns the ChaiScript registered name for the type if one exists.
string name() const; string name() const;
};
}; /// \brief Represents a function object in ChaiScript
///
/// A function object may be one function, such as:
/// \brief Represents a function object in ChaiScript /// \code
/// /// var f = fun(x) { return x; }
/// A function object may be one function, such as: /// \endcode
/// \code ///
/// var f = fun(x) { return x; } /// Or it may represent multiple functions
/// \endcode /// \code
/// /// var f2 = `-`; // represents the unary - as well as the set of binary - operators
/// Or it may represent multiple functions /// \endcode
/// \code ///
/// var f2 = `-`; // represents the unary - as well as the set of binary - operators /// Guarded function example
/// \endcode /// \code
/// /// def f3(x) : x > 2 {
/// Guarded function example /// return x;
/// \code /// }
/// def f3(x) : x > 2 { /// \endcode
/// return x; ///
/// } /// Examples in the function definitions below will reference these examples
/// \endcode class Function {
///
/// Examples in the function definitions below will reference these examples
class Function
{
public: public:
/// \brief Returns the annotation description of the function /// \brief Returns the annotation description of the function
string get_annotation() const; string get_annotation() const;
@ -545,286 +520,264 @@ class Function
/// 1 /// 1
/// \endcode /// \endcode
Object call(Vector t_params) const; Object call(Vector t_params) const;
} }
/// \brief Returns the max of a or b. Requires that operator>(a, b) exists
/// Equivalent to
/// \code
/// return a>b?a:b;
/// \endcode
///
/// Example:
/// \code
/// eval> max(4, 10)
/// 10
/// \endcode
Object
max(Object a, Object b);
/// \brief Returns the min of a or b. Requires that operator<(a, b) exists
///
/// Equivalent to
/// \code
/// return a<b?a:b;
/// \endcode
///
/// Example:
/// \code
/// eval> min(4, 10)
/// 4
/// \endcode
Object min(Object a, Object b);
/// \brief Returns the max of a or b. Requires that operator>(a, b) exists /// \brief Returns true if x is an even integer.
/// Equivalent to ///
/// \code /// Will also work on any non-integer type for which an operator%(x, int) exists
/// return a>b?a:b; ///
/// \endcode /// Example:
/// /// \code
/// Example: /// eval> even(4)
/// \code /// true
/// eval> max(4, 10) /// \endcode
/// 10 bool even(Object x);
/// \endcode
Object max(Object a, Object b);
/// \brief Returns the min of a or b. Requires that operator<(a, b) exists /// \brief Returns true if x is an odd integer.
/// ///
/// Equivalent to /// Will also work on any non-integer type for which an operator%(x, int) exists
/// \code ///
/// return a<b?a:b; /// Example:
/// \endcode /// \code
/// /// eval> odd(4)
/// Example: /// false
/// \code /// \endcode
/// eval> min(4, 10) bool even(Object x);
/// 4
/// \endcode
Object min(Object a, Object b);
/// \brief Returns true if x is an even integer. /// \brief Applies the function f over each element in the Range c.
/// ///
/// Will also work on any non-integer type for which an operator%(x, int) exists /// Example:
/// /// \code
/// Example: /// eval> for_each([1, 2, 3], print)
/// \code /// 1
/// eval> even(4) /// 2
/// true /// 3
/// \endcode /// \endcode
bool even(Object x); void for_each(Range c, Function f);
/// \brief Returns true if x is an odd integer. /// \brief Applies f over each element in the Range c, joining all the results.
/// ///
/// Will also work on any non-integer type for which an operator%(x, int) exists /// Example:
/// /// \code
/// Example: /// eval> map([1, 2, 3], odd)
/// \code /// [true, false, true]
/// eval> odd(4) /// \endcode
/// false Object map(Range c, Function f);
/// \endcode
bool even(Object x);
/// \brief Starts with the initial value and applies the function f to it and the first element of the Range c.
/// The result is then applied to the second element, and so on until the elements are exhausted.
///
/// Example:
/// \code
/// eval> foldl([1, 2, 3, 4], `+`, 0)
/// 10
/// \endcode
Object foldl(Range c, Function f, Object initial);
/// \brief Applies the function f over each element in the Range c. /// \brief Returns the sum total of the values in the Range c.
/// ///
/// Example: /// Example:
/// \code /// \code
/// eval> for_each([1, 2, 3], print) /// eval> sum([1, 2, 3, 4])
/// 1 /// 10
/// 2 /// \endcode
/// 3 ///
/// \endcode /// Equivalent to:
void for_each(Range c, Function f); /// \code
/// foldl(c, `+`, 0.0);
/// \endcode
Numeric sum(Range c);
/// \brief Returns the product of the value in the Range c.
///
/// Example:
/// \code
/// eval> product([1, 2, 3, 4])
/// 24
/// \endcode
///
/// Equivalent to:
/// \code
/// foldl(c, `*`, 1.0);
/// \endcode
Numeric product(Range c);
/// \brief Applies f over each element in the Range c, joining all the results. /// \brief Takes num elements from the Range c, returning them.
/// ///
/// Example: /// Example:
/// \code /// \code
/// eval> map([1, 2, 3], odd) /// eval> take([1, 2, 3, 4], 2)
/// [true, false, true] /// [1, 2]
/// \endcode /// \endcode
Object map(Range c, Function f); ///
/// \returns A container of the same type that was passed in
Object take(Range c, int num);
/// \brief Takes elements from the Range c that match function f, stopping at the first non-match, returning them as a new Vector.
///
/// Example:
/// \code
/// eval> take_while([1, 2, 3], odd)
/// [1]
/// \endcode
///
/// \returns A container of the same type that was passed in
Object take_while(Range c, Function f);
/// \brief Starts with the initial value and applies the function f to it and the first element of the Range c. /// \brief Drops num elements from the Range c, returning the remainder.
/// The result is then applied to the second element, and so on until the elements are exhausted. ///
/// /// Example:
/// Example: /// \code
/// \code /// eval> drop([1, 2, 3, 4], 2)
/// eval> foldl([1, 2, 3, 4], `+`, 0) /// [3, 4]
/// 10 /// \endcode
/// \endcode ///
Object foldl(Range c, Function f, Object initial); /// \returns A container of the same type that was passed in
Object drop(Range c, int num);
/// \brief Drops elements from the Range c that match f, stopping at the first non-match, returning the remainder.
///
/// Example:
/// \code
/// eval> drop_while([1, 2, 3], odd)
/// [2, 3]
/// \endcode
Object drop_while(Range c, Function f);
/// \brief Returns the sum total of the values in the Range c. /// \brief Similar to foldl, this takes the first two elements as its starting values for f. This assumes Range c has at least 2 elements.
/// ///
/// Example: /// Example:
/// \code /// \code
/// eval> sum([1, 2, 3, 4]) /// eval> reduce([1, 2, 3, 4], `+`)
/// 10 /// 10
/// \endcode /// \endcode
/// Object reduce(Range c, Function f);
/// Equivalent to:
/// \code
/// foldl(c, `+`, 0.0);
/// \endcode
Numeric sum(Range c);
/// \brief Takes elements from Container c that match function f, return them.
///
/// Example:
/// \code
/// eval> filter([1, 2, 3, 4], odd)
/// [1, 3]
/// \endcode
Object filter(Container c, Function f);
/// \brief Returns the product of the value in the Range c. /// \brief Joins the elements of the Range c into a string, delimiting each with the delim string.
/// ///
/// Example: /// Example:
/// \code /// \code
/// eval> product([1, 2, 3, 4]) /// eval> join([1, 2, 3], "*")
/// 24 /// 1*2*3
/// \endcode /// \endcode
/// string join(Range c, string delim);
/// Equivalent to:
/// \code
/// foldl(c, `*`, 1.0);
/// \endcode
Numeric product(Range c);
/// \brief Returns the contents of the Container c in reversed order.
///
/// Example:
/// \code
/// eval> reverse([1, 2, 3, 4, 5, 6, 7])
/// [7, 6, 5, 4, 3, 2, 1]
/// \endcode
Container reverse(Container c);
/// \brief Takes num elements from the Range c, returning them. /// \brief Generates a new Vector filled with values starting at x and ending with y.
/// ///
/// Example: /// Works on types supporting operator<=(x, y) and operator++(x)
/// \code ///
/// eval> take([1, 2, 3, 4], 2) /// Example:
/// [1, 2] /// \code
/// \endcode /// eval> generate_range(1, 10)
/// /// [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
/// \returns A container of the same type that was passed in /// \endcode
Object take(Range c, int num); Vector generate_range(Object x, Object y);
/// \brief Returns a new Range with x and y concatenated.
///
/// Example:
/// \code
/// eval> concat([1, 2, 3], [4, 5, 6])
/// [1, 2, 3, 4, 5, 6]
/// \endcode
Object concat(Range x, Range y);
/// \brief Takes elements from the Range c that match function f, stopping at the first non-match, returning them as a new Vector. /// \brief Returns a new Vector with x and y as its values.
/// ///
/// Example: /// Example:
/// \code /// \code
/// eval> take_while([1, 2, 3], odd) /// eval> collate(1, 2)
/// [1] /// [1, 2]
/// \endcode /// \endcode
/// Vector collate(Object x, Object y);
/// \returns A container of the same type that was passed in
Object take_while(Range c, Function f);
/// \brief Applies f to elements of x and y, returning a new Vector with the result of each application.
///
/// Example:
/// \code
/// eval> zip_with(`+`, [1, 2, 3], [4, 5, 6])
/// [5, 7, 9]
/// \endcode
Vector zip_with(Function f, Range x, Range y);
/// \brief Drops num elements from the Range c, returning the remainder. /// \brief Collates elements of x and y, returning a new Vector with the result.
/// ///
/// Example: /// Example:
/// \code /// \code
/// eval> drop([1, 2, 3, 4], 2) /// eval> zip([1, 2, 3], [4, 5, 6])
/// [3, 4] /// [[1, 4], [2, 5], [3, 6]]
/// \endcode /// \endcode
/// Vector zip(Range x, Range y);
/// \returns A container of the same type that was passed in
Object drop(Range c, int num);
/// \brief returns true if there exists a call to the Function f that takes the given parameters
///
/// Example:
/// \code
/// eval> call_exists(`+`, 1, 2)
/// true
/// \endcode
bool call_exists(Function f, ...);
/// \brief Drops elements from the Range c that match f, stopping at the first non-match, returning the remainder. /// \brief Reverses a Range object so that the elements are accessed in reverse
/// Range retro(Range);
/// Example:
/// \code
/// eval> drop_while([1, 2, 3], odd)
/// [2, 3]
/// \endcode
Object drop_while(Range c, Function f);
/// \brief Reverses a Const_Range object so that the elements are accessed in reverse
Const_Range retro(Const_Range);
/// \brief Similar to foldl, this takes the first two elements as its starting values for f. This assumes Range c has at least 2 elements. /// \brief Raises the given object as an exception. Any type of object can be thrown.
/// ///
/// Example: /// Example:
/// \code /// \code
/// eval> reduce([1, 2, 3, 4], `+`) /// eval> try { throw(1); } catch (e) { print("Exception caught: " + to_string(e)); }
/// 10 /// Exception caught: 1
/// \endcode /// \endcode
Object reduce(Range c, Function f); ///
/// \sa \ref keywordtry
void throw(Object);
/// \brief Takes elements from Container c that match function f, return them. } // namespace ChaiScript_Language
///
/// Example:
/// \code
/// eval> filter([1, 2, 3, 4], odd)
/// [1, 3]
/// \endcode
Object filter(Container c, Function f);
/// \brief Joins the elements of the Range c into a string, delimiting each with the delim string.
///
/// Example:
/// \code
/// eval> join([1, 2, 3], "*")
/// 1*2*3
/// \endcode
string join(Range c, string delim);
/// \brief Returns the contents of the Container c in reversed order.
///
/// Example:
/// \code
/// eval> reverse([1, 2, 3, 4, 5, 6, 7])
/// [7, 6, 5, 4, 3, 2, 1]
/// \endcode
Container reverse(Container c);
/// \brief Generates a new Vector filled with values starting at x and ending with y.
///
/// Works on types supporting operator<=(x, y) and operator++(x)
///
/// Example:
/// \code
/// eval> generate_range(1, 10)
/// [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
/// \endcode
Vector generate_range(Object x, Object y);
/// \brief Returns a new Range with x and y concatenated.
///
/// Example:
/// \code
/// eval> concat([1, 2, 3], [4, 5, 6])
/// [1, 2, 3, 4, 5, 6]
/// \endcode
Object concat(Range x, Range y);
/// \brief Returns a new Vector with x and y as its values.
///
/// Example:
/// \code
/// eval> collate(1, 2)
/// [1, 2]
/// \endcode
Vector collate(Object x, Object y);
/// \brief Applies f to elements of x and y, returning a new Vector with the result of each application.
///
/// Example:
/// \code
/// eval> zip_with(`+`, [1, 2, 3], [4, 5, 6])
/// [5, 7, 9]
/// \endcode
Vector zip_with(Function f, Range x, Range y);
/// \brief Collates elements of x and y, returning a new Vector with the result.
///
/// Example:
/// \code
/// eval> zip([1, 2, 3], [4, 5, 6])
/// [[1, 4], [2, 5], [3, 6]]
/// \endcode
Vector zip(Range x, Range y);
/// \brief returns true if there exists a call to the Function f that takes the given parameters
///
/// Example:
/// \code
/// eval> call_exists(`+`, 1, 2)
/// true
/// \endcode
bool call_exists(Function f, ...);
/// \brief Reverses a Range object so that the elements are accessed in reverse
Range retro(Range);
/// \brief Reverses a Const_Range object so that the elements are accessed in reverse
Const_Range retro(Const_Range);
/// \brief Raises the given object as an exception. Any type of object can be thrown.
///
/// Example:
/// \code
/// eval> try { throw(1); } catch (e) { print("Exception caught: " + to_string(e)); }
/// Exception caught: 1
/// \endcode
///
/// \sa \ref keywordtry
void throw(Object);
}

View File

@ -7,29 +7,22 @@
#ifndef CHAISCRIPT_TRACER_HPP_ #ifndef CHAISCRIPT_TRACER_HPP_
#define CHAISCRIPT_TRACER_HPP_ #define CHAISCRIPT_TRACER_HPP_
namespace chaiscript { namespace chaiscript::eval {
namespace eval { struct Noop_Tracer_Detail {
struct Noop_Tracer_Detail
{
template<typename T> template<typename T>
constexpr void trace(const chaiscript::detail::Dispatch_State &, const AST_Node_Impl<T> *) noexcept constexpr void trace(const chaiscript::detail::Dispatch_State &, const AST_Node_Impl<T> *) noexcept {
{
} }
}; };
template<typename ... T> template<typename... T>
struct Tracer : T... struct Tracer : T... {
{
Tracer() = default; Tracer() = default;
constexpr explicit Tracer(T ... t) constexpr explicit Tracer(T... t)
: T(std::move(t))... : T(std::move(t))... {
{
} }
void do_trace(const chaiscript::detail::Dispatch_State &ds, const AST_Node_Impl<Tracer<T...>> *node) { void do_trace(const chaiscript::detail::Dispatch_State &ds, const AST_Node_Impl<Tracer<T...>> *node) {
(static_cast<T&>(*this).trace(ds, node), ... ); (static_cast<T &>(*this).trace(ds, node), ...);
} }
static void trace(const chaiscript::detail::Dispatch_State &ds, const AST_Node_Impl<Tracer<T...>> *node) { static void trace(const chaiscript::detail::Dispatch_State &ds, const AST_Node_Impl<Tracer<T...>> *node) {
@ -39,8 +32,6 @@ namespace chaiscript {
using Noop_Tracer = Tracer<Noop_Tracer_Detail>; using Noop_Tracer = Tracer<Noop_Tracer_Detail>;
} } // namespace chaiscript::eval
}
#endif #endif

View File

@ -7,15 +7,10 @@
#ifndef CHAISCRIPT_UNKNOWN_HPP_ #ifndef CHAISCRIPT_UNKNOWN_HPP_
#define CHAISCRIPT_UNKNOWN_HPP_ #define CHAISCRIPT_UNKNOWN_HPP_
namespace chaiscript {
namespace chaiscript namespace detail {
{ struct Loadable_Module {
namespace detail Loadable_Module(const std::string &, const std::string &) {
{
struct Loadable_Module
{
Loadable_Module(const std::string &, const std::string &)
{
#ifdef CHAISCRIPT_NO_DYNLOAD #ifdef CHAISCRIPT_NO_DYNLOAD
throw chaiscript::exception::load_module_error("Loadable module support was disabled (CHAISCRIPT_NO_DYNLOAD)"); throw chaiscript::exception::load_module_error("Loadable module support was disabled (CHAISCRIPT_NO_DYNLOAD)");
#else #else
@ -25,7 +20,6 @@ namespace chaiscript
ModulePtr m_moduleptr; ModulePtr m_moduleptr;
}; };
} } // namespace detail
} } // namespace chaiscript
#endif #endif

View File

@ -17,41 +17,32 @@
#include <windows.h> #include <windows.h>
#endif #endif
namespace chaiscript {
namespace chaiscript namespace detail {
{ struct Loadable_Module {
namespace detail
{
struct Loadable_Module
{
template<typename T> template<typename T>
static std::wstring to_wstring(const T &t_str) static std::wstring to_wstring(const T &t_str) {
{
return std::wstring(t_str.begin(), t_str.end()); return std::wstring(t_str.begin(), t_str.end());
} }
template<typename T> template<typename T>
static std::string to_string(const T &t_str) static std::string to_string(const T &t_str) {
{
return std::string(t_str.begin(), t_str.end()); return std::string(t_str.begin(), t_str.end());
} }
#if defined(_UNICODE) || defined(UNICODE) #if defined(_UNICODE) || defined(UNICODE)
template<typename T> template<typename T>
static std::wstring to_proper_string(const T &t_str) static std::wstring to_proper_string(const T &t_str) {
{
return to_wstring(t_str); return to_wstring(t_str);
} }
#else #else
template<typename T> template<typename T>
static std::string to_proper_string(const T &t_str) static std::string to_proper_string(const T &t_str) {
{
return to_string(t_str); return to_string(t_str);
} }
#endif #endif
static std::string get_error_message(DWORD t_err) static std::string get_error_message(DWORD t_err) {
{
using StringType = LPTSTR; using StringType = LPTSTR;
#if defined(_UNICODE) || defined(UNICODE) #if defined(_UNICODE) || defined(UNICODE)
@ -61,16 +52,15 @@ namespace chaiscript
#endif #endif
StringType lpMsgBuf = nullptr; StringType lpMsgBuf = nullptr;
if (FormatMessage( if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
nullptr, nullptr,
t_err, t_err,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
reinterpret_cast<StringType>(&lpMsgBuf), reinterpret_cast<StringType>(&lpMsgBuf),
0, nullptr ) != 0 && lpMsgBuf) 0,
{ nullptr)
!= 0
&& lpMsgBuf) {
retval = lpMsgBuf; retval = lpMsgBuf;
LocalFree(lpMsgBuf); LocalFree(lpMsgBuf);
} }
@ -78,13 +68,10 @@ namespace chaiscript
return to_string(retval); return to_string(retval);
} }
struct DLModule struct DLModule {
{
explicit DLModule(const std::string &t_filename) explicit DLModule(const std::string &t_filename)
: m_data(LoadLibrary(to_proper_string(t_filename).c_str())) : m_data(LoadLibrary(to_proper_string(t_filename).c_str())) {
{ if (!m_data) {
if (!m_data)
{
throw chaiscript::exception::load_module_error(get_error_message(GetLastError())); throw chaiscript::exception::load_module_error(get_error_message(GetLastError()));
} }
} }
@ -94,22 +81,16 @@ namespace chaiscript
DLModule(const DLModule &) = delete; DLModule(const DLModule &) = delete;
DLModule &operator=(const DLModule &) = delete; DLModule &operator=(const DLModule &) = delete;
~DLModule() ~DLModule() { FreeLibrary(m_data); }
{
FreeLibrary(m_data);
}
HMODULE m_data; HMODULE m_data;
}; };
template<typename T> template<typename T>
struct DLSym struct DLSym {
{
DLSym(DLModule &t_mod, const std::string &t_symbol) DLSym(DLModule &t_mod, const std::string &t_symbol)
: m_symbol(reinterpret_cast<T>(GetProcAddress(t_mod.m_data, t_symbol.c_str()))) : m_symbol(reinterpret_cast<T>(GetProcAddress(t_mod.m_data, t_symbol.c_str()))) {
{ if (!m_symbol) {
if (!m_symbol)
{
throw chaiscript::exception::load_module_error(get_error_message(GetLastError())); throw chaiscript::exception::load_module_error(get_error_message(GetLastError()));
} }
} }
@ -118,16 +99,15 @@ namespace chaiscript
}; };
Loadable_Module(const std::string &t_module_name, const std::string &t_filename) Loadable_Module(const std::string &t_module_name, const std::string &t_filename)
: m_dlmodule(t_filename), m_func(m_dlmodule, "create_chaiscript_module_" + t_module_name), : m_dlmodule(t_filename)
m_moduleptr(m_func.m_symbol()) , m_func(m_dlmodule, "create_chaiscript_module_" + t_module_name)
{ , m_moduleptr(m_func.m_symbol()) {
} }
DLModule m_dlmodule; DLModule m_dlmodule;
DLSym<Create_Module_Func> m_func; DLSym<Create_Module_Func> m_func;
ModulePtr m_moduleptr; ModulePtr m_moduleptr;
}; };
} } // namespace detail
} } // namespace chaiscript
#endif #endif

View File

@ -7,19 +7,11 @@
#ifndef CHAISCRIPT_UTILITY_FNV1A_HPP_ #ifndef CHAISCRIPT_UTILITY_FNV1A_HPP_
#define CHAISCRIPT_UTILITY_FNV1A_HPP_ #define CHAISCRIPT_UTILITY_FNV1A_HPP_
#include <cstdint>
#include "../chaiscript_defines.hpp" #include "../chaiscript_defines.hpp"
#include <cstdint>
namespace chaiscript {
namespace chaiscript namespace utility {
{
namespace utility
{
static constexpr std::uint32_t fnv1a_32(const char *s, std::uint32_t h = 0x811c9dc5) { static constexpr std::uint32_t fnv1a_32(const char *s, std::uint32_t h = 0x811c9dc5) {
#ifdef __GNUC__ #ifdef __GNUC__
#pragma GCC diagnostic push #pragma GCC diagnostic push
@ -30,7 +22,7 @@ namespace chaiscript
#pragma warning(push) #pragma warning(push)
#pragma warning(disable : 4307) #pragma warning(disable : 4307)
#endif #endif
return (*s == 0) ? h : fnv1a_32(s+1, ((h ^ (*s)) * 0x01000193)); return (*s == 0) ? h : fnv1a_32(s + 1, ((h ^ (*s)) * 0x01000193));
#ifdef CHAISCRIPT_MSVC #ifdef CHAISCRIPT_MSVC
#pragma warning(pop) #pragma warning(pop)
#endif #endif
@ -38,13 +30,9 @@ namespace chaiscript
#ifdef __GNUC__ #ifdef __GNUC__
#pragma GCC diagnostic pop #pragma GCC diagnostic pop
#endif #endif
} }
} // namespace utility
} } // namespace chaiscript
}
#endif #endif

View File

@ -7,15 +7,11 @@
#ifndef CHAISCRIPT_UTILITY_FNV1A_HPP_ #ifndef CHAISCRIPT_UTILITY_FNV1A_HPP_
#define CHAISCRIPT_UTILITY_FNV1A_HPP_ #define CHAISCRIPT_UTILITY_FNV1A_HPP_
#include <cstdint>
#include "../chaiscript_defines.hpp" #include "../chaiscript_defines.hpp"
#include <cstdint>
namespace chaiscript {
namespace chaiscript namespace utility {
{
namespace utility
{
namespace fnv1a { namespace fnv1a {
template<typename Itr> template<typename Itr>
static constexpr std::uint32_t hash(Itr begin, Itr end) noexcept { static constexpr std::uint32_t hash(Itr begin, Itr end) noexcept {
@ -43,13 +39,11 @@ namespace chaiscript
#ifdef __GNUC__ #ifdef __GNUC__
#pragma GCC diagnostic pop #pragma GCC diagnostic pop
#endif #endif
} }
template<size_t N> template<size_t N>
static constexpr std::uint32_t hash(const char (&str)[N]) noexcept { static constexpr std::uint32_t hash(const char (&str)[N]) noexcept {
return hash(std::begin(str), std::end(str)-1); return hash(std::begin(str), std::end(str) - 1);
} }
static constexpr std::uint32_t hash(std::string_view sv) noexcept { static constexpr std::uint32_t hash(std::string_view sv) noexcept {
@ -59,7 +53,7 @@ namespace chaiscript
static inline std::uint32_t hash(const std::string &s) noexcept { static inline std::uint32_t hash(const std::string &s) noexcept {
return hash(s.begin(), s.end()); return hash(s.begin(), s.end());
} }
} } // namespace fnv1a
namespace jenkins_one_at_a_time { namespace jenkins_one_at_a_time {
template<typename Itr> template<typename Itr>
@ -81,7 +75,7 @@ namespace chaiscript
template<size_t N> template<size_t N>
static constexpr std::uint32_t hash(const char (&str)[N]) noexcept { static constexpr std::uint32_t hash(const char (&str)[N]) noexcept {
return hash(std::begin(str), std::end(str)-1); return hash(std::begin(str), std::end(str) - 1);
} }
static constexpr std::uint32_t hash(std::string_view sv) noexcept { static constexpr std::uint32_t hash(std::string_view sv) noexcept {
@ -91,11 +85,10 @@ namespace chaiscript
static inline std::uint32_t hash(const std::string &s) noexcept { static inline std::uint32_t hash(const std::string &s) noexcept {
return hash(s.begin(), s.end()); return hash(s.begin(), s.end());
} }
} } // namespace jenkins_one_at_a_time
using fnv1a::hash; using fnv1a::hash;
} } // namespace utility
} // namespace chaiscript
}
#endif #endif

View File

@ -2,40 +2,32 @@
// Released under the DWTFYW PL // Released under the DWTFYW PL
// //
#ifndef SIMPLEJSON_HPP #ifndef SIMPLEJSON_HPP
#define SIMPLEJSON_HPP #define SIMPLEJSON_HPP
#include <cstdint>
#include <cmath>
#include <cctype>
#include <string>
#include <vector>
#include <map>
#include <type_traits>
#include <initializer_list>
#include <ostream>
#include <iostream>
#include <variant>
#include "../chaiscript_defines.hpp" #include "../chaiscript_defines.hpp"
#include "quick_flat_map.hpp" #include "quick_flat_map.hpp"
#include <cctype>
#include <cmath>
#include <cstdint>
#include <initializer_list>
#include <iostream>
#include <map>
#include <ostream>
#include <string>
#include <type_traits>
#include <variant>
#include <vector>
namespace json { namespace json {
using std::enable_if;
using std::initializer_list;
using std::is_convertible;
using std::is_floating_point;
using std::is_integral;
using std::is_same;
using std::enable_if; class JSON {
using std::initializer_list;
using std::is_same;
using std::is_convertible;
using std::is_integral;
using std::is_floating_point;
class JSON
{
public: public:
enum class Class { enum class Class {
Null = 0, Null = 0,
@ -48,26 +40,40 @@ class JSON
}; };
private: private:
using Data
= std::variant<std::nullptr_t, chaiscript::utility::QuickFlatMap<std::string, JSON>, std::vector<JSON>, std::string, double, std::int64_t, bool>;
struct Internal {
using Data = std::variant<std::nullptr_t, chaiscript::utility::QuickFlatMap<std::string, JSON>, std::vector<JSON>, std::string, double, std::int64_t, bool>; Internal(std::nullptr_t)
: d(nullptr) {
struct Internal }
{ Internal()
Internal(std::nullptr_t) : d(nullptr) { } : d(nullptr) {
Internal() : d(nullptr) { } }
Internal(Class c) : d(make_type(c)) { } Internal(Class c)
template<typename T> Internal(T t) : d(std::move(t)) { } : d(make_type(c)) {
}
template<typename T>
Internal(T t)
: d(std::move(t)) {
}
static Data make_type(Class c) { static Data make_type(Class c) {
switch (c) { switch (c) {
case Class::Null: return nullptr; case Class::Null:
case Class::Object: return chaiscript::utility::QuickFlatMap<std::string, JSON>{}; return nullptr;
case Class::Array: return std::vector<JSON>{}; case Class::Object:
case Class::String: return std::string{}; return chaiscript::utility::QuickFlatMap<std::string, JSON>{};
case Class::Floating: return double{}; case Class::Array:
case Class::Integral: return std::int64_t{}; return std::vector<JSON>{};
case Class::Boolean: return bool{}; case Class::String:
return std::string{};
case Class::Floating:
return double{};
case Class::Integral:
return std::int64_t{};
case Class::Boolean:
return bool{};
} }
throw std::runtime_error("unknown type"); throw std::runtime_error("unknown type");
} }
@ -78,14 +84,10 @@ class JSON
} }
} }
Class type() const noexcept { Class type() const noexcept { return Class(d.index()); }
return Class(d.index());
}
template<auto ClassValue, typename Visitor, typename Or> template<auto ClassValue, typename Visitor, typename Or>
decltype(auto) visit_or(Visitor &&visitor, Or &&other) const decltype(auto) visit_or(Visitor &&visitor, Or &&other) const {
{
if (type() == Class(ClassValue)) { if (type() == Class(ClassValue)) {
return visitor(std::get<static_cast<std::size_t>(ClassValue)>(d)); return visitor(std::get<static_cast<std::size_t>(ClassValue)>(d));
} else { } else {
@ -99,59 +101,35 @@ class JSON
return (std::get<static_cast<std::size_t>(ClassValue)>(d)); return (std::get<static_cast<std::size_t>(ClassValue)>(d));
} }
auto &Map() { auto &Map() { return get_set_type<Class::Object>(); }
return get_set_type<Class::Object>(); auto &Vector() { return get_set_type<Class::Array>(); }
} auto &String() { return get_set_type<Class::String>(); }
auto &Vector() { auto &Int() { return get_set_type<Class::Integral>(); }
return get_set_type<Class::Array>(); auto &Float() { return get_set_type<Class::Floating>(); }
} auto &Bool() { return get_set_type<Class::Boolean>(); }
auto &String() {
return get_set_type<Class::String>();
}
auto &Int() {
return get_set_type<Class::Integral>();
}
auto &Float() {
return get_set_type<Class::Floating>();
}
auto &Bool() {
return get_set_type<Class::Boolean>();
}
auto Map() const noexcept { auto Map() const noexcept { return std::get_if<static_cast<std::size_t>(Class::Object)>(&d); }
return std::get_if<static_cast<std::size_t>(Class::Object)>(&d); auto Vector() const noexcept { return std::get_if<static_cast<std::size_t>(Class::Array)>(&d); }
} auto String() const noexcept { return std::get_if<static_cast<std::size_t>(Class::String)>(&d); }
auto Vector() const noexcept { auto Int() const noexcept { return std::get_if<static_cast<std::size_t>(Class::Integral)>(&d); }
return std::get_if<static_cast<std::size_t>(Class::Array)>(&d); auto Float() const noexcept { return std::get_if<static_cast<std::size_t>(Class::Floating)>(&d); }
} auto Bool() const noexcept { return std::get_if<static_cast<std::size_t>(Class::Boolean)>(&d); }
auto String() const noexcept {
return std::get_if<static_cast<std::size_t>(Class::String)>(&d);
}
auto Int() const noexcept {
return std::get_if<static_cast<std::size_t>(Class::Integral)>(&d);
}
auto Float() const noexcept {
return std::get_if<static_cast<std::size_t>(Class::Floating)>(&d);
}
auto Bool() const noexcept {
return std::get_if<static_cast<std::size_t>(Class::Boolean)>(&d);
}
Data d; Data d;
}; };
Internal internal; Internal internal;
public: public:
template<typename Container>
template <typename Container>
class JSONWrapper { class JSONWrapper {
Container *object = nullptr; Container *object = nullptr;
public: public:
JSONWrapper( Container *val ) : object( val ) {} JSONWrapper(Container *val)
JSONWrapper( std::nullptr_t ) {} : object(val) {
}
JSONWrapper(std::nullptr_t) {}
typename Container::iterator begin() { return object ? object->begin() : typename Container::iterator(); } typename Container::iterator begin() { return object ? object->begin() : typename Container::iterator(); }
typename Container::iterator end() { return object ? object->end() : typename Container::iterator(); } typename Container::iterator end() { return object ? object->end() : typename Container::iterator(); }
@ -159,104 +137,96 @@ class JSON
typename Container::const_iterator end() const { return object ? object->end() : typename Container::iterator(); } typename Container::const_iterator end() const { return object ? object->end() : typename Container::iterator(); }
}; };
template <typename Container> template<typename Container>
class JSONConstWrapper { class JSONConstWrapper {
const Container *object = nullptr; const Container *object = nullptr;
public: public:
JSONConstWrapper( const Container *val ) : object( val ) {} JSONConstWrapper(const Container *val)
JSONConstWrapper( std::nullptr_t ) {} : object(val) {
}
JSONConstWrapper(std::nullptr_t) {}
typename Container::const_iterator begin() const noexcept { return object ? object->begin() : typename Container::const_iterator(); } typename Container::const_iterator begin() const noexcept {
return object ? object->begin() : typename Container::const_iterator();
}
typename Container::const_iterator end() const noexcept { return object ? object->end() : typename Container::const_iterator(); } typename Container::const_iterator end() const noexcept { return object ? object->end() : typename Container::const_iterator(); }
}; };
JSON() = default; JSON() = default;
JSON( std::nullptr_t ) {} JSON(std::nullptr_t) {}
explicit JSON(Class type) explicit JSON(Class type)
: internal(type) : internal(type) {
{
} }
JSON( initializer_list<JSON> list ) JSON(initializer_list<JSON> list)
: internal(Class::Object) : internal(Class::Object) {
{ for (auto i = list.begin(), e = list.end(); i != e; ++i, ++i) {
for( auto i = list.begin(), e = list.end(); i != e; ++i, ++i ) { operator[](i->to_string()) = *std::next(i);
operator[]( i->to_string() ) = *std::next( i );
} }
} }
template <typename T> template<typename T>
explicit JSON( T b, typename enable_if<is_same<T,bool>::value>::type* = nullptr ) noexcept : internal( static_cast<bool>(b) ) {} explicit JSON(T b, typename enable_if<is_same<T, bool>::value>::type * = nullptr) noexcept
: internal(static_cast<bool>(b)) {
template <typename T>
explicit JSON( T i, typename enable_if<is_integral<T>::value && !is_same<T,bool>::value>::type* = nullptr ) noexcept : internal( static_cast<std::int64_t>(i) ) {}
template <typename T>
explicit JSON( T f, typename enable_if<is_floating_point<T>::value>::type* = nullptr ) noexcept : internal( static_cast<double>(f) ) {}
template <typename T>
explicit JSON( T s, typename enable_if<is_convertible<T,std::string>::value>::type* = nullptr ) : internal( static_cast<std::string>(s) ) {}
static JSON Load( const std::string & );
JSON& operator[]( const std::string &key ) {
return internal.Map().operator[]( key );
} }
JSON& operator[]( const size_t index ) { template<typename T>
explicit JSON(T i, typename enable_if<is_integral<T>::value && !is_same<T, bool>::value>::type * = nullptr) noexcept
: internal(static_cast<std::int64_t>(i)) {
}
template<typename T>
explicit JSON(T f, typename enable_if<is_floating_point<T>::value>::type * = nullptr) noexcept
: internal(static_cast<double>(f)) {
}
template<typename T>
explicit JSON(T s, typename enable_if<is_convertible<T, std::string>::value>::type * = nullptr)
: internal(static_cast<std::string>(s)) {
}
static JSON Load(const std::string &);
JSON &operator[](const std::string &key) { return internal.Map().operator[](key); }
JSON &operator[](const size_t index) {
auto &vec = internal.Vector(); auto &vec = internal.Vector();
if( index >= vec.size() ) { if (index >= vec.size()) {
vec.resize( index + 1 ); vec.resize(index + 1);
} }
return vec.operator[]( index ); return vec.operator[](index);
} }
JSON &at(const std::string &key) { return operator[](key); }
JSON &at( const std::string &key ) { const JSON &at(const std::string &key) const {
return operator[]( key ); return internal.visit_or<Class::Object>([&](const auto &m) -> const JSON & { return m.at(key); },
[]() -> const JSON & { throw std::range_error("Not an object, no keys"); });
} }
const JSON &at( const std::string &key ) const { JSON &at(size_t index) { return operator[](index); }
return internal.visit_or<Class::Object>(
[&](const auto &m)->const JSON &{ return m.at(key); },
[]()->const JSON &{ throw std::range_error("Not an object, no keys"); }
);
}
JSON &at( size_t index ) { const JSON &at(size_t index) const {
return operator[]( index ); return internal.visit_or<Class::Array>([&](const auto &m) -> const JSON & { return m.at(index); },
} []() -> const JSON & { throw std::range_error("Not an array, no indexes"); });
const JSON &at( size_t index ) const {
return internal.visit_or<Class::Array>(
[&](const auto &m)->const JSON&{ return m.at(index); },
[]()->const JSON &{ throw std::range_error("Not an array, no indexes"); }
);
} }
auto length() const noexcept { auto length() const noexcept {
return internal.visit_or<Class::Array>( return internal.visit_or<Class::Array>([&](const auto &m) { return static_cast<int>(m.size()); }, []() { return -1; });
[&](const auto &m){ return static_cast<int>(m.size()); },
[](){ return -1; }
);
} }
bool has_key( const std::string &key ) const noexcept { bool has_key(const std::string &key) const noexcept {
return internal.visit_or<Class::Object>( return internal.visit_or<Class::Object>([&](const auto &m) { return m.count(key) != 0; }, []() { return false; });
[&](const auto &m){ return m.count(key) != 0; },
[](){ return false; }
);
} }
int size() const noexcept { int size() const noexcept {
if (auto m = internal.Map(); m != nullptr) { if (auto m = internal.Map(); m != nullptr) {
return static_cast<int>(m->size()); return static_cast<int>(m->size());
} if (auto v = internal.Vector(); v != nullptr) { }
if (auto v = internal.Vector(); v != nullptr) {
return static_cast<int>(v->size()); return static_cast<int>(v->size());
} else { } else {
return -1; return -1;
@ -269,81 +239,70 @@ class JSON
bool is_null() const noexcept { return internal.type() == Class::Null; } bool is_null() const noexcept { return internal.type() == Class::Null; }
std::string to_string() const noexcept { std::string to_string() const noexcept {
return internal.visit_or<Class::String>( return internal.visit_or<Class::String>([](const auto &o) { return o; }, []() { return std::string{}; });
[](const auto &o){ return o; },
[](){ return std::string{}; }
);
} }
double to_float() const noexcept { double to_float() const noexcept {
return internal.visit_or<Class::Floating>( return internal.visit_or<Class::Floating>([](const auto &o) { return o; }, []() { return double{}; });
[](const auto &o){ return o; },
[](){ return double{}; }
);
} }
std::int64_t to_int() const noexcept { std::int64_t to_int() const noexcept {
return internal.visit_or<Class::Integral>( return internal.visit_or<Class::Integral>([](const auto &o) { return o; }, []() { return std::int64_t{}; });
[](const auto &o){ return o; },
[](){ return std::int64_t{}; }
);
} }
bool to_bool() const noexcept { bool to_bool() const noexcept {
return internal.visit_or<Class::Boolean>( return internal.visit_or<Class::Boolean>([](const auto &o) { return o; }, []() { return false; });
[](const auto &o){ return o; },
[](){ return false; }
);
} }
JSONWrapper<chaiscript::utility::QuickFlatMap<std::string, JSON>> object_range() { JSONWrapper<chaiscript::utility::QuickFlatMap<std::string, JSON>> object_range() {
return std::get_if<static_cast<std::size_t>(Class::Object)>(&internal.d); return std::get_if<static_cast<std::size_t>(Class::Object)>(&internal.d);
} }
JSONWrapper<std::vector<JSON>> array_range() { JSONWrapper<std::vector<JSON>> array_range() { return std::get_if<static_cast<std::size_t>(Class::Array)>(&internal.d); }
return std::get_if<static_cast<std::size_t>(Class::Array)>(&internal.d);
}
JSONConstWrapper<chaiscript::utility::QuickFlatMap<std::string, JSON>> object_range() const { JSONConstWrapper<chaiscript::utility::QuickFlatMap<std::string, JSON>> object_range() const {
return std::get_if<static_cast<std::size_t>(Class::Object)>(&internal.d); return std::get_if<static_cast<std::size_t>(Class::Object)>(&internal.d);
} }
JSONConstWrapper<std::vector<JSON>> array_range() const { JSONConstWrapper<std::vector<JSON>> array_range() const { return std::get_if<static_cast<std::size_t>(Class::Array)>(&internal.d); }
return std::get_if<static_cast<std::size_t>(Class::Array)>(&internal.d);
}
std::string dump( long depth = 1, std::string tab = " ") const { std::string dump(long depth = 1, std::string tab = " ") const {
switch( internal.type() ) { switch (internal.type()) {
case Class::Null: case Class::Null:
return "null"; return "null";
case Class::Object: { case Class::Object: {
std::string pad = ""; std::string pad = "";
for( long i = 0; i < depth; ++i, pad += tab ) { } for (long i = 0; i < depth; ++i, pad += tab) {
}
std::string s = "{\n"; std::string s = "{\n";
bool skip = true; bool skip = true;
for( auto &p : *internal.Map() ) { for (auto &p : *internal.Map()) {
if( !skip ) { s += ",\n"; } if (!skip) {
s += ( pad + "\"" + json_escape(p.first) + "\" : " + p.second.dump( depth + 1, tab ) ); s += ",\n";
}
s += (pad + "\"" + json_escape(p.first) + "\" : " + p.second.dump(depth + 1, tab));
skip = false; skip = false;
} }
s += ( "\n" + pad.erase( 0, 2 ) + "}" ) ; s += ("\n" + pad.erase(0, 2) + "}");
return s; return s;
} }
case Class::Array: { case Class::Array: {
std::string s = "["; std::string s = "[";
bool skip = true; bool skip = true;
for( auto &p : *internal.Vector() ) { for (auto &p : *internal.Vector()) {
if( !skip ) { s += ", "; } if (!skip) {
s += p.dump( depth + 1, tab ); s += ", ";
}
s += p.dump(depth + 1, tab);
skip = false; skip = false;
} }
s += "]"; s += "]";
return s; return s;
} }
case Class::String: case Class::String:
return "\"" + json_escape( *internal.String() ) + "\""; return "\"" + json_escape(*internal.String()) + "\"";
case Class::Floating: case Class::Floating:
return std::to_string( *internal.Float() ); return std::to_string(*internal.Float());
case Class::Integral: case Class::Integral:
return std::to_string( *internal.Int() ); return std::to_string(*internal.Int());
case Class::Boolean: case Class::Boolean:
return *internal.Bool() ? "true" : "false"; return *internal.Bool() ? "true" : "false";
} }
@ -351,35 +310,47 @@ class JSON
throw std::runtime_error("Unhandled JSON type"); throw std::runtime_error("Unhandled JSON type");
} }
private: private:
static std::string json_escape( const std::string &str ) { static std::string json_escape(const std::string &str) {
std::string output; std::string output;
for(char i : str) { for (char i : str) {
switch( i ) { switch (i) {
case '\"': output += "\\\""; break; case '\"':
case '\\': output += "\\\\"; break; output += "\\\"";
case '\b': output += "\\b"; break; break;
case '\f': output += "\\f"; break; case '\\':
case '\n': output += "\\n"; break; output += "\\\\";
case '\r': output += "\\r"; break; break;
case '\t': output += "\\t"; break; case '\b':
default : output += i; break; output += "\\b";
break;
case '\f':
output += "\\f";
break;
case '\n':
output += "\\n";
break;
case '\r':
output += "\\r";
break;
case '\t':
output += "\\t";
break;
default:
output += i;
break;
}
} }
}
return output; return output;
} }
private: private:
}; };
struct JSONParser {
struct JSONParser { static bool isspace(const char c) noexcept {
static bool isspace(const char c) noexcept
{
#ifdef CHAISCRIPT_MSVC #ifdef CHAISCRIPT_MSVC
// MSVC warns on these line in some circumstances // MSVC warns on these line in some circumstances
#pragma warning(push) #pragma warning(push)
#pragma warning(disable : 6330) #pragma warning(disable : 6330)
#endif #endif
@ -387,41 +358,42 @@ struct JSONParser {
#ifdef CHAISCRIPT_MSVC #ifdef CHAISCRIPT_MSVC
#pragma warning(pop) #pragma warning(pop)
#endif #endif
} }
static void consume_ws( const std::string &str, size_t &offset ) { static void consume_ws(const std::string &str, size_t &offset) {
while( isspace( str.at(offset) ) && offset <= str.size() ) { ++offset; } while (isspace(str.at(offset)) && offset <= str.size()) {
++offset;
}
} }
static JSON parse_object( const std::string &str, size_t &offset ) { static JSON parse_object(const std::string &str, size_t &offset) {
JSON Object( JSON::Class::Object ); JSON Object(JSON::Class::Object);
++offset; ++offset;
consume_ws( str, offset ); consume_ws(str, offset);
if( str.at(offset) == '}' ) { if (str.at(offset) == '}') {
++offset; return Object; ++offset;
return Object;
} }
for (;offset<str.size();) { for (; offset < str.size();) {
JSON Key = parse_next( str, offset ); JSON Key = parse_next(str, offset);
consume_ws( str, offset ); consume_ws(str, offset);
if( str.at(offset) != ':' ) { if (str.at(offset) != ':') {
throw std::runtime_error(std::string("JSON ERROR: Object: Expected colon, found '") + str.at(offset) + "'\n"); throw std::runtime_error(std::string("JSON ERROR: Object: Expected colon, found '") + str.at(offset) + "'\n");
} }
consume_ws( str, ++offset ); consume_ws(str, ++offset);
JSON Value = parse_next( str, offset ); JSON Value = parse_next(str, offset);
Object[Key.to_string()] = Value; Object[Key.to_string()] = Value;
consume_ws( str, offset ); consume_ws(str, offset);
if( str.at(offset) == ',' ) { if (str.at(offset) == ',') {
++offset; continue; ++offset;
} continue;
else if( str.at(offset) == '}' ) { } else if (str.at(offset) == '}') {
++offset; break; ++offset;
} break;
else { } else {
throw std::runtime_error(std::string("JSON ERROR: Object: Expected comma, found '") + str.at(offset) + "'\n"); throw std::runtime_error(std::string("JSON ERROR: Object: Expected comma, found '") + str.at(offset) + "'\n");
} }
} }
@ -429,27 +401,28 @@ struct JSONParser {
return Object; return Object;
} }
static JSON parse_array( const std::string &str, size_t &offset ) { static JSON parse_array(const std::string &str, size_t &offset) {
JSON Array( JSON::Class::Array ); JSON Array(JSON::Class::Array);
size_t index = 0; size_t index = 0;
++offset; ++offset;
consume_ws( str, offset ); consume_ws(str, offset);
if( str.at(offset) == ']' ) { if (str.at(offset) == ']') {
++offset; return Array; ++offset;
return Array;
} }
for (;offset < str.size();) { for (; offset < str.size();) {
Array[index++] = parse_next( str, offset ); Array[index++] = parse_next(str, offset);
consume_ws( str, offset ); consume_ws(str, offset);
if( str.at(offset) == ',' ) { if (str.at(offset) == ',') {
++offset; continue; ++offset;
} continue;
else if( str.at(offset) == ']' ) { } else if (str.at(offset) == ']') {
++offset; break; ++offset;
} break;
else { } else {
throw std::runtime_error(std::string("JSON ERROR: Array: Expected ',' or ']', found '") + str.at(offset) + "'\n"); throw std::runtime_error(std::string("JSON ERROR: Array: Expected ',' or ']', found '") + str.at(offset) + "'\n");
} }
} }
@ -457,32 +430,51 @@ struct JSONParser {
return Array; return Array;
} }
static JSON parse_string( const std::string &str, size_t &offset ) { static JSON parse_string(const std::string &str, size_t &offset) {
std::string val; std::string val;
for( char c = str.at(++offset); c != '\"' ; c = str.at(++offset) ) { for (char c = str.at(++offset); c != '\"'; c = str.at(++offset)) {
if( c == '\\' ) { if (c == '\\') {
switch( str.at(++offset) ) { switch (str.at(++offset)) {
case '\"': val += '\"'; break; case '\"':
case '\\': val += '\\'; break; val += '\"';
case '/' : val += '/' ; break; break;
case 'b' : val += '\b'; break; case '\\':
case 'f' : val += '\f'; break; val += '\\';
case 'n' : val += '\n'; break; break;
case 'r' : val += '\r'; break; case '/':
case 't' : val += '\t'; break; val += '/';
case 'u' : { break;
val += "\\u" ; case 'b':
for( size_t i = 1; i <= 4; ++i ) { val += '\b';
c = str.at(offset+i); break;
if( (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F') ) { case 'f':
val += '\f';
break;
case 'n':
val += '\n';
break;
case 'r':
val += '\r';
break;
case 't':
val += '\t';
break;
case 'u': {
val += "\\u";
for (size_t i = 1; i <= 4; ++i) {
c = str.at(offset + i);
if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')) {
val += c; val += c;
} else { } else {
throw std::runtime_error(std::string("JSON ERROR: String: Expected hex character in unicode escape, found '") + c + "'"); throw std::runtime_error(
std::string("JSON ERROR: String: Expected hex character in unicode escape, found '") + c + "'");
} }
} }
offset += 4; offset += 4;
} break; } break;
default : val += '\\'; break; default:
val += '\\';
break;
} }
} else { } else {
val += c; val += c;
@ -492,113 +484,115 @@ struct JSONParser {
return JSON(val); return JSON(val);
} }
static JSON parse_number( const std::string &str, size_t &offset ) { static JSON parse_number(const std::string &str, size_t &offset) {
std::string val, exp_str; std::string val, exp_str;
char c = '\0'; char c = '\0';
bool isDouble = false; bool isDouble = false;
bool isNegative = false; bool isNegative = false;
std::int64_t exp = 0; std::int64_t exp = 0;
bool isExpNegative = false; bool isExpNegative = false;
if( offset < str.size() && str.at(offset) == '-' ) { if (offset < str.size() && str.at(offset) == '-') {
isNegative = true; isNegative = true;
++offset; ++offset;
} }
for (; offset < str.size() ;) { for (; offset < str.size();) {
c = str.at(offset++); c = str.at(offset++);
if( c >= '0' && c <= '9' ) { if (c >= '0' && c <= '9') {
val += c; val += c;
} else if( c == '.' && !isDouble ) { } else if (c == '.' && !isDouble) {
val += c; val += c;
isDouble = true; isDouble = true;
} else { } else {
break; break;
} }
} }
if( offset < str.size() && (c == 'E' || c == 'e' )) { if (offset < str.size() && (c == 'E' || c == 'e')) {
c = str.at(offset++); c = str.at(offset++);
if( c == '-' ) { if (c == '-') {
isExpNegative = true; isExpNegative = true;
} else if( c == '+' ) { } else if (c == '+') {
// do nothing // do nothing
} else { } else {
--offset; --offset;
} }
for (; offset < str.size() ;) { for (; offset < str.size();) {
c = str.at(offset++); c = str.at(offset++);
if( c >= '0' && c <= '9' ) { if (c >= '0' && c <= '9') {
exp_str += c; exp_str += c;
} else if( !isspace( c ) && c != ',' && c != ']' && c != '}' ) { } else if (!isspace(c) && c != ',' && c != ']' && c != '}') {
throw std::runtime_error(std::string("JSON ERROR: Number: Expected a number for exponent, found '") + c + "'"); throw std::runtime_error(std::string("JSON ERROR: Number: Expected a number for exponent, found '") + c + "'");
} } else {
else {
break; break;
} }
} }
exp = chaiscript::parse_num<std::int64_t>( exp_str ) * (isExpNegative?-1:1); exp = chaiscript::parse_num<std::int64_t>(exp_str) * (isExpNegative ? -1 : 1);
} } else if (offset < str.size() && (!isspace(c) && c != ',' && c != ']' && c != '}')) {
else if( offset < str.size() && (!isspace( c ) && c != ',' && c != ']' && c != '}' )) {
throw std::runtime_error(std::string("JSON ERROR: Number: unexpected character '") + c + "'"); throw std::runtime_error(std::string("JSON ERROR: Number: unexpected character '") + c + "'");
} }
--offset; --offset;
if( isDouble ) { if (isDouble) {
return JSON((isNegative?-1:1) * chaiscript::parse_num<double>( val ) * std::pow( 10, exp )); return JSON((isNegative ? -1 : 1) * chaiscript::parse_num<double>(val) * std::pow(10, exp));
} else { } else {
if( !exp_str.empty() ) { if (!exp_str.empty()) {
return JSON((isNegative?-1:1) * static_cast<double>(chaiscript::parse_num<std::int64_t>( val )) * std::pow( 10, exp )); return JSON((isNegative ? -1 : 1) * static_cast<double>(chaiscript::parse_num<std::int64_t>(val)) * std::pow(10, exp));
} else { } else {
return JSON((isNegative?-1:1) * chaiscript::parse_num<std::int64_t>( val )); return JSON((isNegative ? -1 : 1) * chaiscript::parse_num<std::int64_t>(val));
} }
} }
} }
static JSON parse_bool( const std::string &str, size_t &offset ) { static JSON parse_bool(const std::string &str, size_t &offset) {
if( str.substr( offset, 4 ) == "true" ) { if (str.substr(offset, 4) == "true") {
offset += 4; offset += 4;
return JSON(true); return JSON(true);
} else if( str.substr( offset, 5 ) == "false" ) { } else if (str.substr(offset, 5) == "false") {
offset += 5; offset += 5;
return JSON(false); return JSON(false);
} else { } else {
throw std::runtime_error(std::string("JSON ERROR: Bool: Expected 'true' or 'false', found '") + str.substr( offset, 5 ) + "'"); throw std::runtime_error(std::string("JSON ERROR: Bool: Expected 'true' or 'false', found '") + str.substr(offset, 5) + "'");
} }
} }
static JSON parse_null( const std::string &str, size_t &offset ) { static JSON parse_null(const std::string &str, size_t &offset) {
if( str.substr( offset, 4 ) != "null" ) { if (str.substr(offset, 4) != "null") {
throw std::runtime_error(std::string("JSON ERROR: Null: Expected 'null', found '") + str.substr( offset, 4 ) + "'"); throw std::runtime_error(std::string("JSON ERROR: Null: Expected 'null', found '") + str.substr(offset, 4) + "'");
} }
offset += 4; offset += 4;
return JSON(); return JSON();
} }
static JSON parse_next( const std::string &str, size_t &offset ) { static JSON parse_next(const std::string &str, size_t &offset) {
char value; char value;
consume_ws( str, offset ); consume_ws(str, offset);
value = str.at(offset); value = str.at(offset);
switch( value ) { switch (value) {
case '[' : return parse_array( str, offset ); case '[':
case '{' : return parse_object( str, offset ); return parse_array(str, offset);
case '\"': return parse_string( str, offset ); case '{':
case 't' : return parse_object(str, offset);
case 'f' : return parse_bool( str, offset ); case '\"':
case 'n' : return parse_null( str, offset ); return parse_string(str, offset);
default : if( ( value <= '9' && value >= '0' ) || value == '-' ) { case 't':
return parse_number( str, offset ); case 'f':
return parse_bool(str, offset);
case 'n':
return parse_null(str, offset);
default:
if ((value <= '9' && value >= '0') || value == '-') {
return parse_number(str, offset);
} }
} }
throw std::runtime_error(std::string("JSON ERROR: Parse: Unexpected starting character '") + value + "'"); throw std::runtime_error(std::string("JSON ERROR: Parse: Unexpected starting character '") + value + "'");
} }
};
}; inline JSON JSON::Load(const std::string &str) {
inline JSON JSON::Load( const std::string &str ) {
size_t offset = 0; size_t offset = 0;
return JSONParser::parse_next( str, offset ); return JSONParser::parse_next(str, offset);
} }
} // End Namespace json } // End Namespace json
#endif #endif

View File

@ -3,46 +3,34 @@
#include "json.hpp" #include "json.hpp"
namespace chaiscript namespace chaiscript {
{ class json_wrap {
class json_wrap
{
public: public:
static Module &library(Module &m) {
static Module& library(Module& m)
{
m.add(chaiscript::fun([](const std::string &t_str) { return from_json(t_str); }), "from_json"); m.add(chaiscript::fun([](const std::string &t_str) { return from_json(t_str); }), "from_json");
m.add(chaiscript::fun(&json_wrap::to_json), "to_json"); m.add(chaiscript::fun(&json_wrap::to_json), "to_json");
return m; return m;
} }
private: private:
static Boxed_Value from_json(const json::JSON &t_json) {
static Boxed_Value from_json(const json::JSON &t_json) switch (t_json.JSONType()) {
{
switch( t_json.JSONType() ) {
case json::JSON::Class::Null: case json::JSON::Class::Null:
return Boxed_Value(); return Boxed_Value();
case json::JSON::Class::Object: case json::JSON::Class::Object: {
{
std::map<std::string, Boxed_Value> m; std::map<std::string, Boxed_Value> m;
for (const auto &p : t_json.object_range()) for (const auto &p : t_json.object_range()) {
{
m.insert(std::make_pair(p.first, from_json(p.second))); m.insert(std::make_pair(p.first, from_json(p.second)));
} }
return Boxed_Value(m); return Boxed_Value(m);
} }
case json::JSON::Class::Array: case json::JSON::Class::Array: {
{
std::vector<Boxed_Value> vec; std::vector<Boxed_Value> vec;
for (const auto &p : t_json.array_range()) for (const auto &p : t_json.array_range()) {
{
vec.emplace_back(from_json(p)); vec.emplace_back(from_json(p));
} }
@ -61,28 +49,22 @@ namespace chaiscript
throw std::runtime_error("Unknown JSON type"); throw std::runtime_error("Unknown JSON type");
} }
static Boxed_Value from_json(const std::string &t_json) static Boxed_Value from_json(const std::string &t_json) {
{
try { try {
return from_json( json::JSON::Load(t_json) ); return from_json(json::JSON::Load(t_json));
} catch (const std::out_of_range& ) { } catch (const std::out_of_range &) {
throw std::runtime_error("Unparsed JSON input"); throw std::runtime_error("Unparsed JSON input");
} }
} }
static std::string to_json(const Boxed_Value &t_bv) static std::string to_json(const Boxed_Value &t_bv) { return to_json_object(t_bv).dump(); }
{
return to_json_object(t_bv).dump();
}
static json::JSON to_json_object(const Boxed_Value &t_bv) static json::JSON to_json_object(const Boxed_Value &t_bv) {
{
try { try {
const std::map<std::string, Boxed_Value> m = chaiscript::boxed_cast<const std::map<std::string, Boxed_Value> &>(t_bv); const std::map<std::string, Boxed_Value> m = chaiscript::boxed_cast<const std::map<std::string, Boxed_Value> &>(t_bv);
json::JSON obj(json::JSON::Class::Object); json::JSON obj(json::JSON::Class::Object);
for (const auto &o : m) for (const auto &o : m) {
{
obj[o.first] = to_json_object(o.second); obj[o.first] = to_json_object(o.second);
} }
return obj; return obj;
@ -94,8 +76,7 @@ namespace chaiscript
const std::vector<Boxed_Value> v = chaiscript::boxed_cast<const std::vector<Boxed_Value> &>(t_bv); const std::vector<Boxed_Value> v = chaiscript::boxed_cast<const std::vector<Boxed_Value> &>(t_bv);
json::JSON obj(json::JSON::Class::Array); json::JSON obj(json::JSON::Class::Array);
for (size_t i = 0; i < v.size(); ++i) for (size_t i = 0; i < v.size(); ++i) {
{
obj[i] = to_json_object(v[i]); obj[i] = to_json_object(v[i]);
} }
return obj; return obj;
@ -103,11 +84,9 @@ namespace chaiscript
// not a vector // not a vector
} }
try { try {
Boxed_Number bn(t_bv); Boxed_Number bn(t_bv);
if (Boxed_Number::is_floating_point(t_bv)) if (Boxed_Number::is_floating_point(t_bv)) {
{
return json::JSON(bn.get_as<double>()); return json::JSON(bn.get_as<double>());
} else { } else {
return json::JSON(bn.get_as<std::int64_t>()); return json::JSON(bn.get_as<std::int64_t>());
@ -128,13 +107,11 @@ namespace chaiscript
// not a string // not a string
} }
try { try {
const chaiscript::dispatch::Dynamic_Object &o = boxed_cast<const dispatch::Dynamic_Object &>(t_bv); const chaiscript::dispatch::Dynamic_Object &o = boxed_cast<const dispatch::Dynamic_Object &>(t_bv);
json::JSON obj(json::JSON::Class::Object); json::JSON obj(json::JSON::Class::Object);
for (const auto &attr : o.get_attrs()) for (const auto &attr : o.get_attrs()) {
{
obj[attr.first] = to_json_object(attr.second); obj[attr.first] = to_json_object(attr.second);
} }
return obj; return obj;
@ -142,15 +119,13 @@ namespace chaiscript
// not a dynamic object // not a dynamic object
} }
if (t_bv.is_null()) return json::JSON(); // a null value if (t_bv.is_null())
return json::JSON(); // a null value
throw std::runtime_error("Unknown object type to convert to JSON"); throw std::runtime_error("Unknown object type to convert to JSON");
} }
}; };
} // namespace chaiscript
}
#endif #endif

View File

@ -2,10 +2,8 @@
#define CHAISCRIPT_UTILITY_QUICK_FLAT_MAP_HPP #define CHAISCRIPT_UTILITY_QUICK_FLAT_MAP_HPP
namespace chaiscript::utility { namespace chaiscript::utility {
template<typename Key, typename Value, typename Comparator = std::equal_to<>>
template<typename Key, typename Value, typename Comparator=std::equal_to<>> struct QuickFlatMap {
struct QuickFlatMap
{
Comparator comparator; Comparator comparator;
template<typename Lookup> template<typename Lookup>
@ -28,35 +26,19 @@ namespace chaiscript::utility {
} }
} }
auto size() const noexcept { auto size() const noexcept { return data.size(); }
return data.size();
}
auto begin() const noexcept { auto begin() const noexcept { return data.begin(); }
return data.begin();
}
auto end() const noexcept { auto end() const noexcept { return data.end(); }
return data.end();
}
auto begin() noexcept { return data.begin(); }
auto begin() noexcept { auto end() noexcept { return data.end(); }
return data.begin();
}
auto end() noexcept { auto &back() noexcept { return data.back(); }
return data.end();
}
auto &back() noexcept {
return data.back();
}
const auto &back() const noexcept {
return data.back();
}
const auto &back() const noexcept { return data.back(); }
Value &operator[](const Key &s) { Value &operator[](const Key &s) {
const auto itr = find(s); const auto itr = find(s);
@ -68,24 +50,14 @@ namespace chaiscript::utility {
} }
} }
Value &at_index(const std::size_t idx) noexcept Value &at_index(const std::size_t idx) noexcept { return data[idx].second; }
{
return data[idx].second;
}
const Value &at_index(const std::size_t idx) const noexcept const Value &at_index(const std::size_t idx) const noexcept { return data[idx].second; }
{
return data[idx].second;
}
bool empty() const noexcept bool empty() const noexcept { return data.empty(); }
{
return data.empty();
}
template<typename Itr> template<typename Itr>
void assign(Itr begin, Itr end) void assign(Itr begin, Itr end) {
{
data.assign(begin, end); data.assign(begin, end);
} }
@ -98,10 +70,8 @@ namespace chaiscript::utility {
} }
} }
template<typename M> template<typename M>
auto insert_or_assign(Key &&key, M &&m) auto insert_or_assign(Key &&key, M &&m) {
{
if (auto itr = find(key); itr != data.end()) { if (auto itr = find(key); itr != data.end()) {
*itr = std::forward<M>(m); *itr = std::forward<M>(m);
return std::pair{itr, false}; return std::pair{itr, false};
@ -111,10 +81,8 @@ namespace chaiscript::utility {
} }
} }
template<typename M> template<typename M>
auto insert_or_assign(const Key &key, M &&m) auto insert_or_assign(const Key &key, M &&m) {
{
if (auto itr = find(key); itr != data.end()) { if (auto itr = find(key); itr != data.end()) {
itr->second = std::forward<M>(m); itr->second = std::forward<M>(m);
return std::pair{itr, false}; return std::pair{itr, false};
@ -135,7 +103,7 @@ namespace chaiscript::utility {
template<typename Lookup> template<typename Lookup>
size_t count(const Lookup &s) const noexcept { size_t count(const Lookup &s) const noexcept {
return (find(s) != data.end())?1:0; return (find(s) != data.end()) ? 1 : 0;
} }
std::vector<std::pair<Key, Value>> data; std::vector<std::pair<Key, Value>> data;
@ -144,8 +112,7 @@ namespace chaiscript::utility {
using iterator = typename decltype(data)::iterator; using iterator = typename decltype(data)::iterator;
using const_iterator = typename decltype(data)::const_iterator; using const_iterator = typename decltype(data)::const_iterator;
std::pair<iterator,bool> insert( value_type&& value ) std::pair<iterator, bool> insert(value_type &&value) {
{
if (const auto itr = find(value.first); itr != data.end()) { if (const auto itr = find(value.first); itr != data.end()) {
return std::pair{itr, false}; return std::pair{itr, false};
} else { } else {
@ -159,11 +126,8 @@ namespace chaiscript::utility {
data.reserve(data.size() + 2); data.reserve(data.size() + 2);
} }
} }
}; };
} } // namespace chaiscript::utility
#endif #endif

View File

@ -7,47 +7,36 @@
// This is an open source non-commercial project. Dear PVS-Studio, please check it. // This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com // PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_STACK_VECTOR_HPP_ #ifndef CHAISCRIPT_STACK_VECTOR_HPP_
#define CHAISCRIPT_STACK_VECTOR_HPP_ #define CHAISCRIPT_STACK_VECTOR_HPP_
#include <cstdint> #include <cstdint>
#include <type_traits>
#include <string> #include <string>
#include <type_traits>
template<typename T, std::size_t MaxSize> template<typename T, std::size_t MaxSize>
struct Stack_Vector struct Stack_Vector {
{
constexpr static auto aligned_size = sizeof(T) + (sizeof(T) & std::alignment_of_v<T>) > 0 ? std::alignment_of_v<T> : 0; constexpr static auto aligned_size = sizeof(T) + (sizeof(T) & std::alignment_of_v<T>) > 0 ? std::alignment_of_v<T> : 0;
alignas(std::alignment_of_v<T>) char data[aligned_size * MaxSize]; alignas(std::alignment_of_v<T>) char data[aligned_size * MaxSize];
[[nodiscard]] T & operator[](const std::size_t idx) noexcept { [[nodiscard]] T &operator[](const std::size_t idx) noexcept { return *reinterpret_cast<T *>(&data + aligned_size * idx); }
return *reinterpret_cast<T*>(&data + aligned_size * idx);
[[nodiscard]] const T &operator[](const std::size_t idx) const noexcept {
return *reinterpret_cast<const T *>(&data + aligned_size * idx);
} }
[[nodiscard]] const T & operator[](const std::size_t idx) const noexcept { template<typename... Param>
return *reinterpret_cast<const T*>(&data + aligned_size * idx); T &emplace_back(Param &&...param) {
} auto *p = new (&(*this)[m_size++]) T(std::forward<Param>(param)...);
template<typename ... Param>
T& emplace_back(Param && ... param) {
auto *p = new(&(*this)[m_size++]) T(std::forward<Param>(param)...);
return *p; return *p;
}; };
auto size() const noexcept { auto size() const noexcept { return m_size; };
return m_size;
};
void pop_back() noexcept(std::is_nothrow_destructible_v<T>) { void pop_back() noexcept(std::is_nothrow_destructible_v<T>) { (*this)[--m_size].~T(); }
(*this)[--m_size].~T();
}
~Stack_Vector() noexcept(std::is_nothrow_destructible_v<T>) ~Stack_Vector() noexcept(std::is_nothrow_destructible_v<T>) {
{
auto loc = m_size - 1; auto loc = m_size - 1;
for (std::size_t pos = 0; pos < m_size; ++pos) { for (std::size_t pos = 0; pos < m_size; ++pos) {
(*this)[loc--].~T(); (*this)[loc--].~T();
@ -55,9 +44,6 @@ struct Stack_Vector
} }
std::size_t m_size{0}; std::size_t m_size{0};
}; };
#endif CHAISCRIPT_STACK_VECTOR_HPP_ #endif CHAISCRIPT_STACK_VECTOR_HPP_

View File

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

View File

@ -7,7 +7,6 @@
// This is an open source non-commercial project. Dear PVS-Studio, please check it. // This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com // PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#ifndef CHAISCRIPT_UTILITY_UTILITY_HPP_ #ifndef CHAISCRIPT_UTILITY_UTILITY_HPP_
#define CHAISCRIPT_UTILITY_UTILITY_HPP_ #define CHAISCRIPT_UTILITY_UTILITY_HPP_
@ -16,16 +15,11 @@
#include <utility> #include <utility>
#include <vector> #include <vector>
#include "../language/chaiscript_common.hpp"
#include "../dispatchkit/register_function.hpp"
#include "../dispatchkit/operators.hpp" #include "../dispatchkit/operators.hpp"
#include "../dispatchkit/register_function.hpp"
#include "../language/chaiscript_common.hpp"
namespace chaiscript::utility {
namespace chaiscript
{
namespace utility
{
/// Single step command for registering a class with ChaiScript /// Single step command for registering a class with ChaiScript
/// ///
/// \param[in,out] t_module Model to add class to /// \param[in,out] t_module Model to add class to
@ -53,17 +47,14 @@ namespace chaiscript
void add_class(ModuleType &t_module, void add_class(ModuleType &t_module,
const std::string &t_class_name, const std::string &t_class_name,
const std::vector<chaiscript::Proxy_Function> &t_constructors, const std::vector<chaiscript::Proxy_Function> &t_constructors,
const std::vector<std::pair<chaiscript::Proxy_Function, std::string>> &t_funcs) const std::vector<std::pair<chaiscript::Proxy_Function, std::string>> &t_funcs) {
{
t_module.add(chaiscript::user_type<Class>(), t_class_name); t_module.add(chaiscript::user_type<Class>(), t_class_name);
for(const chaiscript::Proxy_Function &ctor: t_constructors) for (const chaiscript::Proxy_Function &ctor : t_constructors) {
{
t_module.add(ctor, t_class_name); t_module.add(ctor, t_class_name);
} }
for(const auto &fun: t_funcs) for (const auto &fun : t_funcs) {
{
t_module.add(fun.first, fun.second); t_module.add(fun.first, fun.second);
} }
} }
@ -72,13 +63,11 @@ namespace chaiscript
typename std::enable_if<std::is_enum<Enum>::value, void>::type typename std::enable_if<std::is_enum<Enum>::value, void>::type
add_class(ModuleType &t_module, add_class(ModuleType &t_module,
const std::string &t_class_name, const std::string &t_class_name,
const std::vector<std::pair<typename std::underlying_type<Enum>::type, std::string>> &t_constants const std::vector<std::pair<typename std::underlying_type<Enum>::type, std::string>> &t_constants) {
)
{
t_module.add(chaiscript::user_type<Enum>(), t_class_name); t_module.add(chaiscript::user_type<Enum>(), t_class_name);
t_module.add(chaiscript::constructor<Enum ()>(), t_class_name); t_module.add(chaiscript::constructor<Enum()>(), t_class_name);
t_module.add(chaiscript::constructor<Enum (const Enum &)>(), t_class_name); t_module.add(chaiscript::constructor<Enum(const Enum &)>(), t_class_name);
using namespace chaiscript::bootstrap::operators; using namespace chaiscript::bootstrap::operators;
equal<Enum>(t_module); equal<Enum>(t_module);
@ -88,19 +77,14 @@ namespace chaiscript
t_module.add(chaiscript::fun([](const Enum &e, const int &i) { return e == i; }), "=="); t_module.add(chaiscript::fun([](const Enum &e, const int &i) { return e == i; }), "==");
t_module.add(chaiscript::fun([](const int &i, const Enum &e) { return i == e; }), "=="); t_module.add(chaiscript::fun([](const int &i, const Enum &e) { return i == e; }), "==");
for (const auto &constant : t_constants) for (const auto &constant : t_constants) {
{
t_module.add_global_const(chaiscript::const_var(Enum(constant.first)), constant.second); t_module.add_global_const(chaiscript::const_var(Enum(constant.first)), constant.second);
} }
} }
template<typename EnumClass, typename ModuleType> template<typename EnumClass, typename ModuleType>
typename std::enable_if<std::is_enum<EnumClass>::value, void>::type typename std::enable_if<std::is_enum<EnumClass>::value, void>::type
add_class(ModuleType &t_module, add_class(ModuleType &t_module, const std::string &t_class_name, const std::vector<std::pair<EnumClass, std::string>> &t_constants) {
const std::string &t_class_name,
const std::vector<std::pair<EnumClass, std::string>> &t_constants
)
{
t_module.add(chaiscript::user_type<EnumClass>(), t_class_name); t_module.add(chaiscript::user_type<EnumClass>(), t_class_name);
t_module.add(chaiscript::constructor<EnumClass()>(), t_class_name); t_module.add(chaiscript::constructor<EnumClass()>(), t_class_name);
@ -111,13 +95,10 @@ namespace chaiscript
not_equal<EnumClass>(t_module); not_equal<EnumClass>(t_module);
assign<EnumClass>(t_module); assign<EnumClass>(t_module);
for (const auto &constant : t_constants) for (const auto &constant : t_constants) {
{
t_module.add_global_const(chaiscript::const_var(EnumClass(constant.first)), constant.second); t_module.add_global_const(chaiscript::const_var(EnumClass(constant.first)), constant.second);
} }
} }
} } // namespace chaiscript::utility
}
#endif #endif

View File

@ -5,8 +5,7 @@ double f(const std::string &, double, bool) noexcept {
return .0; return .0;
} }
int main() int main() {
{
chaiscript::ChaiScript chai; chaiscript::ChaiScript chai;
chai.add(chaiscript::fun(&f), "f"); chai.add(chaiscript::fun(&f), "f");
@ -16,5 +15,4 @@ int main()
f("str", 1.2, false); f("str", 1.2, false);
} }
)"); )");
} }

View File

@ -5,16 +5,14 @@ double f(const std::string &, double, bool) noexcept {
return .0; return .0;
} }
int main() int main() {
{
chaiscript::ChaiScript chai; chaiscript::ChaiScript chai;
chai.add(chaiscript::fun(&f), "f"); chai.add(chaiscript::fun(&f), "f");
const auto f = chai.eval<std::function<void ()>>(R"(fun(){ f("str", 1.2, false); })"); const auto f = chai.eval<std::function<void()>>(R"(fun(){ f("str", 1.2, false); })");
for (int i = 0; i < 100000; ++i) { for (int i = 0; i < 100000; ++i) {
f(); f();
} }
} }

View File

@ -1,52 +1,45 @@
#include <chaiscript/chaiscript.hpp> #include <chaiscript/chaiscript.hpp>
class Entity class Entity {
{ public:
public:
int width; int width;
int height; int height;
int x; int x;
int y; int y;
std::string name; std::string name;
std::function<void (Entity &)> updater; std::function<void(Entity &)> updater;
Entity(const int t_width, const int t_height, const int t_x, const int t_y, std::string t_name) Entity(const int t_width, const int t_height, const int t_x, const int t_y, std::string t_name)
: width(t_width), height(t_height), x(t_x), y(t_y), name(std::move(t_name)) : width(t_width)
{ , height(t_height)
, x(t_x)
, y(t_y)
, name(std::move(t_name)) {
} }
}; };
class Factory class Factory {
{ public:
public:
// we may as well pass the parameters for the entity to the factory method, this does the initialization // we may as well pass the parameters for the entity to the factory method, this does the initialization
// in one step. // in one step.
Entity *make_entity(const int width, const int height, const int x, const int y, const std::string &name) Entity *make_entity(const int width, const int height, const int x, const int y, const std::string &name) {
{
auto entity = entities.insert({name, Entity{width, height, x, y, name}}); auto entity = entities.insert({name, Entity{width, height, x, y, name}});
return &(entity.first->second); return &(entity.first->second);
} }
Entity *get_entity(const std::string &name) Entity *get_entity(const std::string &name) { return &entities.at(name); }
{
return &entities.at(name);
}
// loop over all entities and all their updater function (if it exists) // loop over all entities and all their updater function (if it exists)
void update_entities() void update_entities() {
{ for (auto &entity : entities) {
for (auto &entity : entities)
{
if (entity.second.updater) { if (entity.second.updater) {
entity.second.updater(entity.second); entity.second.updater(entity.second);
} }
} }
} }
private:
private:
// we cannot store the entities in a std::vector if we want to return a pointer to them, // we cannot store the entities in a std::vector if we want to return a pointer to them,
// because a vector automatically resizing itself can invalidate the pointer that was returned. // because a vector automatically resizing itself can invalidate the pointer that was returned.
// using a map guarantees that the memory assigned to the entity will never change, plus // using a map guarantees that the memory assigned to the entity will never change, plus
@ -54,8 +47,7 @@ class Factory
std::map<std::string, Entity> entities; std::map<std::string, Entity> entities;
}; };
int main() int main() {
{
chaiscript::ChaiScript chai; chaiscript::ChaiScript chai;
chai.add(chaiscript::fun(&Entity::width), "width"); chai.add(chaiscript::fun(&Entity::width), "width");
@ -71,7 +63,6 @@ int main()
chai.add(chaiscript::fun(&Factory::update_entities), "update_entities"); chai.add(chaiscript::fun(&Factory::update_entities), "update_entities");
chai.add(chaiscript::user_type<Factory>(), "Factory"); // this isn't strictly necessary but makes error messages nicer chai.add(chaiscript::user_type<Factory>(), "Factory"); // this isn't strictly necessary but makes error messages nicer
Factory f; Factory f;
chai.add(chaiscript::var(&f), "f"); chai.add(chaiscript::var(&f), "f");
@ -92,11 +83,5 @@ int main()
print(f.get_entity("entity3").x == 20) // this one has no updater, so it stays the same print(f.get_entity("entity3").x == 20) // this one has no updater, so it stays the same
)""; )"";
chai.eval(script); chai.eval(script);
} }

View File

@ -7,7 +7,6 @@
// This is an open source non-commercial project. Dear PVS-Studio, please check it. // This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com // PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#include <iostream> #include <iostream>
#include <list> #include <list>
#include <regex> #include <regex>
@ -19,14 +18,15 @@
#include <chaiscript/chaiscript.hpp> #include <chaiscript/chaiscript.hpp>
#ifdef READLINE_AVAILABLE #ifdef READLINE_AVAILABLE
#include <readline/readline.h>
#include <readline/history.h> #include <readline/history.h>
#include <readline/readline.h>
#else #else
char *mystrdup(const char *s) { char *mystrdup(const char *s) {
size_t len = strlen(s); // Space for length plus nul 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 if (d == nullptr)
return nullptr; // No memory
#ifdef CHAISCRIPT_MSVC #ifdef CHAISCRIPT_MSVC
strcpy_s(d, len + 1, s); // Copy the characters strcpy_s(d, len + 1, s); // Copy the characters
#else #else
@ -36,26 +36,20 @@ char *mystrdup(const char *s) {
return d; // Return the new string return d; // Return the new string
} }
char* readline(const char* p) char *readline(const char *p) {
{
std::string retval; std::string retval;
std::cout << p; std::cout << p;
std::getline(std::cin, retval); std::getline(std::cin, retval);
return std::cin.eof() ? nullptr : mystrdup(retval.c_str()); return std::cin.eof() ? nullptr : mystrdup(retval.c_str());
} }
void add_history(const char *) {}
void add_history(const char*){} void using_history() {}
void using_history(){}
#endif #endif
void *cast_module_symbol(std::vector<std::string> (*t_path)()) {
union cast_union {
void *cast_module_symbol(std::vector<std::string>(*t_path)()) std::vector<std::string> (*in_ptr)();
{
union cast_union
{
std::vector<std::string>(*in_ptr)();
void *out_ptr; void *out_ptr;
}; };
@ -64,8 +58,7 @@ void *cast_module_symbol(std::vector<std::string>(*t_path)())
return c.out_ptr; return c.out_ptr;
} }
std::vector<std::string> default_search_paths() std::vector<std::string> default_search_paths() {
{
std::vector<std::string> paths; std::vector<std::string> paths;
#ifndef CHAISCRIPT_NO_DYNLOAD #ifndef CHAISCRIPT_NO_DYNLOAD
@ -77,14 +70,12 @@ std::vector<std::string> default_search_paths()
size_t lastslash = exepath.rfind('\\'); size_t lastslash = exepath.rfind('\\');
size_t secondtolastslash = exepath.rfind('\\', lastslash - 1); size_t secondtolastslash = exepath.rfind('\\', lastslash - 1);
if (lastslash != std::string::npos) if (lastslash != std::string::npos) {
{
paths.push_back(exepath.substr(0, lastslash)); paths.push_back(exepath.substr(0, lastslash));
} }
if (secondtolastslash != std::string::npos) if (secondtolastslash != std::string::npos) {
{ return {exepath.substr(0, secondtolastslash) + "\\lib\\chaiscript\\"};
return{ exepath.substr(0, secondtolastslash) + "\\lib\\chaiscript\\" };
} }
#else #else
@ -93,29 +84,23 @@ std::vector<std::string> default_search_paths()
std::vector<char> buf(2048); std::vector<char> buf(2048);
ssize_t size = -1; ssize_t size = -1;
if ((size = readlink("/proc/self/exe", &buf.front(), buf.size())) > 0) if ((size = readlink("/proc/self/exe", &buf.front(), buf.size())) > 0) {
{
exepath = std::string(&buf.front(), static_cast<size_t>(size)); exepath = std::string(&buf.front(), static_cast<size_t>(size));
} }
if (exepath.empty()) if (exepath.empty()) {
{ if ((size = readlink("/proc/curproc/file", &buf.front(), buf.size())) > 0) {
if ((size = readlink("/proc/curproc/file", &buf.front(), buf.size())) > 0)
{
exepath = std::string(&buf.front(), static_cast<size_t>(size)); exepath = std::string(&buf.front(), static_cast<size_t>(size));
} }
} }
if (exepath.empty()) if (exepath.empty()) {
{ if ((size = readlink("/proc/self/path/a.out", &buf.front(), buf.size())) > 0) {
if ((size = readlink("/proc/self/path/a.out", &buf.front(), buf.size())) > 0)
{
exepath = std::string(&buf.front(), static_cast<size_t>(size)); exepath = std::string(&buf.front(), static_cast<size_t>(size));
} }
} }
if (exepath.empty()) if (exepath.empty()) {
{
Dl_info rInfo; Dl_info rInfo;
memset(&rInfo, 0, sizeof(rInfo)); memset(&rInfo, 0, sizeof(rInfo));
if (!dladdr(cast_module_symbol(&default_search_paths), &rInfo) || !rInfo.dli_fname) { if (!dladdr(cast_module_symbol(&default_search_paths), &rInfo) || !rInfo.dli_fname) {
@ -128,13 +113,11 @@ std::vector<std::string> default_search_paths()
size_t lastslash = exepath.rfind('/'); size_t lastslash = exepath.rfind('/');
size_t secondtolastslash = exepath.rfind('/', lastslash - 1); size_t secondtolastslash = exepath.rfind('/', lastslash - 1);
if (lastslash != std::string::npos) if (lastslash != std::string::npos) {
{
paths.push_back(exepath.substr(0, lastslash)); paths.push_back(exepath.substr(0, lastslash));
} }
if (secondtolastslash != std::string::npos) if (secondtolastslash != std::string::npos) {
{
paths.push_back(exepath.substr(0, secondtolastslash) + "/lib/chaiscript/"); paths.push_back(exepath.substr(0, secondtolastslash) + "/lib/chaiscript/");
} }
#endif #endif
@ -149,8 +132,7 @@ void help(int n) {
std::cout << "Additionally, you can inspect the runtime system using:\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_system() - outputs all functions registered to the system\n";
std::cout << " dump_object(x) - dumps information about the given symbol\n"; std::cout << " dump_object(x) - dumps information about the given symbol\n";
} } else {
else {
std::cout << "usage : chai [option]+\n"; std::cout << "usage : chai [option]+\n";
std::cout << "option:\n"; std::cout << "option:\n";
std::cout << " -h | --help\n"; std::cout << " -h | --help\n";
@ -162,29 +144,24 @@ void help(int n) {
} }
} }
std::string helloWorld(const std::string &t_name) std::string helloWorld(const std::string &t_name) {
{
return "Hello " + t_name + "!"; return "Hello " + t_name + "!";
} }
bool throws_exception(const std::function<void()> &f) bool throws_exception(const std::function<void()> &f) {
{
try { try {
f(); f();
} } catch (...) {
catch (...) {
return true; return true;
} }
return false; return false;
} }
chaiscript::exception::eval_error get_eval_error(const std::function<void()> &f) chaiscript::exception::eval_error get_eval_error(const std::function<void()> &f) {
{
try { try {
f(); f();
} } catch (const chaiscript::exception::eval_error &e) {
catch (const chaiscript::exception::eval_error &e) {
return e; return e;
} }
@ -200,13 +177,11 @@ std::string get_next_command() {
std::string val(input_raw); std::string val(input_raw);
size_t pos = val.find_first_not_of("\t \n"); size_t pos = val.find_first_not_of("\t \n");
if (pos != std::string::npos) if (pos != std::string::npos) {
{
val.erase(0, pos); val.erase(0, pos);
} }
pos = val.find_last_not_of("\t \n"); pos = val.find_last_not_of("\t \n");
if (pos != std::string::npos) if (pos != std::string::npos) {
{
val.erase(pos + 1, std::string::npos); val.erase(pos + 1, std::string::npos);
} }
@ -215,11 +190,7 @@ std::string get_next_command() {
::free(input_raw); ::free(input_raw);
} }
} }
if (retval == "quit" if (retval == "quit" || retval == "exit" || retval == "help" || retval == "version") {
|| retval == "exit"
|| retval == "help"
|| retval == "version")
{
retval += "(0)"; retval += "(0)";
} }
return retval; return retval;
@ -231,8 +202,7 @@ void myexit(int return_val) {
exit(return_val); exit(return_val);
} }
void interactive(chaiscript::ChaiScript& chai) void interactive(chaiscript::ChaiScript &chai) {
{
using_history(); using_history();
for (;;) { for (;;) {
@ -241,32 +211,28 @@ void interactive(chaiscript::ChaiScript& chai)
// evaluate input // evaluate input
chaiscript::Boxed_Value val = chai.eval(input); chaiscript::Boxed_Value val = chai.eval(input);
//Then, we try to print the result of the evaluation to the user // Then, we try to print the result of the evaluation to the user
if (!val.get_type_info().bare_equal(chaiscript::user_type<void>())) { if (!val.get_type_info().bare_equal(chaiscript::user_type<void>())) {
try { 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) << '\n';
} catch (...) {
} // If we can't, do nothing
} }
catch (...) {} //If we can't, do nothing } catch (const chaiscript::exception::eval_error &ee) {
}
}
catch (const chaiscript::exception::eval_error &ee) {
std::cout << ee.what(); std::cout << ee.what();
if (ee.call_stack.size() > 0) { 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 << "during evaluation at (" << ee.call_stack[0].start().line << ", " << ee.call_stack[0].start().column << ")";
} }
std::cout << '\n'; std::cout << '\n';
} } catch (const std::exception &e) {
catch (const std::exception &e) {
std::cout << e.what(); std::cout << e.what();
std::cout << std::endl; std::cout << std::endl;
} }
} }
} }
int main(int argc, char *argv[]) int main(int argc, char *argv[]) {
{ // Disable deprecation warning for getenv call.
// Disable deprecation warning for getenv call.
#ifdef CHAISCRIPT_MSVC #ifdef CHAISCRIPT_MSVC
#pragma warning(push) #pragma warning(push)
#pragma warning(disable : 4996) #pragma warning(disable : 4996)
@ -281,8 +247,7 @@ int main(int argc, char *argv[])
std::vector<std::string> usepaths; std::vector<std::string> usepaths;
usepaths.push_back(""); usepaths.push_back("");
if (usepath) if (usepath) {
{
usepaths.push_back(usepath); usepaths.push_back(usepath);
} }
@ -290,12 +255,11 @@ int main(int argc, char *argv[])
std::vector<std::string> searchpaths = default_search_paths(); std::vector<std::string> searchpaths = default_search_paths();
modulepaths.insert(modulepaths.end(), searchpaths.begin(), searchpaths.end()); modulepaths.insert(modulepaths.end(), searchpaths.begin(), searchpaths.end());
modulepaths.push_back(""); modulepaths.push_back("");
if (modulepath) if (modulepath) {
{
modulepaths.push_back(modulepath); modulepaths.push_back(modulepath);
} }
//chaiscript::ChaiScript chai(modulepaths, usepaths); // chaiscript::ChaiScript chai(modulepaths, usepaths);
chaiscript::ChaiScript chai(usepaths); chaiscript::ChaiScript chai(usepaths);
chai.add(chaiscript::fun(&myexit), "exit"); chai.add(chaiscript::fun(&myexit), "exit");
@ -308,8 +272,7 @@ int main(int argc, char *argv[])
clock_t begin = clock(); clock_t begin = clock();
for (int i = 0; i < 1000; i++) for (int i = 0; i < 1000; i++) {
{
std::string str = helloWorld("Bob12345"); std::string str = helloWorld("Bob12345");
fwrite(str.c_str(), 1, str.size(), stdout); fwrite(str.c_str(), 1, str.size(), stdout);
} }
@ -317,17 +280,17 @@ int main(int argc, char *argv[])
clock_t end = clock(); clock_t end = clock();
double elapsed_secs = double(end - begin) / CLOCKS_PER_SEC; double elapsed_secs = double(end - begin) / CLOCKS_PER_SEC;
//begin = clock(); // begin = clock();
////for (int i = 0; i < 1000; i++) ////for (int i = 0; i < 1000; i++)
////{ ////{
//// chai.eval("puts(helloWorld(\"Bob12345\"));"); //// chai.eval("puts(helloWorld(\"Bob12345\"));");
////} ////}
//chai.eval_file("E:\\C++\\ChaiScript - 5.4.0\\samples\forx.chai"); // chai.eval_file("E:\\C++\\ChaiScript - 5.4.0\\samples\forx.chai");
//end = clock(); // end = clock();
//elapsed_secs = double(end - begin) / CLOCKS_PER_SEC; // elapsed_secs = double(end - begin) / CLOCKS_PER_SEC;
//printf("**MyProgram::time= %lf\n", elapsed_secs); // printf("**MyProgram::time= %lf\n", elapsed_secs);
for (int i = 0; i < argc; ++i) { for (int i = 0; i < argc; ++i) {
if (i == 0 && argc > 1) { if (i == 0 && argc > 1) {
@ -337,49 +300,47 @@ int main(int argc, char *argv[])
std::string arg(i ? argv[i] : "--interactive"); std::string arg(i ? argv[i] : "--interactive");
enum { enum {
eInteractive eInteractive,
, eCommand eCommand,
, eFile eFile
} mode = eCommand; } mode
= eCommand;
if (arg == "-c" || arg == "--command") { if (arg == "-c" || arg == "--command") {
if ((i + 1) >= argc) { if ((i + 1) >= argc) {
std::cout << "insufficient input following " << arg << std::endl; std::cout << "insufficient input following " << arg << std::endl;
return EXIT_FAILURE; return EXIT_FAILURE;
} } else {
else {
arg = argv[++i]; arg = argv[++i];
} }
} } else if (arg == "-" || arg == "--stdin") {
else if (arg == "-" || arg == "--stdin") {
arg = ""; arg = "";
std::string line; std::string line;
while (std::getline(std::cin, line)) { while (std::getline(std::cin, line)) {
arg += line + '\n'; arg += line + '\n';
} }
} } else if (arg == "-v" || arg == "--version") {
else if (arg == "-v" || arg == "--version") {
arg = "version()"; arg = "version()";
} } else if (arg == "-h" || arg == "--help") {
else if (arg == "-h" || arg == "--help") {
arg = "help(-1)"; arg = "help(-1)";
} } else if (arg == "-i" || arg == "--interactive") {
else if (arg == "-i" || arg == "--interactive") {
mode = eInteractive; mode = eInteractive;
} } else if (arg.find('-') == 0) {
else if (arg.find('-') == 0) {
std::cout << "unrecognised argument " << arg << std::endl; std::cout << "unrecognised argument " << arg << std::endl;
return EXIT_FAILURE; return EXIT_FAILURE;
} } else {
else {
mode = eFile; mode = eFile;
} }
chaiscript::Boxed_Value val; chaiscript::Boxed_Value val;
try { try {
switch (mode) { switch (mode) {
case eInteractive: interactive(chai); break; case eInteractive:
case eCommand: val = chai.eval(arg); break; interactive(chai);
break;
case eCommand:
val = chai.eval(arg);
break;
case eFile: { case eFile: {
begin = clock(); begin = clock();
@ -391,15 +352,12 @@ int main(int argc, char *argv[])
printf("**ChaiScript::time= %.10f\n", elapsed_secs1); printf("**ChaiScript::time= %.10f\n", elapsed_secs1);
break; break;
} }
} }
} } catch (const chaiscript::exception::eval_error &ee) {
catch (const chaiscript::exception::eval_error &ee) {
std::cout << ee.pretty_print(); std::cout << ee.pretty_print();
std::cout << std::endl; std::cout << std::endl;
return EXIT_FAILURE; return EXIT_FAILURE;
} } catch (std::exception &e) {
catch (std::exception &e) {
std::cout << e.what() << std::endl; std::cout << e.what() << std::endl;
return EXIT_FAILURE; return EXIT_FAILURE;
} }
@ -407,4 +365,3 @@ int main(int argc, char *argv[])
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }

View File

@ -1,79 +1,66 @@
#include <chaiscript/chaiscript.hpp> #include <chaiscript/chaiscript.hpp>
class BaseClass class BaseClass {
{ public:
public: BaseClass() = default;
BaseClass()
{
}
BaseClass(const BaseClass &) = default; BaseClass(const BaseClass &) = default;
virtual ~BaseClass() {} virtual ~BaseClass() = default;
virtual std::string doSomething(float, double) const = 0; virtual std::string doSomething(float, double) const = 0;
void setValue(const std::string &t_val) { void setValue(const std::string &t_val) {
if (validateValue(t_val)) if (validateValue(t_val)) {
{
m_value = t_val; m_value = t_val;
} }
} }
std::string getValue() const { std::string getValue() const { return m_value; }
return m_value;
}
protected: protected:
virtual bool validateValue(const std::string &t_val) = 0; virtual bool validateValue(const std::string &t_val) = 0;
private: private:
std::string m_value; std::string m_value;
}; };
class ChaiScriptDerived : public BaseClass class ChaiScriptDerived : public BaseClass {
{ public:
public: ChaiScriptDerived(const std::vector<chaiscript::Boxed_Value> &t_funcs) {
ChaiScriptDerived(const std::vector<chaiscript::Boxed_Value> &t_funcs)
{
// using the range-checked .at() methods to give us an exception // using the range-checked .at() methods to give us an exception
// instead of a crash if the user passed in too-few params // instead of a crash if the user passed in too-few params
tie(t_funcs.at(0), m_doSomethingImpl); tie(t_funcs.at(0), m_doSomethingImpl);
tie(t_funcs.at(1), m_validateValueImpl); tie(t_funcs.at(1), m_validateValueImpl);
} }
std::string doSomething(float f, double d) const override std::string doSomething(float f, double d) const override {
{
assert(m_doSomethingImpl); assert(m_doSomethingImpl);
return m_doSomethingImpl(*this, f, d); return m_doSomethingImpl(*this, f, d);
} }
protected: protected:
bool validateValue(const std::string &t_val) override bool validateValue(const std::string &t_val) override {
{
assert(m_validateValueImpl); assert(m_validateValueImpl);
return m_validateValueImpl(*this, t_val); return m_validateValueImpl(*this, t_val);
} }
private: private:
template<typename Param> template<typename Param>
void tie(const chaiscript::Boxed_Value &t_func, Param &t_param) void tie(const chaiscript::Boxed_Value &t_func, Param &t_param) {
{
t_param = chaiscript::boxed_cast<Param>(t_func); t_param = chaiscript::boxed_cast<Param>(t_func);
} }
std::function<std::string (const ChaiScriptDerived&, float, double)> m_doSomethingImpl; std::function<std::string(const ChaiScriptDerived &, float, double)> m_doSomethingImpl;
std::function<bool (ChaiScriptDerived&, const std::string &t_val)> m_validateValueImpl; std::function<bool(ChaiScriptDerived &, const std::string &t_val)> m_validateValueImpl;
}; };
int main() int main() {
{
chaiscript::ChaiScript chai; chaiscript::ChaiScript chai;
chai.add(chaiscript::fun(&BaseClass::doSomething), "doSomething"); chai.add(chaiscript::fun(&BaseClass::doSomething), "doSomething");
chai.add(chaiscript::fun(&BaseClass::setValue), "setValue"); chai.add(chaiscript::fun(&BaseClass::setValue), "setValue");
chai.add(chaiscript::fun(&BaseClass::getValue), "getValue"); chai.add(chaiscript::fun(&BaseClass::getValue), "getValue");
chai.add(chaiscript::constructor<ChaiScriptDerived (const std::vector<chaiscript::Boxed_Value> &)>(), "ChaiScriptDerived"); chai.add(chaiscript::constructor<ChaiScriptDerived(const std::vector<chaiscript::Boxed_Value> &)>(), "ChaiScriptDerived");
chai.add(chaiscript::base_class<BaseClass, ChaiScriptDerived>()); chai.add(chaiscript::base_class<BaseClass, ChaiScriptDerived>());
chai.add(chaiscript::user_type<BaseClass>(), "BaseClass"); chai.add(chaiscript::user_type<BaseClass>(), "BaseClass");
chai.add(chaiscript::user_type<ChaiScriptDerived>(), "ChaiScriptDerived"); chai.add(chaiscript::user_type<ChaiScriptDerived>(), "ChaiScriptDerived");
@ -106,7 +93,7 @@ int main()
chai.eval(script); chai.eval(script);
BaseClass &myderived = chai.eval<ChaiScriptDerived&>("myderived"); BaseClass &myderived = chai.eval<ChaiScriptDerived &>("myderived");
// at this point in the code myderived is both a ChaiScript variable and a C++ variable. In both cases // at this point in the code myderived is both a ChaiScript variable and a C++ variable. In both cases
// it is a derivation of BaseClass, and the implementation is provided via ChaiScript functors // it is a derivation of BaseClass, and the implementation is provided via ChaiScript functors
@ -121,7 +108,6 @@ int main()
myderived.setValue("12345"); myderived.setValue("12345");
assert(myderived.getValue() == "1234"); assert(myderived.getValue() == "1234");
chai.eval(R"(myderived.setValue("new"))"); // set the value via chaiscript chai.eval(R"(myderived.setValue("new"))"); // set the value via chaiscript
assert(myderived.getValue() == "new"); assert(myderived.getValue() == "new");
@ -131,5 +117,3 @@ int main()
// The whole process is fully orthogonal // The whole process is fully orthogonal
} }

View File

@ -3,12 +3,10 @@
#include <chaiscript/chaiscript.hpp> #include <chaiscript/chaiscript.hpp>
#ifdef READLINE_AVAILABLE #ifdef READLINE_AVAILABLE
#include <readline/readline.h>
#include <readline/history.h> #include <readline/history.h>
#include <readline/readline.h>
#endif #endif
std::string get_next_command() { std::string get_next_command() {
#ifdef READLINE_AVAILABLE #ifdef READLINE_AVAILABLE
char *input_raw; char *input_raw;
@ -23,42 +21,32 @@ std::string get_next_command() {
#endif #endif
} }
void function(void) void function(void) {
{
// do nothing // do nothing
} }
class test class test {
{
chaiscript::ChaiScript chai; chaiscript::ChaiScript chai;
chaiscript::ChaiScript::State backupState = chai.get_state(); chaiscript::ChaiScript::State backupState = chai.get_state();
public: public:
void ResetState() void ResetState() {
{
chai.set_state(backupState); chai.set_state(backupState);
chai.add(chaiscript::fun(&function),"Whatever()"); chai.add(chaiscript::fun(&function), "Whatever()");
} }
void RunFile(std::string sFile) void RunFile(std::string sFile) {
{
try { try {
chaiscript::Boxed_Value val = chai.eval_file(sFile); chaiscript::Boxed_Value val = chai.eval_file(sFile);
} } catch (std::exception &e) {
catch (std::exception &e) {
std::cout << e.what() << '\n'; std::cout << e.what() << '\n';
} }
} }
}; };
int main(int /*argc*/, char * /*argv*/[]) { int main(int /*argc*/, char * /*argv*/[]) {
test myChai; test myChai;
std::string command = ""; std::string command = "";
// //
@ -70,12 +58,11 @@ int main(int /*argc*/, char * /*argv*/[]) {
// scenario3 - RunFile gets in changing intervals: memory usage goes up and down, but never as // scenario3 - RunFile gets in changing intervals: memory usage goes up and down, but never as
// low as in case 1 scenario3 : // low as in case 1 scenario3 :
while(command != "quit") while (command != "quit") {
{ for (int i = 1; i < 200; i++)
for(int i = 1; i < 200; i++)
myChai.ResetState(); myChai.ResetState();
if(command == "runfile") if (command == "runfile")
myChai.RunFile("Test.chai"); myChai.RunFile("Test.chai");
command = get_next_command(); command = get_next_command();

View File

@ -2,14 +2,11 @@
#include <chaiscript/dispatchkit/bootstrap_stl.hpp> #include <chaiscript/dispatchkit/bootstrap_stl.hpp>
#include <chaiscript/dispatchkit/function_call.hpp> #include <chaiscript/dispatchkit/function_call.hpp>
int main( int /*argc*/ , char * /*argv*/[] ) int main(int /*argc*/, char * /*argv*/[]) {
{
chaiscript::ChaiScript ch; chaiscript::ChaiScript ch;
try {
try static const char script[] =
{
static const char script[ ] =
R""( R""(
class Rectangle class Rectangle
@ -21,12 +18,9 @@ int main( int /*argc*/ , char * /*argv*/[] )
)""; )"";
ch.eval(script);
ch.eval( script ); } catch (const std::exception &e) {
} printf(" >>> Exception thrown: %s \n", e.what());
catch ( const std::exception &e )
{
printf( " >>> Exception thrown: %s \n" , e.what( ) );
} }
return 1; return 1;

View File

@ -1,7 +1,6 @@
#include <chaiscript/chaiscript_stdlib.hpp> #include <chaiscript/chaiscript_stdlib.hpp>
// MSVC doesn't like that we are using C++ return types from our C declared module // MSVC doesn't like that we are using C++ return types from our C declared module
// but this is the best way to do it for cross platform compatibility // but this is the best way to do it for cross platform compatibility
#ifdef CHAISCRIPT_MSVC #ifdef CHAISCRIPT_MSVC
@ -14,13 +13,10 @@
#pragma clang diagnostic ignored "-Wreturn-type-c-linkage" #pragma clang diagnostic ignored "-Wreturn-type-c-linkage"
#endif #endif
CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_chaiscript_stdlib() {
CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_chaiscript_stdlib()
{
return chaiscript::Std_Lib::library(); return chaiscript::Std_Lib::library();
} }
#ifdef __llvm__ #ifdef __llvm__
#pragma clang diagnostic pop #pragma clang diagnostic pop
#endif #endif

View File

@ -7,7 +7,6 @@
// This is an open source non-commercial project. Dear PVS-Studio, please check it. // This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com // PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#include <iostream> #include <iostream>
#include <list> #include <list>
#include <regex> #include <regex>
@ -16,49 +15,45 @@
#define _CRT_SECURE_NO_WARNINGS #define _CRT_SECURE_NO_WARNINGS
#endif #endif
#include <chaiscript/chaiscript.hpp>
#include "../static_libs/chaiscript_parser.hpp" #include "../static_libs/chaiscript_parser.hpp"
#include "../static_libs/chaiscript_stdlib.hpp" #include "../static_libs/chaiscript_stdlib.hpp"
#include <chaiscript/chaiscript.hpp>
#include "sha3.h" #include "sha3.h"
#ifdef READLINE_AVAILABLE #ifdef READLINE_AVAILABLE
#include <readline/readline.h>
#include <readline/history.h> #include <readline/history.h>
#include <readline/readline.h>
#else #else
char *mystrdup (const char *s) { char *mystrdup(const char *s) {
size_t len = strlen(s); // Space for length plus nul 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 if (d == nullptr) {
return nullptr;
} // No memory
#ifdef CHAISCRIPT_MSVC #ifdef CHAISCRIPT_MSVC
strcpy_s(d, len+1, s); // Copy the characters strcpy_s(d, len + 1, s); // Copy the characters
#else #else
strncpy(d,s,len); // Copy the characters strncpy(d, s, len); // Copy the characters
#endif #endif
d[len] = '\0'; d[len] = '\0';
return d; // Return the new string return d; // Return the new string
} }
char* readline(const char* p) char *readline(const char *p) {
{
std::string retval; std::string retval;
std::cout << p ; std::cout << p;
std::getline(std::cin, retval); std::getline(std::cin, retval);
return std::cin.eof() ? nullptr : mystrdup(retval.c_str()); return std::cin.eof() ? nullptr : mystrdup(retval.c_str());
} }
void add_history(const char * /*unused*/) {}
void add_history(const char* /*unused*/){} void using_history() {}
void using_history(){}
#endif #endif
void *cast_module_symbol(std::vector<std::string> (*t_path)()) {
union cast_union {
void *cast_module_symbol(std::vector<std::string> (*t_path)())
{
union cast_union
{
std::vector<std::string> (*in_ptr)(); std::vector<std::string> (*in_ptr)();
void *out_ptr; void *out_ptr;
}; };
@ -68,26 +63,23 @@ void *cast_module_symbol(std::vector<std::string> (*t_path)())
return c.out_ptr; return c.out_ptr;
} }
std::vector<std::string> default_search_paths() std::vector<std::string> default_search_paths() {
{
std::vector<std::string> paths; std::vector<std::string> paths;
#ifndef CHAISCRIPT_NO_DYNLOAD #ifndef CHAISCRIPT_NO_DYNLOAD
#ifdef CHAISCRIPT_WINDOWS // force no unicode #ifdef CHAISCRIPT_WINDOWS // force no unicode
CHAR path[4096]; CHAR path[4096];
int size = GetModuleFileNameA(nullptr, path, sizeof(path)-1); int size = GetModuleFileNameA(nullptr, path, sizeof(path) - 1);
std::string exepath(path, size); std::string exepath(path, size);
size_t lastslash = exepath.rfind('\\'); size_t lastslash = exepath.rfind('\\');
size_t secondtolastslash = exepath.rfind('\\', lastslash - 1); size_t secondtolastslash = exepath.rfind('\\', lastslash - 1);
if (lastslash != std::string::npos) if (lastslash != std::string::npos) {
{
paths.push_back(exepath.substr(0, lastslash)); paths.push_back(exepath.substr(0, lastslash));
} }
if (secondtolastslash != std::string::npos) if (secondtolastslash != std::string::npos) {
{
return {exepath.substr(0, secondtolastslash) + "\\lib\\chaiscript\\"}; return {exepath.substr(0, secondtolastslash) + "\\lib\\chaiscript\\"};
} }
#else #else
@ -97,32 +89,26 @@ std::vector<std::string> default_search_paths()
std::vector<char> buf(2048); std::vector<char> buf(2048);
ssize_t size = -1; ssize_t size = -1;
if ((size = readlink("/proc/self/exe", &buf.front(), buf.size())) >= 0) if ((size = readlink("/proc/self/exe", &buf.front(), buf.size())) >= 0) {
{
exepath = std::string(&buf.front(), static_cast<size_t>(size)); exepath = std::string(&buf.front(), static_cast<size_t>(size));
} }
if (exepath.empty()) if (exepath.empty()) {
{ if ((size = readlink("/proc/curproc/file", &buf.front(), buf.size())) >= 0) {
if ((size = readlink("/proc/curproc/file", &buf.front(), buf.size())) >= 0)
{
exepath = std::string(&buf.front(), static_cast<size_t>(size)); exepath = std::string(&buf.front(), static_cast<size_t>(size));
} }
} }
if (exepath.empty()) if (exepath.empty()) {
{ if ((size = readlink("/proc/self/path/a.out", &buf.front(), buf.size())) >= 0) {
if ((size = readlink("/proc/self/path/a.out", &buf.front(), buf.size())) >= 0)
{
exepath = std::string(&buf.front(), static_cast<size_t>(size)); exepath = std::string(&buf.front(), static_cast<size_t>(size));
} }
} }
if (exepath.empty()) if (exepath.empty()) {
{
Dl_info rInfo; Dl_info rInfo;
memset( &rInfo, 0, sizeof(rInfo) ); memset(&rInfo, 0, sizeof(rInfo));
if ( dladdr(cast_module_symbol(&default_search_paths), &rInfo) == 0 || rInfo.dli_fname == nullptr ) { if (dladdr(cast_module_symbol(&default_search_paths), &rInfo) == 0 || rInfo.dli_fname == nullptr) {
return paths; return paths;
} }
@ -132,13 +118,11 @@ std::vector<std::string> default_search_paths()
size_t lastslash = exepath.rfind('/'); size_t lastslash = exepath.rfind('/');
size_t secondtolastslash = exepath.rfind('/', lastslash - 1); size_t secondtolastslash = exepath.rfind('/', lastslash - 1);
if (lastslash != std::string::npos) if (lastslash != std::string::npos) {
{ paths.push_back(exepath.substr(0, lastslash + 1));
paths.push_back(exepath.substr(0, lastslash+1));
} }
if (secondtolastslash != std::string::npos) if (secondtolastslash != std::string::npos) {
{
paths.push_back(exepath.substr(0, secondtolastslash) + "/lib/chaiscript/"); paths.push_back(exepath.substr(0, secondtolastslash) + "/lib/chaiscript/");
} }
#endif #endif
@ -148,7 +132,7 @@ std::vector<std::string> default_search_paths()
} }
void help(int n) { void help(int n) {
if ( n >= 0 ) { if (n >= 0) {
std::cout << "ChaiScript evaluator. To evaluate an expression, type it and press <enter>.\n"; 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 << "Additionally, you can inspect the runtime system using:\n";
std::cout << " dump_system() - outputs all functions registered to the system\n"; std::cout << " dump_system() - outputs all functions registered to the system\n";
@ -165,8 +149,7 @@ void help(int n) {
} }
} }
bool throws_exception(const std::function<void ()> &f) bool throws_exception(const std::function<void()> &f) {
{
try { try {
f(); f();
} catch (...) { } catch (...) {
@ -176,8 +159,7 @@ bool throws_exception(const std::function<void ()> &f)
return false; return false;
} }
chaiscript::exception::eval_error get_eval_error(const std::function<void ()> &f) chaiscript::exception::eval_error get_eval_error(const std::function<void()> &f) {
{
try { try {
f(); f();
} catch (const chaiscript::exception::eval_error &e) { } catch (const chaiscript::exception::eval_error &e) {
@ -189,21 +171,19 @@ chaiscript::exception::eval_error get_eval_error(const std::function<void ()> &f
std::string get_next_command() { std::string get_next_command() {
std::string retval("quit"); std::string retval("quit");
if ( ! std::cin.eof() ) { if (!std::cin.eof()) {
char *input_raw = readline("eval> "); char *input_raw = readline("eval> ");
if ( input_raw != nullptr ) { if (input_raw != nullptr) {
add_history(input_raw); add_history(input_raw);
std::string val(input_raw); std::string val(input_raw);
size_t pos = val.find_first_not_of("\t \n"); size_t pos = val.find_first_not_of("\t \n");
if (pos != std::string::npos) if (pos != std::string::npos) {
{
val.erase(0, pos); val.erase(0, pos);
} }
pos = val.find_last_not_of("\t \n"); pos = val.find_last_not_of("\t \n");
if (pos != std::string::npos) if (pos != std::string::npos) {
{ val.erase(pos + 1, std::string::npos);
val.erase(pos+1, std::string::npos);
} }
retval = val; retval = val;
@ -211,11 +191,7 @@ std::string get_next_command() {
::free(input_raw); ::free(input_raw);
} }
} }
if( retval == "quit" if (retval == "quit" || retval == "exit" || retval == "help" || retval == "version") {
|| retval == "exit"
|| retval == "help"
|| retval == "version")
{
retval += "(0)"; retval += "(0)";
} }
return retval; return retval;
@ -227,8 +203,7 @@ void myexit(int return_val) {
exit(return_val); exit(return_val);
} }
void interactive(chaiscript::ChaiScript_Basic& chai) void interactive(chaiscript::ChaiScript_Basic &chai) {
{
using_history(); using_history();
for (;;) { for (;;) {
@ -237,30 +212,27 @@ void interactive(chaiscript::ChaiScript_Basic& chai)
// evaluate input // evaluate input
chaiscript::Boxed_Value val = chai.eval(input); chaiscript::Boxed_Value val = chai.eval(input);
//Then, we try to print the result of the evaluation to the user // Then, we try to print the result of the evaluation to the user
if (!val.get_type_info().bare_equal(chaiscript::user_type<void>())) { if (!val.get_type_info().bare_equal(chaiscript::user_type<void>())) {
try { 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) << '\n';
} catch (...) {
} // If we can't, do nothing
} }
catch (...) {} //If we can't, do nothing } catch (const chaiscript::exception::eval_error &ee) {
}
}
catch (const chaiscript::exception::eval_error &ee) {
std::cout << ee.what(); std::cout << ee.what();
if ( !ee.call_stack.empty() ) { if (!ee.call_stack.empty()) {
std::cout << "during evaluation at (" << ee.call_stack[0].start().line << ", " << ee.call_stack[0].start().column << ")"; std::cout << "during evaluation at (" << ee.call_stack[0].start().line << ", " << ee.call_stack[0].start().column << ")";
} }
std::cout << '\n'; std::cout << '\n';
} } catch (const std::exception &e) {
catch (const std::exception &e) {
std::cout << e.what(); std::cout << e.what();
std::cout << '\n'; std::cout << '\n';
} }
} }
} }
double now() double now() {
{
using namespace std::chrono; using namespace std::chrono;
auto now = high_resolution_clock::now(); auto now = high_resolution_clock::now();
return duration_cast<duration<double>>(now.time_since_epoch()).count(); return duration_cast<duration<double>>(now.time_since_epoch()).count();
@ -269,7 +241,7 @@ double now()
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
chaiscript::ChaiScript chai; chaiscript::ChaiScript chai;
chai.eval( R"chaiscript( chai.eval(R"chaiscript(
def assert_equal(x, y) def assert_equal(x, y)
{ {
if (x == y) if (x == y)
@ -339,7 +311,8 @@ def assert_throws(desc, x)
std::ofstream ofs("BOXED_VALUE/" + sha); std::ofstream ofs("BOXED_VALUE/" + sha);
ofs << input; ofs << input;
} catch (const chaiscript::exception::load_module_error &e) { } catch (const chaiscript::exception::load_module_error &e) {
std::cout << "Unhandled module load error\n" << e.what() << '\n'; std::cout << "Unhandled module load error\n"
<< e.what() << '\n';
} catch (const std::exception &) { } catch (const std::exception &) {
std::ofstream ofs("STD_EXCEPTION/" + sha); std::ofstream ofs("STD_EXCEPTION/" + sha);
ofs << input; ofs << input;
@ -350,5 +323,3 @@ def assert_throws(desc, x)
return 0; return 0;
} }

View File

@ -7,7 +7,6 @@
// This is an open source non-commercial project. Dear PVS-Studio, please check it. // This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com // PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#include <iostream> #include <iostream>
#include <list> #include <list>
#include <regex> #include <regex>
@ -16,48 +15,43 @@
#define _CRT_SECURE_NO_WARNINGS #define _CRT_SECURE_NO_WARNINGS
#endif #endif
#include <chaiscript/chaiscript_basic.hpp>
#include "../static_libs/chaiscript_parser.hpp" #include "../static_libs/chaiscript_parser.hpp"
#include "../static_libs/chaiscript_stdlib.hpp" #include "../static_libs/chaiscript_stdlib.hpp"
#include <chaiscript/chaiscript_basic.hpp>
#ifdef READLINE_AVAILABLE #ifdef READLINE_AVAILABLE
#include <readline/readline.h>
#include <readline/history.h> #include <readline/history.h>
#include <readline/readline.h>
#else #else
char *mystrdup (const char *s) { char *mystrdup(const char *s) {
size_t len = strlen(s); // Space for length plus nul 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 if (d == nullptr) {
return nullptr;
} // No memory
#ifdef CHAISCRIPT_MSVC #ifdef CHAISCRIPT_MSVC
strcpy_s(d, len+1, s); // Copy the characters strcpy_s(d, len + 1, s); // Copy the characters
#else #else
strncpy(d,s,len); // Copy the characters strncpy(d, s, len); // Copy the characters
#endif #endif
d[len] = '\0'; d[len] = '\0';
return d; // Return the new string return d; // Return the new string
} }
char* readline(const char* p) char *readline(const char *p) {
{
std::string retval; std::string retval;
std::cout << p ; std::cout << p;
std::getline(std::cin, retval); std::getline(std::cin, retval);
return std::cin.eof() ? nullptr : mystrdup(retval.c_str()); return std::cin.eof() ? nullptr : mystrdup(retval.c_str());
} }
void add_history(const char * /*unused*/) {}
void add_history(const char* /*unused*/){} void using_history() {}
void using_history(){}
#endif #endif
void *cast_module_symbol(std::vector<std::string> (*t_path)()) {
union cast_union {
void *cast_module_symbol(std::vector<std::string> (*t_path)())
{
union cast_union
{
std::vector<std::string> (*in_ptr)(); std::vector<std::string> (*in_ptr)();
void *out_ptr; void *out_ptr;
}; };
@ -67,26 +61,23 @@ void *cast_module_symbol(std::vector<std::string> (*t_path)())
return c.out_ptr; return c.out_ptr;
} }
std::vector<std::string> default_search_paths() std::vector<std::string> default_search_paths() {
{
std::vector<std::string> paths; std::vector<std::string> paths;
#ifndef CHAISCRIPT_NO_DYNLOAD #ifndef CHAISCRIPT_NO_DYNLOAD
#ifdef CHAISCRIPT_WINDOWS // force no unicode #ifdef CHAISCRIPT_WINDOWS // force no unicode
CHAR path[4096]; CHAR path[4096];
int size = GetModuleFileNameA(nullptr, path, sizeof(path)-1); int size = GetModuleFileNameA(nullptr, path, sizeof(path) - 1);
std::string exepath(path, size); std::string exepath(path, size);
size_t lastslash = exepath.rfind('\\'); size_t lastslash = exepath.rfind('\\');
size_t secondtolastslash = exepath.rfind('\\', lastslash - 1); size_t secondtolastslash = exepath.rfind('\\', lastslash - 1);
if (lastslash != std::string::npos) if (lastslash != std::string::npos) {
{
paths.push_back(exepath.substr(0, lastslash)); paths.push_back(exepath.substr(0, lastslash));
} }
if (secondtolastslash != std::string::npos) if (secondtolastslash != std::string::npos) {
{
return {exepath.substr(0, secondtolastslash) + "\\lib\\chaiscript\\"}; return {exepath.substr(0, secondtolastslash) + "\\lib\\chaiscript\\"};
} }
#else #else
@ -96,32 +87,26 @@ std::vector<std::string> default_search_paths()
std::vector<char> buf(2048); std::vector<char> buf(2048);
ssize_t size = -1; ssize_t size = -1;
if ((size = readlink("/proc/self/exe", &buf.front(), buf.size())) >= 0) if ((size = readlink("/proc/self/exe", &buf.front(), buf.size())) >= 0) {
{
exepath = std::string(&buf.front(), static_cast<size_t>(size)); exepath = std::string(&buf.front(), static_cast<size_t>(size));
} }
if (exepath.empty()) if (exepath.empty()) {
{ if ((size = readlink("/proc/curproc/file", &buf.front(), buf.size())) >= 0) {
if ((size = readlink("/proc/curproc/file", &buf.front(), buf.size())) >= 0)
{
exepath = std::string(&buf.front(), static_cast<size_t>(size)); exepath = std::string(&buf.front(), static_cast<size_t>(size));
} }
} }
if (exepath.empty()) if (exepath.empty()) {
{ if ((size = readlink("/proc/self/path/a.out", &buf.front(), buf.size())) >= 0) {
if ((size = readlink("/proc/self/path/a.out", &buf.front(), buf.size())) >= 0)
{
exepath = std::string(&buf.front(), static_cast<size_t>(size)); exepath = std::string(&buf.front(), static_cast<size_t>(size));
} }
} }
if (exepath.empty()) if (exepath.empty()) {
{
Dl_info rInfo; Dl_info rInfo;
memset( &rInfo, 0, sizeof(rInfo) ); memset(&rInfo, 0, sizeof(rInfo));
if ( dladdr(cast_module_symbol(&default_search_paths), &rInfo) == 0 || rInfo.dli_fname == nullptr ) { if (dladdr(cast_module_symbol(&default_search_paths), &rInfo) == 0 || rInfo.dli_fname == nullptr) {
return paths; return paths;
} }
@ -131,13 +116,11 @@ std::vector<std::string> default_search_paths()
size_t lastslash = exepath.rfind('/'); size_t lastslash = exepath.rfind('/');
size_t secondtolastslash = exepath.rfind('/', lastslash - 1); size_t secondtolastslash = exepath.rfind('/', lastslash - 1);
if (lastslash != std::string::npos) if (lastslash != std::string::npos) {
{ paths.push_back(exepath.substr(0, lastslash + 1));
paths.push_back(exepath.substr(0, lastslash+1));
} }
if (secondtolastslash != std::string::npos) if (secondtolastslash != std::string::npos) {
{
paths.push_back(exepath.substr(0, secondtolastslash) + "/lib/chaiscript/"); paths.push_back(exepath.substr(0, secondtolastslash) + "/lib/chaiscript/");
} }
#endif #endif
@ -147,7 +130,7 @@ std::vector<std::string> default_search_paths()
} }
void help(int n) { void help(int n) {
if ( n >= 0 ) { if (n >= 0) {
std::cout << "ChaiScript evaluator. To evaluate an expression, type it and press <enter>.\n"; 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 << "Additionally, you can inspect the runtime system using:\n";
std::cout << " dump_system() - outputs all functions registered to the system\n"; std::cout << " dump_system() - outputs all functions registered to the system\n";
@ -164,8 +147,7 @@ void help(int n) {
} }
} }
std::string throws_exception(const std::function<void ()> &f) std::string throws_exception(const std::function<void()> &f) {
{
try { try {
f(); f();
} catch (const std::exception &e) { } catch (const std::exception &e) {
@ -175,8 +157,7 @@ std::string throws_exception(const std::function<void ()> &f)
return ""; return "";
} }
chaiscript::exception::eval_error get_eval_error(const std::function<void ()> &f) chaiscript::exception::eval_error get_eval_error(const std::function<void()> &f) {
{
try { try {
f(); f();
} catch (const chaiscript::exception::eval_error &e) { } catch (const chaiscript::exception::eval_error &e) {
@ -188,21 +169,19 @@ chaiscript::exception::eval_error get_eval_error(const std::function<void ()> &f
std::string get_next_command() { std::string get_next_command() {
std::string retval("quit"); std::string retval("quit");
if ( ! std::cin.eof() ) { if (!std::cin.eof()) {
char *input_raw = readline("eval> "); char *input_raw = readline("eval> ");
if ( input_raw != nullptr ) { if (input_raw != nullptr) {
add_history(input_raw); add_history(input_raw);
std::string val(input_raw); std::string val(input_raw);
size_t pos = val.find_first_not_of("\t \n"); size_t pos = val.find_first_not_of("\t \n");
if (pos != std::string::npos) if (pos != std::string::npos) {
{
val.erase(0, pos); val.erase(0, pos);
} }
pos = val.find_last_not_of("\t \n"); pos = val.find_last_not_of("\t \n");
if (pos != std::string::npos) if (pos != std::string::npos) {
{ val.erase(pos + 1, std::string::npos);
val.erase(pos+1, std::string::npos);
} }
retval = val; retval = val;
@ -210,11 +189,7 @@ std::string get_next_command() {
::free(input_raw); ::free(input_raw);
} }
} }
if( retval == "quit" if (retval == "quit" || retval == "exit" || retval == "help" || retval == "version") {
|| retval == "exit"
|| retval == "help"
|| retval == "version")
{
retval += "(0)"; retval += "(0)";
} }
return retval; return retval;
@ -226,8 +201,7 @@ void myexit(int return_val) {
exit(return_val); exit(return_val);
} }
void interactive(chaiscript::ChaiScript_Basic& chai) void interactive(chaiscript::ChaiScript_Basic &chai) {
{
using_history(); using_history();
for (;;) { for (;;) {
@ -236,39 +210,34 @@ void interactive(chaiscript::ChaiScript_Basic& chai)
// evaluate input // evaluate input
chaiscript::Boxed_Value val = chai.eval(input); chaiscript::Boxed_Value val = chai.eval(input);
//Then, we try to print the result of the evaluation to the user // Then, we try to print the result of the evaluation to the user
if (!val.get_type_info().bare_equal(chaiscript::user_type<void>())) { if (!val.get_type_info().bare_equal(chaiscript::user_type<void>())) {
try { 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) << '\n';
} catch (...) {
} // If we can't, do nothing
} }
catch (...) {} //If we can't, do nothing } catch (const chaiscript::exception::eval_error &ee) {
}
}
catch (const chaiscript::exception::eval_error &ee) {
std::cout << ee.what(); std::cout << ee.what();
if ( !ee.call_stack.empty() ) { if (!ee.call_stack.empty()) {
std::cout << "during evaluation at (" << ee.call_stack[0].start().line << ", " << ee.call_stack[0].start().column << ")"; std::cout << "during evaluation at (" << ee.call_stack[0].start().line << ", " << ee.call_stack[0].start().column << ")";
} }
std::cout << '\n'; std::cout << '\n';
} } catch (const std::exception &e) {
catch (const std::exception &e) {
std::cout << e.what(); std::cout << e.what();
std::cout << '\n'; std::cout << '\n';
} }
} }
} }
double now() double now() {
{
using namespace std::chrono; using namespace std::chrono;
auto now = high_resolution_clock::now(); auto now = high_resolution_clock::now();
return duration_cast<duration<double>>(now.time_since_epoch()).count(); return duration_cast<duration<double>>(now.time_since_epoch()).count();
} }
int main(int argc, char *argv[]) int main(int argc, char *argv[]) {
{ // Disable deprecation warning for getenv call.
// Disable deprecation warning for getenv call.
#ifdef CHAISCRIPT_MSVC #ifdef CHAISCRIPT_MSVC
#pragma warning(push) #pragma warning(push)
#pragma warning(disable : 4996) #pragma warning(disable : 4996)
@ -283,8 +252,7 @@ int main(int argc, char *argv[])
std::vector<std::string> usepaths; std::vector<std::string> usepaths;
usepaths.emplace_back(""); usepaths.emplace_back("");
if (usepath != nullptr) if (usepath != nullptr) {
{
usepaths.emplace_back(usepath); usepaths.emplace_back(usepath);
} }
@ -292,12 +260,11 @@ int main(int argc, char *argv[])
std::vector<std::string> searchpaths = default_search_paths(); std::vector<std::string> searchpaths = default_search_paths();
modulepaths.insert(modulepaths.end(), searchpaths.begin(), searchpaths.end()); modulepaths.insert(modulepaths.end(), searchpaths.begin(), searchpaths.end());
modulepaths.emplace_back(""); modulepaths.emplace_back("");
if (modulepath != nullptr) if (modulepath != nullptr) {
{
modulepaths.emplace_back(modulepath); modulepaths.emplace_back(modulepath);
} }
chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser(),modulepaths,usepaths); chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(), create_chaiscript_parser(), modulepaths, usepaths);
chai.add(chaiscript::fun(&myexit), "exit"); chai.add(chaiscript::fun(&myexit), "exit");
chai.add(chaiscript::fun(&myexit), "quit"); chai.add(chaiscript::fun(&myexit), "quit");
@ -311,46 +278,48 @@ int main(int argc, char *argv[])
bool any_exception_ok = false; bool any_exception_ok = false;
for (int i = 0; i < argc; ++i) { for (int i = 0; i < argc; ++i) {
if ( i == 0 && argc > 1 ) { if (i == 0 && argc > 1) {
++i; ++i;
} }
std::string arg( i != 0 ? argv[i] : "--interactive" ); std::string arg(i != 0 ? argv[i] : "--interactive");
enum { eInteractive enum {
, eCommand eInteractive,
, eFile eCommand,
} mode = eCommand ; eFile
} mode
= eCommand;
if ( arg == "-c" || arg == "--command" ) { if (arg == "-c" || arg == "--command") {
if ( (i+1) >= argc ) { if ((i + 1) >= argc) {
std::cout << "insufficient input following " << arg << '\n'; std::cout << "insufficient input following " << arg << '\n';
return EXIT_FAILURE; return EXIT_FAILURE;
} }
arg = argv[++i]; arg = argv[++i];
} else if ( arg == "-" || arg == "--stdin" ) { } else if (arg == "-" || arg == "--stdin") {
arg = "" ; arg = "";
std::string line; std::string line;
while ( std::getline(std::cin, line) ) { while (std::getline(std::cin, line)) {
arg += line + '\n' ; arg += line + '\n';
} }
} else if ( arg == "-v" || arg == "--version" ) { } else if (arg == "-v" || arg == "--version") {
arg = "print(version())" ; arg = "print(version())";
} else if ( arg == "-h" || arg == "--help" ) { } else if (arg == "-h" || arg == "--help") {
arg = "help(-1)"; arg = "help(-1)";
} else if ( arg == "-e" || arg == "--evalerrorok" ) { } else if (arg == "-e" || arg == "--evalerrorok") {
eval_error_ok = true; eval_error_ok = true;
continue; continue;
} else if ( arg == "--exception" ) { } else if (arg == "--exception") {
boxed_exception_ok = true; boxed_exception_ok = true;
continue; continue;
} else if ( arg == "--any-exception" ) { } else if (arg == "--any-exception") {
any_exception_ok = true; any_exception_ok = true;
continue; continue;
} else if ( arg == "-i" || arg == "--interactive" ) { } else if (arg == "-i" || arg == "--interactive") {
mode = eInteractive ; mode = eInteractive;
} else if ( arg.find('-') == 0 ) { } else if (arg.find('-') == 0) {
std::cout << "unrecognised argument " << arg << '\n'; std::cout << "unrecognised argument " << arg << '\n';
return EXIT_FAILURE; return EXIT_FAILURE;
} else { } else {
@ -358,7 +327,7 @@ int main(int argc, char *argv[])
} }
try { try {
switch ( mode ) { switch (mode) {
case eInteractive: case eInteractive:
interactive(chai); interactive(chai);
break; break;
@ -368,32 +337,28 @@ int main(int argc, char *argv[])
case eFile: case eFile:
chai.eval_file(arg); chai.eval_file(arg);
} }
} } catch (const chaiscript::exception::eval_error &ee) {
catch (const chaiscript::exception::eval_error &ee) {
std::cout << ee.pretty_print(); std::cout << ee.pretty_print();
std::cout << '\n'; std::cout << '\n';
if (!eval_error_ok) { if (!eval_error_ok) {
return EXIT_FAILURE; return EXIT_FAILURE;
} }
} } catch (const chaiscript::Boxed_Value &e) {
catch (const chaiscript::Boxed_Value &e) {
std::cout << "Unhandled exception thrown of type " << e.get_type_info().name() << '\n'; std::cout << "Unhandled exception thrown of type " << e.get_type_info().name() << '\n';
if (!boxed_exception_ok) { if (!boxed_exception_ok) {
return EXIT_FAILURE; return EXIT_FAILURE;
} }
} } catch (const chaiscript::exception::load_module_error &e) {
catch (const chaiscript::exception::load_module_error &e) { std::cout << "Unhandled module load error\n"
std::cout << "Unhandled module load error\n" << e.what() << '\n'; << e.what() << '\n';
} } catch (std::exception &e) {
catch (std::exception &e) {
std::cout << "Unhandled standard exception: " << e.what() << '\n'; std::cout << "Unhandled standard exception: " << e.what() << '\n';
if (!any_exception_ok) { if (!any_exception_ok) {
throw; throw;
} }
} } catch (...) {
catch (...) {
std::cout << "Unhandled unknown exception" << '\n'; std::cout << "Unhandled unknown exception" << '\n';
if (!any_exception_ok) { if (!any_exception_ok) {
throw; throw;

View File

@ -4,67 +4,52 @@
// and Jason Turner (jason@emptycrate.com) // and Jason Turner (jason@emptycrate.com)
// http://www.chaiscript.com // http://www.chaiscript.com
// NOT TO BE USED AS A SOURCE OF BEST PRACTICES // NOT TO BE USED AS A SOURCE OF BEST PRACTICES
// FOR CHAISCRIPT // FOR CHAISCRIPT
#include <iostream>
#include <ctime> #include <ctime>
#include <iostream>
#include <chaiscript/chaiscript.hpp> #include <chaiscript/chaiscript.hpp>
#include <chaiscript/dispatchkit/bootstrap_stl.hpp> #include <chaiscript/dispatchkit/bootstrap_stl.hpp>
#include <chaiscript/dispatchkit/function_call.hpp> #include <chaiscript/dispatchkit/function_call.hpp>
void log(const std::string &msg) void log(const std::string &msg) {
{
std::cout << "[" << time(nullptr) << "] " << msg << '\n'; std::cout << "[" << time(nullptr) << "] " << msg << '\n';
} }
void log(const std::string &module, const std::string &msg) void log(const std::string &module, const std::string &msg) {
{
std::cout << "[" << time(nullptr) << "] <" << module << "> " << msg << '\n'; std::cout << "[" << time(nullptr) << "] <" << module << "> " << msg << '\n';
} }
void bound_log(const std::string &msg) void bound_log(const std::string &msg) {
{
log(msg); log(msg);
} }
void hello_world(const chaiscript::Boxed_Value & /*o*/) void hello_world(const chaiscript::Boxed_Value & /*o*/) {
{
std::cout << "Hello World\n"; std::cout << "Hello World\n";
} }
void hello_constructor(const chaiscript::Boxed_Value & /*o*/) void hello_constructor(const chaiscript::Boxed_Value & /*o*/) {
{
std::cout << "Hello Constructor\n"; std::cout << "Hello Constructor\n";
} }
struct System {
std::map<std::string, std::function<std::string(const std::string &)>> m_callbacks;
struct System void add_callback(const std::string &t_name, const std::function<std::string(const std::string &)> &t_func) {
{
std::map<std::string, std::function<std::string (const std::string &) > > m_callbacks;
void add_callback(const std::string &t_name,
const std::function<std::string (const std::string &)> &t_func)
{
m_callbacks[t_name] = t_func; m_callbacks[t_name] = t_func;
} }
void do_callbacks(const std::string &inp) {
void do_callbacks(const std::string &inp)
{
log("Running Callbacks: " + inp); log("Running Callbacks: " + inp);
for (auto & m_callback : m_callbacks) for (auto &m_callback : m_callbacks) {
{
log("Callback: " + m_callback.first, m_callback.second(inp)); log("Callback: " + m_callback.first, m_callback.second(inp));
} }
} }
}; };
void take_shared_ptr(const std::shared_ptr<const std::string> &p) void take_shared_ptr(const std::shared_ptr<const std::string> &p) {
{
std::cout << *p << '\n'; std::cout << *p << '\n';
} }
@ -73,15 +58,14 @@ int main(int /*argc*/, char * /*argv*/[]) {
ChaiScript chai; ChaiScript chai;
// Create a new system object and share it with the chaiscript engine
//Create a new system object and share it with the chaiscript engine
System system; System system;
chai.add_global(var(&system), "system"); chai.add_global(var(&system), "system");
//Add a bound callback method // Add a bound callback method
chai.add(fun(&System::add_callback, std::ref(system)), "add_callback_bound"); chai.add(fun(&System::add_callback, std::ref(system)), "add_callback_bound");
//Register the two methods of the System structure. // Register the two methods of the System structure.
chai.add(fun(&System::add_callback), "add_callback"); chai.add(fun(&System::add_callback), "add_callback");
chai.add(fun(&System::do_callbacks), "do_callbacks"); chai.add(fun(&System::do_callbacks), "do_callbacks");
@ -111,29 +95,26 @@ int main(int /*argc*/, char * /*argv*/[]) {
// A shortcut to using eval is just to use the chai operator() // A shortcut to using eval is just to use the chai operator()
chai(R"(log("Test Module", "Test Message");)"); chai(R"(log("Test Module", "Test Message");)");
//Finally, it is possible to register a lambda as a system function, in this // Finally, it is possible to register a lambda as a system function, in this
//way, we can, for instance add a bound member function to the system // way, we can, for instance add a bound member function to the system
chai.add(fun([&system](){ return system.do_callbacks("Bound Test"); }), "do_callbacks"); chai.add(fun([&system]() { return system.do_callbacks("Bound Test"); }), "do_callbacks");
//Call bound version of do_callbacks // Call bound version of do_callbacks
chai("do_callbacks()"); chai("do_callbacks()");
std::function<void ()> caller = chai.eval<std::function<void ()> >( std::function<void()> caller = chai.eval<std::function<void()>>(R"(fun() { system.do_callbacks("From Functor"); })");
R"(fun() { system.do_callbacks("From Functor"); })"
);
caller(); caller();
// If we would like a type-safe return value from all call, we can use
//If we would like a type-safe return value from all call, we can use // the templated version of eval:
//the templated version of eval:
int i = chai.eval<int>("5+5"); int i = chai.eval<int>("5+5");
std::cout << "5+5: " << i << '\n'; std::cout << "5+5: " << i << '\n';
//Add a new variable // Add a new variable
chai("var scripti = 15"); chai("var scripti = 15");
//We can even get a handle to the variables in the system // We can even get a handle to the variables in the system
int &scripti = chai.eval<int &>("scripti"); int &scripti = chai.eval<int &>("scripti");
std::cout << "scripti: " << scripti << '\n'; std::cout << "scripti: " << scripti << '\n';
@ -141,10 +122,10 @@ int main(int /*argc*/, char * /*argv*/[]) {
std::cout << "scripti (updated): " << scripti << '\n'; std::cout << "scripti (updated): " << scripti << '\n';
chai(R"(print("Scripti from chai: " + to_string(scripti)))"); chai(R"(print("Scripti from chai: " + to_string(scripti)))");
//To do: Add examples of handling Boxed_Values directly when needed // To do: Add examples of handling Boxed_Values directly when needed
//Creating a functor on the stack and using it immediately // Creating a functor on the stack and using it immediately
int x = chai.eval<std::function<int (int, int)> >("fun (x, y) { return x + y; }")(5, 6); int x = chai.eval<std::function<int(int, int)>>("fun (x, y) { return x + y; }")(5, 6);
std::stringstream ss; std::stringstream ss;
ss << x; ss << x;
@ -158,25 +139,23 @@ int main(int /*argc*/, char * /*argv*/[]) {
chai("def getvar() { return constvar; }"); chai("def getvar() { return constvar; }");
chai("print( getvar() )"); chai("print( getvar() )");
// Ability to create our own container types when needed. std::vector and std::map are
//Ability to create our own container types when needed. std::vector and std::map are // mostly supported currently
//mostly supported currently // chai.add(bootstrap::standard_library::vector_type<std::vector<int> >("IntVector"));
//chai.add(bootstrap::standard_library::vector_type<std::vector<int> >("IntVector"));
// Test ability to register a function that excepts a shared_ptr version of a type // Test ability to register a function that excepts a shared_ptr version of a type
chai(R"(take_shared_ptr("Hello World as a shared_ptr");)"); chai(R"(take_shared_ptr("Hello World as a shared_ptr");)");
chai.add(fun(&bound_log, std::string("Msg")), "BoundFun"); chai.add(fun(&bound_log, std::string("Msg")), "BoundFun");
//Dynamic objects test // Dynamic objects test
chai.add(chaiscript::Proxy_Function(new dispatch::detail::Dynamic_Object_Function("TestType", fun(&hello_world))), "hello_world"); chai.add(chaiscript::Proxy_Function(new dispatch::detail::Dynamic_Object_Function("TestType", fun(&hello_world))), "hello_world");
chai.add(chaiscript::Proxy_Function(new dispatch::detail::Dynamic_Object_Constructor("TestType", fun(&hello_constructor))), "TestType"); chai.add(chaiscript::Proxy_Function(new dispatch::detail::Dynamic_Object_Constructor("TestType", fun(&hello_constructor))), "TestType");
// chai.add(fun(std::function<Boxed_Value (dispatch::Dynamic_Object &)>(std::bind(&dispatch::detail::Dynamic_Object_Attribute::func, "TestType", "attr", std::placeholders::_1))), "attr"); // chai.add(fun(std::function<Boxed_Value (dispatch::Dynamic_Object &)>(std::bind(&dispatch::detail::Dynamic_Object_Attribute::func,
// "TestType", "attr", std::placeholders::_1))), "attr");
chai.eval("var x = TestType()"); chai.eval("var x = TestType()");
// chai.eval("x.attr = \"hi\""); // chai.eval("x.attr = \"hi\"");
// chai.eval("print(x.attr)"); // chai.eval("print(x.attr)");
chai.eval("x.hello_world()"); chai.eval("x.hello_world()");
} }

View File

@ -11,19 +11,15 @@
#include <endian.h> #include <endian.h>
#endif #endif
/// same as reset() /// same as reset()
SHA3::SHA3(Bits bits) SHA3::SHA3(Bits bits)
: m_blockSize(200 - 2 * (bits / 8)), : m_blockSize(200 - 2 * (bits / 8))
m_bits(bits) , m_bits(bits) {
{
reset(); reset();
} }
/// restart /// restart
void SHA3::reset() void SHA3::reset() {
{
for (size_t i = 0; i < StateSize; i++) for (size_t i = 0; i < StateSize; i++)
m_hash[i] = 0; m_hash[i] = 0;
@ -31,32 +27,19 @@ void SHA3::reset()
m_bufferSize = 0; m_bufferSize = 0;
} }
/// constants and local helper functions /// constants and local helper functions
namespace namespace {
{
const unsigned int Rounds = 24; const unsigned int Rounds = 24;
const uint64_t XorMasks[Rounds] = const uint64_t XorMasks[Rounds]
{ = {0x0000000000000001ULL, 0x0000000000008082ULL, 0x800000000000808aULL, 0x8000000080008000ULL, 0x000000000000808bULL, 0x0000000080000001ULL, 0x8000000080008081ULL, 0x8000000000008009ULL, 0x000000000000008aULL, 0x0000000000000088ULL, 0x0000000080008009ULL, 0x000000008000000aULL, 0x000000008000808bULL, 0x800000000000008bULL, 0x8000000000008089ULL, 0x8000000000008003ULL, 0x8000000000008002ULL, 0x8000000000000080ULL, 0x000000000000800aULL, 0x800000008000000aULL, 0x8000000080008081ULL, 0x8000000000008080ULL, 0x0000000080000001ULL, 0x8000000080008008ULL};
0x0000000000000001ULL, 0x0000000000008082ULL, 0x800000000000808aULL,
0x8000000080008000ULL, 0x000000000000808bULL, 0x0000000080000001ULL,
0x8000000080008081ULL, 0x8000000000008009ULL, 0x000000000000008aULL,
0x0000000000000088ULL, 0x0000000080008009ULL, 0x000000008000000aULL,
0x000000008000808bULL, 0x800000000000008bULL, 0x8000000000008089ULL,
0x8000000000008003ULL, 0x8000000000008002ULL, 0x8000000000000080ULL,
0x000000000000800aULL, 0x800000008000000aULL, 0x8000000080008081ULL,
0x8000000000008080ULL, 0x0000000080000001ULL, 0x8000000080008008ULL
};
/// rotate left and wrap around to the right /// rotate left and wrap around to the right
inline uint64_t rotateLeft(uint64_t x, uint8_t numBits) inline uint64_t rotateLeft(uint64_t x, uint8_t numBits) {
{
return (x << numBits) | (x >> (64 - numBits)); return (x << numBits) | (x >> (64 - numBits));
} }
/// convert litte vs big endian /// convert litte vs big endian
inline uint64_t swap(uint64_t x) inline uint64_t swap(uint64_t x) {
{
#if defined(__GNUC__) || defined(__clang__) #if defined(__GNUC__) || defined(__clang__)
return __builtin_bswap64(x); return __builtin_bswap64(x);
#endif #endif
@ -64,54 +47,42 @@ namespace
return _byteswap_uint64(x); return _byteswap_uint64(x);
#endif #endif
return (x >> 56) | return (x >> 56) | ((x >> 40) & 0x000000000000FF00ULL) | ((x >> 24) & 0x0000000000FF0000ULL) | ((x >> 8) & 0x00000000FF000000ULL)
((x >> 40) & 0x000000000000FF00ULL) | | ((x << 8) & 0x000000FF00000000ULL) | ((x << 24) & 0x0000FF0000000000ULL) | ((x << 40) & 0x00FF000000000000ULL) | (x << 56);
((x >> 24) & 0x0000000000FF0000ULL) |
((x >> 8) & 0x00000000FF000000ULL) |
((x << 8) & 0x000000FF00000000ULL) |
((x << 24) & 0x0000FF0000000000ULL) |
((x << 40) & 0x00FF000000000000ULL) |
(x << 56);
} }
/// return x % 5 for 0 <= x <= 9 /// return x % 5 for 0 <= x <= 9
unsigned int mod5(unsigned int x) unsigned int mod5(unsigned int x) {
{
if (x < 5) if (x < 5)
return x; return x;
return x - 5; return x - 5;
} }
} } // namespace
/// process a full block /// process a full block
void SHA3::processBlock(const void* data) void SHA3::processBlock(const void *data) {
{
#if defined(__BYTE_ORDER) && (__BYTE_ORDER != 0) && (__BYTE_ORDER == __BIG_ENDIAN) #if defined(__BYTE_ORDER) && (__BYTE_ORDER != 0) && (__BYTE_ORDER == __BIG_ENDIAN)
#define LITTLEENDIAN(x) swap(x) #define LITTLEENDIAN(x) swap(x)
#else #else
#define LITTLEENDIAN(x) (x) #define LITTLEENDIAN(x) (x)
#endif #endif
const uint64_t* data64 = (const uint64_t*) data; const uint64_t *data64 = (const uint64_t *)data;
// mix data into state // mix data into state
for (unsigned int i = 0; i < m_blockSize / 8; i++) for (unsigned int i = 0; i < m_blockSize / 8; i++)
m_hash[i] ^= LITTLEENDIAN(data64[i]); m_hash[i] ^= LITTLEENDIAN(data64[i]);
// re-compute state // re-compute state
for (unsigned int round = 0; round < Rounds; round++) for (unsigned int round = 0; round < Rounds; round++) {
{
// Theta // Theta
uint64_t coefficients[5]; uint64_t coefficients[5];
for (unsigned int i = 0; i < 5; i++) for (unsigned int i = 0; i < 5; i++)
coefficients[i] = m_hash[i] ^ m_hash[i + 5] ^ m_hash[i + 10] ^ m_hash[i + 15] ^ m_hash[i + 20]; coefficients[i] = m_hash[i] ^ m_hash[i + 5] ^ m_hash[i + 10] ^ m_hash[i + 15] ^ m_hash[i + 20];
for (unsigned int i = 0; i < 5; i++) for (unsigned int i = 0; i < 5; i++) {
{
uint64_t one = coefficients[mod5(i + 4)] ^ rotateLeft(coefficients[mod5(i + 1)], 1); uint64_t one = coefficients[mod5(i + 4)] ^ rotateLeft(coefficients[mod5(i + 1)], 1);
m_hash[i ] ^= one; m_hash[i] ^= one;
m_hash[i + 5] ^= one; m_hash[i + 5] ^= one;
m_hash[i + 10] ^= one; m_hash[i + 10] ^= one;
m_hash[i + 15] ^= one; m_hash[i + 15] ^= one;
@ -123,34 +94,79 @@ void SHA3::processBlock(const void* data)
// Rho Pi // Rho Pi
uint64_t last = m_hash[1]; uint64_t last = m_hash[1];
one = m_hash[10]; m_hash[10] = rotateLeft(last, 1); last = one; one = m_hash[10];
one = m_hash[ 7]; m_hash[ 7] = rotateLeft(last, 3); last = one; m_hash[10] = rotateLeft(last, 1);
one = m_hash[11]; m_hash[11] = rotateLeft(last, 6); last = one; last = one;
one = m_hash[17]; m_hash[17] = rotateLeft(last, 10); last = one; one = m_hash[7];
one = m_hash[18]; m_hash[18] = rotateLeft(last, 15); last = one; m_hash[7] = rotateLeft(last, 3);
one = m_hash[ 3]; m_hash[ 3] = rotateLeft(last, 21); last = one; last = one;
one = m_hash[ 5]; m_hash[ 5] = rotateLeft(last, 28); last = one; one = m_hash[11];
one = m_hash[16]; m_hash[16] = rotateLeft(last, 36); last = one; m_hash[11] = rotateLeft(last, 6);
one = m_hash[ 8]; m_hash[ 8] = rotateLeft(last, 45); last = one; last = one;
one = m_hash[21]; m_hash[21] = rotateLeft(last, 55); last = one; one = m_hash[17];
one = m_hash[24]; m_hash[24] = rotateLeft(last, 2); last = one; m_hash[17] = rotateLeft(last, 10);
one = m_hash[ 4]; m_hash[ 4] = rotateLeft(last, 14); last = one; last = one;
one = m_hash[15]; m_hash[15] = rotateLeft(last, 27); last = one; one = m_hash[18];
one = m_hash[23]; m_hash[23] = rotateLeft(last, 41); last = one; m_hash[18] = rotateLeft(last, 15);
one = m_hash[19]; m_hash[19] = rotateLeft(last, 56); last = one; last = one;
one = m_hash[13]; m_hash[13] = rotateLeft(last, 8); last = one; one = m_hash[3];
one = m_hash[12]; m_hash[12] = rotateLeft(last, 25); last = one; m_hash[3] = rotateLeft(last, 21);
one = m_hash[ 2]; m_hash[ 2] = rotateLeft(last, 43); last = one; last = one;
one = m_hash[20]; m_hash[20] = rotateLeft(last, 62); last = one; one = m_hash[5];
one = m_hash[14]; m_hash[14] = rotateLeft(last, 18); last = one; m_hash[5] = rotateLeft(last, 28);
one = m_hash[22]; m_hash[22] = rotateLeft(last, 39); last = one; last = one;
one = m_hash[ 9]; m_hash[ 9] = rotateLeft(last, 61); last = one; one = m_hash[16];
one = m_hash[ 6]; m_hash[ 6] = rotateLeft(last, 20); last = one; m_hash[16] = rotateLeft(last, 36);
m_hash[ 1] = rotateLeft(last, 44); last = one;
one = m_hash[8];
m_hash[8] = rotateLeft(last, 45);
last = one;
one = m_hash[21];
m_hash[21] = rotateLeft(last, 55);
last = one;
one = m_hash[24];
m_hash[24] = rotateLeft(last, 2);
last = one;
one = m_hash[4];
m_hash[4] = rotateLeft(last, 14);
last = one;
one = m_hash[15];
m_hash[15] = rotateLeft(last, 27);
last = one;
one = m_hash[23];
m_hash[23] = rotateLeft(last, 41);
last = one;
one = m_hash[19];
m_hash[19] = rotateLeft(last, 56);
last = one;
one = m_hash[13];
m_hash[13] = rotateLeft(last, 8);
last = one;
one = m_hash[12];
m_hash[12] = rotateLeft(last, 25);
last = one;
one = m_hash[2];
m_hash[2] = rotateLeft(last, 43);
last = one;
one = m_hash[20];
m_hash[20] = rotateLeft(last, 62);
last = one;
one = m_hash[14];
m_hash[14] = rotateLeft(last, 18);
last = one;
one = m_hash[22];
m_hash[22] = rotateLeft(last, 39);
last = one;
one = m_hash[9];
m_hash[9] = rotateLeft(last, 61);
last = one;
one = m_hash[6];
m_hash[6] = rotateLeft(last, 20);
last = one;
m_hash[1] = rotateLeft(last, 44);
// Chi // Chi
for (unsigned int j = 0; j < 25; j += 5) for (unsigned int j = 0; j < 25; j += 5) {
{
// temporaries // temporaries
uint64_t one = m_hash[j]; uint64_t one = m_hash[j];
uint64_t two = m_hash[j + 1]; uint64_t two = m_hash[j + 1];
@ -167,26 +183,21 @@ void SHA3::processBlock(const void* data)
} }
} }
/// add arbitrary number of bytes /// add arbitrary number of bytes
void SHA3::add(const void* data, size_t numBytes) void SHA3::add(const void *data, size_t numBytes) {
{ const uint8_t *current = (const uint8_t *)data;
const uint8_t* current = (const uint8_t*) data;
// copy data to buffer // copy data to buffer
if (m_bufferSize > 0) if (m_bufferSize > 0) {
{ while (numBytes > 0 && m_bufferSize < m_blockSize) {
while (numBytes > 0 && m_bufferSize < m_blockSize)
{
m_buffer[m_bufferSize++] = *current++; m_buffer[m_bufferSize++] = *current++;
numBytes--; numBytes--;
} }
} }
// full buffer // full buffer
if (m_bufferSize == m_blockSize) if (m_bufferSize == m_blockSize) {
{ processBlock((void *)m_buffer);
processBlock((void*)m_buffer);
m_numBytes += m_blockSize; m_numBytes += m_blockSize;
m_bufferSize = 0; m_bufferSize = 0;
} }
@ -196,8 +207,7 @@ void SHA3::add(const void* data, size_t numBytes)
return; return;
// process full blocks // process full blocks
while (numBytes >= m_blockSize) while (numBytes >= m_blockSize) {
{
processBlock(current); processBlock(current);
current += m_blockSize; current += m_blockSize;
m_numBytes += m_blockSize; m_numBytes += m_blockSize;
@ -205,17 +215,14 @@ void SHA3::add(const void* data, size_t numBytes)
} }
// keep remaining bytes in buffer // keep remaining bytes in buffer
while (numBytes > 0) while (numBytes > 0) {
{
m_buffer[m_bufferSize++] = *current++; m_buffer[m_bufferSize++] = *current++;
numBytes--; numBytes--;
} }
} }
/// process everything left in the internal buffer /// process everything left in the internal buffer
void SHA3::processBuffer() void SHA3::processBuffer() {
{
// add padding // add padding
size_t offset = m_bufferSize; size_t offset = m_bufferSize;
// add a "1" byte // add a "1" byte
@ -230,10 +237,8 @@ void SHA3::processBuffer()
processBlock(m_buffer); processBlock(m_buffer);
} }
/// return latest hash as 16 hex characters /// return latest hash as 16 hex characters
std::string SHA3::getHash() std::string SHA3::getHash() {
{
// process remaining bytes // process remaining bytes
processBuffer(); processBuffer();
@ -249,7 +254,7 @@ std::string SHA3::getHash()
for (unsigned int j = 0; j < 8; j++) // 64 bits => 8 bytes for (unsigned int j = 0; j < 8; j++) // 64 bits => 8 bytes
{ {
// convert a byte to hex // convert a byte to hex
unsigned char oneByte = (unsigned char) (m_hash[i] >> (8 * j)); unsigned char oneByte = (unsigned char)(m_hash[i] >> (8 * j));
result += dec2hex[oneByte >> 4]; result += dec2hex[oneByte >> 4];
result += dec2hex[oneByte & 15]; result += dec2hex[oneByte & 15];
} }
@ -257,10 +262,9 @@ std::string SHA3::getHash()
// SHA3-224's last entry in m_hash provides only 32 bits instead of 64 bits // SHA3-224's last entry in m_hash provides only 32 bits instead of 64 bits
unsigned int remainder = m_bits - hashLength * 64; unsigned int remainder = m_bits - hashLength * 64;
unsigned int processed = 0; unsigned int processed = 0;
while (processed < remainder) while (processed < remainder) {
{
// convert a byte to hex // convert a byte to hex
unsigned char oneByte = (unsigned char) (m_hash[hashLength] >> processed); unsigned char oneByte = (unsigned char)(m_hash[hashLength] >> processed);
result += dec2hex[oneByte >> 4]; result += dec2hex[oneByte >> 4];
result += dec2hex[oneByte & 15]; result += dec2hex[oneByte & 15];
@ -270,19 +274,15 @@ std::string SHA3::getHash()
return result; return result;
} }
/// compute SHA3 of a memory block /// compute SHA3 of a memory block
std::string SHA3::operator()(const void* data, size_t numBytes) std::string SHA3::operator()(const void *data, size_t numBytes) {
{
reset(); reset();
add(data, numBytes); add(data, numBytes);
return getHash(); return getHash();
} }
/// compute SHA3 of a string, excluding final zero /// compute SHA3 of a string, excluding final zero
std::string SHA3::operator()(const std::string& text) std::string SHA3::operator()(const std::string &text) {
{
reset(); reset();
add(text.c_str(), text.size()); add(text.c_str(), text.size());
return getHash(); return getHash();

View File

@ -7,7 +7,6 @@
// This is an open source non-commercial project. Dear PVS-Studio, please check it. // This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com // PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#include <chaiscript/chaiscript_basic.hpp> #include <chaiscript/chaiscript_basic.hpp>
#include <chaiscript/dispatchkit/bootstrap_stl.hpp> #include <chaiscript/dispatchkit/bootstrap_stl.hpp>
#include <list> #include <list>
@ -25,11 +24,10 @@
#pragma clang diagnostic ignored "-Wreturn-type-c-linkage" #pragma clang diagnostic ignored "-Wreturn-type-c-linkage"
#endif #endif
CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_stl_extra() CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_stl_extra() {
{
auto module = std::make_shared<chaiscript::Module>(); auto module = std::make_shared<chaiscript::Module>();
chaiscript::bootstrap::standard_library::list_type<std::list<chaiscript::Boxed_Value> >("List", *module); chaiscript::bootstrap::standard_library::list_type<std::list<chaiscript::Boxed_Value>>("List", *module);
chaiscript::bootstrap::standard_library::vector_type<std::vector<uint16_t> >("u16vector", *module); chaiscript::bootstrap::standard_library::vector_type<std::vector<uint16_t>>("u16vector", *module);
module->add(chaiscript::vector_conversion<std::vector<uint16_t>>()); module->add(chaiscript::vector_conversion<std::vector<uint16_t>>());
return module; return module;
} }

View File

@ -3,28 +3,38 @@
#include <chaiscript/dispatchkit/bootstrap.hpp> #include <chaiscript/dispatchkit/bootstrap.hpp>
#include <string> #include <string>
class TestBaseType {
public:
class TestBaseType TestBaseType()
{ : val(10)
public: , const_val(15)
TestBaseType() : val(10), const_val(15), mdarray{} { } , mdarray{} {
TestBaseType(int) : val(10), const_val(15), mdarray{} { } }
TestBaseType(int *) : val(10), const_val(15), mdarray{} { } TestBaseType(int)
: val(10)
, const_val(15)
, mdarray{} {
}
TestBaseType(int *)
: val(10)
, const_val(15)
, mdarray{} {
}
TestBaseType(const TestBaseType &other) TestBaseType(const TestBaseType &other)
: val(other.val), const_val(other.const_val), const_val_ptr(&const_val), : val(other.val)
func_member(other.func_member) , const_val(other.const_val)
{ , const_val_ptr(&const_val)
, func_member(other.func_member) {
} }
TestBaseType(TestBaseType &&other) TestBaseType(TestBaseType &&other)
: val(other.val), const_val(other.const_val), const_val_ptr(&const_val), : val(other.val)
func_member(std::move(other.func_member)) , const_val(other.const_val)
{ , const_val_ptr(&const_val)
, func_member(std::move(other.func_member)) {
} }
TestBaseType &operator=(TestBaseType &&) = delete; TestBaseType &operator=(TestBaseType &&) = delete;
TestBaseType &operator=(const TestBaseType &) = delete; TestBaseType &operator=(const TestBaseType &) = delete;
@ -39,102 +49,75 @@ class TestBaseType
const int const_val; const int const_val;
const int *const_val_ptr = &const_val; const int *const_val_ptr = &const_val;
const int *get_const_val_ptr() { const int *get_const_val_ptr() { return const_val_ptr; }
return const_val_ptr;
}
int mdarray[2][3][5]; int mdarray[2][3][5];
std::function<int (int)> func_member; std::function<int(int)> func_member;
void set_string_val(std::string &t_str)
{
t_str = "42";
}
void set_string_val(std::string &t_str) { t_str = "42"; }
}; };
class Type2 class Type2 {
{ public:
public:
Type2(TestBaseType t_bt) Type2(TestBaseType t_bt)
: m_bt(std::move(t_bt)), : m_bt(std::move(t_bt))
m_str("Hello World") , m_str("Hello World") {
{
} }
int get_val() const int get_val() const { return m_bt.val; }
{
return m_bt.val;
}
const char *get_str() const { return m_str.c_str(); }
const char *get_str() const private:
{
return m_str.c_str();
}
private:
TestBaseType m_bt; TestBaseType m_bt;
std::string m_str; std::string m_str;
}; };
enum TestEnum enum TestEnum {
{
TestValue1 = 1 TestValue1 = 1
}; };
int to_int(TestEnum t) int to_int(TestEnum t) {
{
return t; return t;
} }
class TestDerivedType : public TestBaseType class TestDerivedType : public TestBaseType {
{ public:
public:
int func() override { return 1; } int func() override { return 1; }
int derived_only_func() { return 19; } int derived_only_func() { return 19; }
}; };
class TestMoreDerivedType : public TestDerivedType class TestMoreDerivedType : public TestDerivedType {
{ public:
public:
}; };
std::shared_ptr<TestBaseType> derived_type_factory() std::shared_ptr<TestBaseType> derived_type_factory() {
{
return std::make_shared<TestDerivedType>(); return std::make_shared<TestDerivedType>();
} }
std::shared_ptr<TestBaseType> more_derived_type_factory() std::shared_ptr<TestBaseType> more_derived_type_factory() {
{
return std::make_shared<TestMoreDerivedType>(); return std::make_shared<TestMoreDerivedType>();
} }
std::shared_ptr<TestBaseType> null_factory() std::shared_ptr<TestBaseType> null_factory() {
{
return std::shared_ptr<TestBaseType>(); return std::shared_ptr<TestBaseType>();
} }
void update_shared_ptr(std::shared_ptr<TestBaseType> &ptr) void update_shared_ptr(std::shared_ptr<TestBaseType> &ptr) {
{
ptr = std::make_shared<TestDerivedType>(); ptr = std::make_shared<TestDerivedType>();
} }
void nullify_shared_ptr(std::shared_ptr<TestBaseType> &ptr) void nullify_shared_ptr(std::shared_ptr<TestBaseType> &ptr) {
{
ptr = nullptr; ptr = nullptr;
} }
std::string hello_world() std::string hello_world() {
{
return "Hello World"; return "Hello World";
} }
static int global_i = 1; static int global_i = 1;
int *get_new_int() int *get_new_int() {
{
return &global_i; return &global_i;
} }
@ -150,8 +133,7 @@ int *get_new_int()
#pragma clang diagnostic ignored "-Wreturn-type-c-linkage" #pragma clang diagnostic ignored "-Wreturn-type-c-linkage"
#endif #endif
CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_test_module() CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_test_module() {
{
chaiscript::ModulePtr m(new chaiscript::Module()); chaiscript::ModulePtr m(new chaiscript::Module());
m->add(chaiscript::fun(hello_world), "hello_world"); m->add(chaiscript::fun(hello_world), "hello_world");
@ -161,16 +143,16 @@ CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_test_mo
m->add(chaiscript::user_type<TestMoreDerivedType>(), "TestMoreDerivedType"); m->add(chaiscript::user_type<TestMoreDerivedType>(), "TestMoreDerivedType");
m->add(chaiscript::user_type<Type2>(), "Type2"); m->add(chaiscript::user_type<Type2>(), "Type2");
m->add(chaiscript::constructor<TestBaseType ()>(), "TestBaseType"); m->add(chaiscript::constructor<TestBaseType()>(), "TestBaseType");
// m->add(chaiscript::constructor<TestBaseType (int)>(), "TestBaseType"); // m->add(chaiscript::constructor<TestBaseType (int)>(), "TestBaseType");
m->add(chaiscript::constructor<TestBaseType (const TestBaseType &)>(), "TestBaseType"); m->add(chaiscript::constructor<TestBaseType(const TestBaseType &)>(), "TestBaseType");
m->add(chaiscript::constructor<TestBaseType (int *)>(), "TestBaseType"); m->add(chaiscript::constructor<TestBaseType(int *)>(), "TestBaseType");
m->add(chaiscript::constructor<TestDerivedType ()>(), "TestDerivedType"); m->add(chaiscript::constructor<TestDerivedType()>(), "TestDerivedType");
m->add(chaiscript::constructor<TestDerivedType (const TestDerivedType &)>(), "TestDerivedType"); m->add(chaiscript::constructor<TestDerivedType(const TestDerivedType &)>(), "TestDerivedType");
m->add(chaiscript::constructor<TestMoreDerivedType ()>(), "TestMoreDerivedType"); m->add(chaiscript::constructor<TestMoreDerivedType()>(), "TestMoreDerivedType");
m->add(chaiscript::constructor<TestMoreDerivedType (const TestMoreDerivedType &)>(), "TestMoreDerivedType"); m->add(chaiscript::constructor<TestMoreDerivedType(const TestMoreDerivedType &)>(), "TestMoreDerivedType");
/// \todo automatic chaining of base classes? /// \todo automatic chaining of base classes?
m->add(chaiscript::base_class<TestBaseType, TestDerivedType>()); m->add(chaiscript::base_class<TestBaseType, TestDerivedType>());
@ -202,7 +184,6 @@ CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_test_mo
m->add(chaiscript::fun(&TestBaseType::func_member), "func_member"); m->add(chaiscript::fun(&TestBaseType::func_member), "func_member");
m->add(chaiscript::fun(&get_new_int), "get_new_int"); m->add(chaiscript::fun(&get_new_int), "get_new_int");
m->add_global_const(chaiscript::const_var(TestValue1), "TestValue1"); m->add_global_const(chaiscript::const_var(TestValue1), "TestValue1");
m->add(chaiscript::user_type<TestEnum>(), "TestEnum"); m->add(chaiscript::user_type<TestEnum>(), "TestEnum");
@ -215,16 +196,14 @@ CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_test_mo
m->add(chaiscript::fun(&Type2::get_val), "get_val"); m->add(chaiscript::fun(&Type2::get_val), "get_val");
m->add(chaiscript::fun(&Type2::get_str), "get_str"); m->add(chaiscript::fun(&Type2::get_str), "get_str");
m->add(chaiscript::type_conversion<const char *, std::string>()); m->add(chaiscript::type_conversion<const char *, std::string>());
m->add(chaiscript::constructor<Type2 (const TestBaseType &)>(), "Type2"); m->add(chaiscript::constructor<Type2(const TestBaseType &)>(), "Type2");
m->add(chaiscript::fun(&update_shared_ptr), "update_shared_ptr"); m->add(chaiscript::fun(&update_shared_ptr), "update_shared_ptr");
m->add(chaiscript::fun(&nullify_shared_ptr), "nullify_shared_ptr"); m->add(chaiscript::fun(&nullify_shared_ptr), "nullify_shared_ptr");
return m; return m;
} }
#ifdef __llvm__ #ifdef __llvm__
#pragma clang diagnostic pop #pragma clang diagnostic pop
#endif #endif

View File

@ -1,8 +1,6 @@
#include "../include/chaiscript/language/chaiscript_parser.hpp" #include "../include/chaiscript/language/chaiscript_parser.hpp"
#include "chaiscript_parser.hpp" #include "chaiscript_parser.hpp"
std::unique_ptr<chaiscript::parser::ChaiScript_Parser_Base> create_chaiscript_parser() std::unique_ptr<chaiscript::parser::ChaiScript_Parser_Base> create_chaiscript_parser() {
{
return std::make_unique<chaiscript::parser::ChaiScript_Parser<chaiscript::eval::Noop_Tracer, chaiscript::optimizer::Optimizer_Default>>(); return std::make_unique<chaiscript::parser::ChaiScript_Parser<chaiscript::eval::Noop_Tracer, chaiscript::optimizer::Optimizer_Default>>();
} }

View File

@ -2,11 +2,13 @@
#ifndef CHAISCRIPT_PARSER_LIB #ifndef CHAISCRIPT_PARSER_LIB
#define CHAISCRIPT_PARSER_LIB #define CHAISCRIPT_PARSER_LIB
#include <memory>
namespace chaiscript { namespace chaiscript {
namespace parser { namespace parser {
class ChaiScript_Parser_Base; class ChaiScript_Parser_Base;
} }
} } // namespace chaiscript
std::unique_ptr<chaiscript::parser::ChaiScript_Parser_Base> create_chaiscript_parser(); std::unique_ptr<chaiscript::parser::ChaiScript_Parser_Base> create_chaiscript_parser();

View File

@ -1,8 +1,6 @@
#include "../include/chaiscript/chaiscript_stdlib.hpp" #include "../include/chaiscript/chaiscript_stdlib.hpp"
#include "chaiscript_stdlib.hpp" #include "chaiscript_stdlib.hpp"
std::shared_ptr<chaiscript::Module> create_chaiscript_stdlib() std::shared_ptr<chaiscript::Module> create_chaiscript_stdlib() {
{
return chaiscript::Std_Lib::library(); return chaiscript::Std_Lib::library();
} }

View File

@ -1,15 +1,13 @@
#include <chaiscript/utility/utility.hpp> #include <chaiscript/utility/utility.hpp>
using namespace chaiscript; using namespace chaiscript;
template<typename T> template<typename T>
void use(T){} void use(T) {
}
template<typename To> template<typename To>
bool run_test_type_conversion(const Boxed_Value &bv, bool expectedpass) bool run_test_type_conversion(const Boxed_Value &bv, bool expectedpass) {
{
try { try {
To ret = chaiscript::boxed_cast<To>(bv); To ret = chaiscript::boxed_cast<To>(bv);
use(ret); use(ret);
@ -31,17 +29,14 @@ bool run_test_type_conversion(const Boxed_Value &bv, bool expectedpass)
} }
template<typename To> template<typename To>
bool test_type_conversion(const Boxed_Value &bv, bool expectedpass) bool test_type_conversion(const Boxed_Value &bv, bool expectedpass) {
{
bool ret = run_test_type_conversion<To>(bv, expectedpass); bool ret = run_test_type_conversion<To>(bv, expectedpass);
if (!ret) if (!ret) {
{ std::cerr << "Error with type conversion test. From: " << (bv.is_const() ? "const " : "")
std::cerr << "Error with type conversion test. From: " << bv.get_type_info().name() << " To: " << (std::is_const<To>::value ? "const " : "")
<< (bv.is_const()?(std::string("const ")):(std::string())) << bv.get_type_info().name() << typeid(To).name() << " test was expected to " << (expectedpass ? "succeed" : "fail")
<< " To: " << " but did not\n";
<< (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";
} }
return ret; return ret;
@ -49,13 +44,32 @@ bool test_type_conversion(const Boxed_Value &bv, bool expectedpass)
template<typename Type> template<typename Type>
bool do_test(const Boxed_Value &bv, bool do_test(const Boxed_Value &bv,
bool T, bool ConstT, bool TRef, bool ConstTRef, bool TPtr, bool T,
bool ConstTPtr, bool TPtrConst, bool ConstTPtrConst, bool SharedPtrT, bool SharedConstPtrT, bool ConstT,
bool SharedPtrTRef, bool ConstSharedPtrT, bool ConstSharedConstPtrT, bool ConstSharedPtrTRef, bool ConstSharedPtrTConstRef, bool TRef,
bool WrappedRef, bool WrappedConstRef, bool ConstWrappedRef, bool ConstWrappedConstRef, bool ConstWrappedRefRef, bool ConstTRef,
bool ConstWrappedConstRefRef, bool Number, bool ConstNumber, bool ConstNumberRef, bool TPtrConstRef, bool TPtr,
bool ConstTPtrConstRef) bool ConstTPtr,
{ bool TPtrConst,
bool ConstTPtrConst,
bool SharedPtrT,
bool SharedConstPtrT,
bool SharedPtrTRef,
bool ConstSharedPtrT,
bool ConstSharedConstPtrT,
bool ConstSharedPtrTRef,
bool ConstSharedPtrTConstRef,
bool WrappedRef,
bool WrappedConstRef,
bool ConstWrappedRef,
bool ConstWrappedConstRef,
bool ConstWrappedRefRef,
bool ConstWrappedConstRefRef,
bool Number,
bool ConstNumber,
bool ConstNumberRef,
bool TPtrConstRef,
bool ConstTPtrConstRef) {
bool passed = true; bool passed = true;
passed &= test_type_conversion<Type>(bv, T); passed &= test_type_conversion<Type>(bv, T);
passed &= test_type_conversion<const Type>(bv, ConstT); passed &= test_type_conversion<const Type>(bv, ConstT);
@ -63,22 +77,22 @@ bool do_test(const Boxed_Value &bv,
passed &= test_type_conversion<const Type &>(bv, ConstTRef); passed &= test_type_conversion<const Type &>(bv, ConstTRef);
passed &= test_type_conversion<Type *>(bv, TPtr); passed &= test_type_conversion<Type *>(bv, TPtr);
passed &= test_type_conversion<const Type *>(bv, ConstTPtr); passed &= test_type_conversion<const Type *>(bv, ConstTPtr);
passed &= test_type_conversion<Type * const>(bv, TPtrConst); passed &= test_type_conversion<Type *const>(bv, TPtrConst);
passed &= test_type_conversion<const Type * const>(bv, ConstTPtrConst); passed &= test_type_conversion<const Type *const>(bv, ConstTPtrConst);
passed &= test_type_conversion<std::shared_ptr<Type> >(bv, SharedPtrT); passed &= test_type_conversion<std::shared_ptr<Type>>(bv, SharedPtrT);
passed &= test_type_conversion<std::shared_ptr<const Type> >(bv, SharedConstPtrT); passed &= test_type_conversion<std::shared_ptr<const Type>>(bv, SharedConstPtrT);
passed &= test_type_conversion<std::shared_ptr<Type> &>(bv, SharedPtrTRef); passed &= test_type_conversion<std::shared_ptr<Type> &>(bv, SharedPtrTRef);
//passed &= test_type_conversion<std::shared_ptr<const Type> &>(bv, false); // passed &= test_type_conversion<std::shared_ptr<const Type> &>(bv, false);
passed &= test_type_conversion<const std::shared_ptr<Type> >(bv, ConstSharedPtrT); passed &= test_type_conversion<const std::shared_ptr<Type>>(bv, ConstSharedPtrT);
passed &= test_type_conversion<const std::shared_ptr<const Type> >(bv, ConstSharedConstPtrT); passed &= test_type_conversion<const std::shared_ptr<const Type>>(bv, ConstSharedConstPtrT);
passed &= test_type_conversion<const std::shared_ptr<Type> &>(bv, ConstSharedPtrTRef); passed &= test_type_conversion<const std::shared_ptr<Type> &>(bv, ConstSharedPtrTRef);
passed &= test_type_conversion<const std::shared_ptr<const Type> &>(bv, ConstSharedPtrTConstRef); passed &= test_type_conversion<const std::shared_ptr<const Type> &>(bv, ConstSharedPtrTConstRef);
passed &= test_type_conversion<std::reference_wrapper<Type> >(bv, WrappedRef); passed &= test_type_conversion<std::reference_wrapper<Type>>(bv, WrappedRef);
passed &= test_type_conversion<std::reference_wrapper<const Type> >(bv, WrappedConstRef); passed &= test_type_conversion<std::reference_wrapper<const Type>>(bv, WrappedConstRef);
passed &= test_type_conversion<std::reference_wrapper<Type> &>(bv, false); passed &= test_type_conversion<std::reference_wrapper<Type> &>(bv, false);
passed &= test_type_conversion<std::reference_wrapper<const Type> &>(bv, false); passed &= test_type_conversion<std::reference_wrapper<const Type> &>(bv, false);
passed &= test_type_conversion<const std::reference_wrapper<Type> >(bv, ConstWrappedRef); passed &= test_type_conversion<const std::reference_wrapper<Type>>(bv, ConstWrappedRef);
passed &= test_type_conversion<const std::reference_wrapper<const Type> >(bv, ConstWrappedConstRef); passed &= test_type_conversion<const std::reference_wrapper<const Type>>(bv, ConstWrappedConstRef);
passed &= test_type_conversion<const std::reference_wrapper<Type> &>(bv, ConstWrappedRefRef); passed &= test_type_conversion<const std::reference_wrapper<Type> &>(bv, ConstWrappedRefRef);
passed &= test_type_conversion<const std::reference_wrapper<const Type> &>(bv, ConstWrappedConstRefRef); passed &= test_type_conversion<const std::reference_wrapper<const Type> &>(bv, ConstWrappedConstRefRef);
passed &= test_type_conversion<Boxed_Number>(bv, Number); passed &= test_type_conversion<Boxed_Number>(bv, Number);
@ -87,12 +101,12 @@ bool do_test(const Boxed_Value &bv,
passed &= test_type_conversion<const Boxed_Number &>(bv, ConstNumberRef); passed &= test_type_conversion<const Boxed_Number &>(bv, ConstNumberRef);
passed &= test_type_conversion<Boxed_Number *>(bv, false); passed &= test_type_conversion<Boxed_Number *>(bv, false);
passed &= test_type_conversion<const Boxed_Number *>(bv, false); passed &= test_type_conversion<const Boxed_Number *>(bv, false);
passed &= test_type_conversion<Boxed_Number * const>(bv, false); passed &= test_type_conversion<Boxed_Number *const>(bv, false);
passed &= test_type_conversion<const Boxed_Number *const>(bv, false); passed &= test_type_conversion<const Boxed_Number *const>(bv, false);
passed &= test_type_conversion<Type *&>(bv, false); passed &= test_type_conversion<Type *&>(bv, false);
passed &= test_type_conversion<const Type *&>(bv, false); passed &= test_type_conversion<const Type *&>(bv, false);
passed &= test_type_conversion<Type * const&>(bv, TPtrConstRef); passed &= test_type_conversion<Type *const &>(bv, TPtrConstRef);
passed &= test_type_conversion<const Type * const&>(bv, ConstTPtrConstRef); passed &= test_type_conversion<const Type *const &>(bv, ConstTPtrConstRef);
passed &= test_type_conversion<Boxed_Value>(bv, true); passed &= test_type_conversion<Boxed_Value>(bv, true);
passed &= test_type_conversion<const Boxed_Value>(bv, true); passed &= test_type_conversion<const Boxed_Value>(bv, true);
passed &= test_type_conversion<const Boxed_Value &>(bv, true); passed &= test_type_conversion<const Boxed_Value &>(bv, true);
@ -102,134 +116,506 @@ bool do_test(const Boxed_Value &bv,
/** Tests intended for built int types **/ /** Tests intended for built int types **/
template<typename T> template<typename T>
bool built_in_type_test(const T &initial, bool ispod) bool built_in_type_test(const T &initial, bool ispod) {
{
bool passed = true; bool passed = true;
/** value tests **/ /** value tests **/
T i = T(initial); T i = T(initial);
passed &= do_test<T>(var(i), true, true, true, true, true, passed &= do_test<T>(var(i),
true, true, true, true, true, true,
true, true, true, true, true, true, true,
true, true, true, true, true, true,
ispod, ispod, ispod, true, true); true,
true,
true,
true,
true,
true,
true,
true,
true,
true,
true,
true,
true,
true,
true,
true,
true,
true,
ispod,
ispod,
ispod,
true,
true);
passed &= do_test<T>(const_var(i), true, true, false, true, false, passed &= do_test<T>(const_var(i),
true, false, true, false, true, true,
false, false, true, false, true, false, true,
true, false, true, false, true, false,
ispod, ispod, ispod, false, true); true,
false,
true,
false,
true,
false,
true,
false,
false,
true,
false,
true,
false,
true,
false,
true,
false,
true,
ispod,
ispod,
ispod,
false,
true);
passed &= do_test<T>(var(&i), true, true, true, true, true, passed &= do_test<T>(var(&i),
true, true, true, false, false, true,
false, false, false, false, false, true, true,
true, true, true, true, true, true,
ispod, ispod, ispod, true, true); true,
true,
true,
true,
true,
false,
false,
false,
false,
false,
false,
false,
true,
true,
true,
true,
true,
true,
ispod,
ispod,
ispod,
true,
true);
passed &= do_test<T>(const_var(&i), true, true, false, true, false, passed &= do_test<T>(const_var(&i),
true, false, true, false, false, true,
false, false, false, false, false, false, true,
true, false, true, false, true, false,
ispod, ispod, ispod, false, true); true,
false,
true,
false,
true,
false,
false,
false,
false,
false,
false,
false,
false,
true,
false,
true,
false,
true,
ispod,
ispod,
ispod,
false,
true);
passed &= do_test<T>(var(std::ref(i)), true, true, true, true, true, passed &= do_test<T>(var(std::ref(i)),
true, true, true, false, false, true,
false, false, false, false, false, true, true,
true, true, true, true, true, true,
ispod, ispod, ispod, true, true); true,
true,
true,
true,
true,
false,
false,
false,
false,
false,
false,
false,
true,
true,
true,
true,
true,
true,
ispod,
ispod,
ispod,
true,
true);
passed &= do_test<T>(var(std::cref(i)), true, true, false, true, false, passed &= do_test<T>(var(std::cref(i)),
true, false, true, false, false, true,
false, false, false, false, false, false, true,
true, false, true, false, true, false,
ispod, ispod, ispod, false, true); true,
false,
true,
false,
true,
false,
false,
false,
false,
false,
false,
false,
false,
true,
false,
true,
false,
true,
ispod,
ispod,
ispod,
false,
true);
/** Const Reference Variable tests */ /** Const Reference Variable tests */
// This reference will be copied on input, which is expected // This reference will be copied on input, which is expected
const T &ir = i; const T &ir = i;
passed &= do_test<T>(var(i), true, true, true, true, true, passed &= do_test<T>(var(i),
true, true, true, true, true, true,
true, true, true, true, true, true, true,
true, true, true, true, true, true,
ispod, ispod, ispod, true, true); true,
true,
true,
true,
true,
true,
true,
true,
true,
true,
true,
true,
true,
true,
true,
true,
true,
true,
ispod,
ispod,
ispod,
true,
true);
// But a pointer or reference to it should be necessarily const // But a pointer or reference to it should be necessarily const
passed &= do_test<T>(var(&ir), true, true, false, true, false, passed &= do_test<T>(var(&ir),
true, false, true, false, false, true,
false, false, false, false, false, false, true,
true, false, true, false, true, false,
ispod, ispod, ispod, false, true); true,
false,
true,
false,
true,
false,
false,
false,
false,
false,
false,
false,
false,
true,
false,
true,
false,
true,
ispod,
ispod,
ispod,
false,
true);
passed &= do_test<T>(var(std::ref(ir)), true, true, false, true, false, passed &= do_test<T>(var(std::ref(ir)),
true, false, true, false, false, true,
false, false, false, false, false, false, true,
true, false, true, false, true, false,
ispod, ispod, ispod, false, true); true,
false,
true,
false,
true,
false,
false,
false,
false,
false,
false,
false,
false,
true,
false,
true,
false,
true,
ispod,
ispod,
ispod,
false,
true);
// Make sure const of const works too // Make sure const of const works too
passed &= do_test<T>(const_var(&ir), true, true, false, true, false, passed &= do_test<T>(const_var(&ir),
true, false, true, false, false, true,
false, false, false, false, false, false, true,
true, false, true, false, true, false,
ispod, ispod, ispod, false, true); true,
false,
true,
false,
true,
false,
false,
false,
false,
false,
false,
false,
false,
true,
false,
true,
false,
true,
ispod,
ispod,
ispod,
false,
true);
passed &= do_test<T>(const_var(std::ref(ir)), true, true, false, true, false, passed &= do_test<T>(const_var(std::ref(ir)),
true, false, true, false, false, true,
false, false, false, false, false, false, true,
true, false, true, false, true, false,
ispod, ispod, ispod, false, true); true,
false,
true,
false,
true,
false,
false,
false,
false,
false,
false,
false,
false,
true,
false,
true,
false,
true,
ispod,
ispod,
ispod,
false,
true);
/** Const Reference Variable tests */ /** Const Reference Variable tests */
// This will always be seen as a const // This will always be seen as a const
const T*cip = &i; const T *cip = &i;
passed &= do_test<T>(var(cip), true, true, false, true, false, passed &= do_test<T>(var(cip),
true, false, true, false, false, true,
false, false, false, false, false, false, true,
true, false, true, false, true, false,
ispod, ispod, ispod, false, true); true,
false,
true,
false,
true,
false,
false,
false,
false,
false,
false,
false,
false,
true,
false,
true,
false,
true,
ispod,
ispod,
ispod,
false,
true);
// make sure const of const works // make sure const of const works
passed &= do_test<T>(const_var(cip), true, true, false, true, false, passed &= do_test<T>(const_var(cip),
true, false, true, false, false, true,
false, false, false, false, false, false, true,
true, false, true, false, true, false,
ispod, ispod, ispod, false, true); true,
false,
true,
false,
true,
false,
false,
false,
false,
false,
false,
false,
false,
true,
false,
true,
false,
true,
ispod,
ispod,
ispod,
false,
true);
/** shared_ptr tests **/ /** shared_ptr tests **/
auto ip = std::make_shared<T>(initial); auto ip = std::make_shared<T>(initial);
passed &= do_test<T>(var(ip), true, true, true, true, true, passed &= do_test<T>(var(ip),
true, true, true, true, true, true,
true, true, true, true, true, true, true,
true, true, true, true, true, true,
ispod, ispod, ispod, true, true); true,
true,
true,
true,
true,
true,
true,
true,
true,
true,
true,
true,
true,
true,
true,
true,
true,
true,
ispod,
ispod,
ispod,
true,
true);
passed &= do_test<T>(const_var(ip), true, true, false, true, false, passed &= do_test<T>(const_var(ip),
true, false, true, false, true, true,
false, false, true, false, true, false, true,
true, false, true, false, true, false,
ispod, ispod, ispod, false, true); true,
false,
true,
false,
true,
false,
true,
false,
false,
true,
false,
true,
false,
true,
false,
true,
false,
true,
ispod,
ispod,
ispod,
false,
true);
/** const shared_ptr tests **/ /** const shared_ptr tests **/
auto ipc = std::make_shared<const T>(T(initial)); auto ipc = std::make_shared<const T>(T(initial));
passed &= do_test<T>(var(ipc), true, true, false, true, false, passed &= do_test<T>(var(ipc),
true, false, true, false, true, true,
false, false, true, false, true, false, true,
true, false, true, false, true, false,
ispod, ispod, ispod, false, true); true,
false,
true,
false,
true,
false,
true,
false,
false,
true,
false,
true,
false,
true,
false,
true,
false,
true,
ispod,
ispod,
ispod,
false,
true);
// const of this should be the same, making sure it compiles // const of this should be the same, making sure it compiles
passed &= do_test<T>(const_var(ipc), true, true, false, true, false, passed &= do_test<T>(const_var(ipc),
true, false, true, false, true, true,
false, false, true, false, true, false, true,
true, false, true, false, true, false,
ispod, ispod, ispod, false, true); true,
false,
true,
false,
true,
false,
true,
false,
false,
true,
false,
true,
false,
true,
false,
true,
false,
true,
ispod,
ispod,
ispod,
false,
true);
/** Double ptr tests **/ /** Double ptr tests **/
@ -241,15 +627,13 @@ bool built_in_type_test(const T &initial, bool ispod)
false, true, false, true, false, false, true, false, true, false,
true, false, true, false, true, true, false, true, false, true,
ispod, ispod, ispod, false, true); ispod, ispod, ispod, false, true);
*/ */
return passed; return passed;
} }
template<typename T> template<typename T>
bool pointer_test(const T& default_value, const T& new_value) bool pointer_test(const T &default_value, const T &new_value) {
{
T *p = new T(default_value); T *p = new T(default_value);
// we store a pointer to a pointer, so we can get a pointer to a pointer // we store a pointer to a pointer, so we can get a pointer to a pointer
@ -257,14 +641,13 @@ bool pointer_test(const T& default_value, const T& new_value)
T **result = boxed_cast<T **>(var(&p)); T **result = boxed_cast<T **>(var(&p));
*(*result) = new_value; *(*result) = new_value;
if (p != (*result)) {
if (p != (*result) ) {
std::cerr << "Pointer passed in different than one returned\n"; std::cerr << "Pointer passed in different than one returned\n";
delete p; delete p;
return false; return false;
} }
if (*p != *(*result) ) { if (*p != *(*result)) {
std::cerr << "Somehow dereferenced pointer values are not the same?\n"; std::cerr << "Somehow dereferenced pointer values are not the same?\n";
delete p; delete p;
return false; return false;
@ -283,9 +666,7 @@ bool pointer_test(const T& default_value, const T& new_value)
} }
} }
int main() {
int main()
{
bool passed = true; bool passed = true;
/* /*

View File

@ -1,21 +1,16 @@
#include <chaiscript/chaiscript_basic.hpp>
#include "../static_libs/chaiscript_parser.hpp" #include "../static_libs/chaiscript_parser.hpp"
#include "../static_libs/chaiscript_stdlib.hpp" #include "../static_libs/chaiscript_stdlib.hpp"
#include <chaiscript/chaiscript_basic.hpp>
extern "C" {
extern "C" int do_something(int i) {
{
int do_something(int i)
{
return i % 2; return i % 2;
} }
} }
int main() int main() {
{ chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(), create_chaiscript_parser());
chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser());
chai.add(chaiscript::fun(&do_something), "do_something"); chai.add(chaiscript::fun(&do_something), "do_something");
return chai.eval<int>("do_something(101)") == 101 % 2?EXIT_SUCCESS:EXIT_FAILURE; return chai.eval<int>("do_something(101)") == 101 % 2 ? EXIT_SUCCESS : EXIT_FAILURE;
} }

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,6 @@
#include <chaiscript/chaiscript_basic.hpp>
#include "../static_libs/chaiscript_parser.hpp" #include "../static_libs/chaiscript_parser.hpp"
#include "../static_libs/chaiscript_stdlib.hpp" #include "../static_libs/chaiscript_stdlib.hpp"
#include <chaiscript/chaiscript_basic.hpp>
#ifdef CHAISCRIPT_MSVC #ifdef CHAISCRIPT_MSVC
// ignore errors about negative unsigned integer literals // ignore errors about negative unsigned integer literals
@ -9,20 +8,18 @@
#pragma warning(disable : 4146) #pragma warning(disable : 4146)
#endif #endif
#define TEST_LITERAL(v) test_literal(v, #v) #define TEST_LITERAL(v) test_literal(v, #v)
#define TEST_LITERAL_SIGNED(v) test_literal(v, #v, true) #define TEST_LITERAL_SIGNED(v) test_literal(v, #v, true)
template<typename T> template<typename T>
bool test_literal(T val, const std::string &str, bool use_boxed_number = false) bool test_literal(T val, const std::string &str, bool use_boxed_number = false) {
{
std::cout << '(' << str << ") Comparing : C++ '" << val; std::cout << '(' << str << ") Comparing : C++ '" << val;
chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser()); chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(), create_chaiscript_parser());
// Note, after applying the `-` it's possible that chaiscript has internally converted // Note, after applying the `-` it's possible that chaiscript has internally converted
// between two equivalently sized types (ie, unsigned long and unsigned long long on a 64bit system) // between two equivalently sized types (ie, unsigned long and unsigned long long on a 64bit system)
// so we're going to allow some leeway with the signed tests // so we're going to allow some leeway with the signed tests
T val2 = [&](){ T val2 = [&]() {
if (!use_boxed_number) { if (!use_boxed_number) {
return chai.eval<T>(str); return chai.eval<T>(str);
} }
@ -33,79 +30,29 @@ bool test_literal(T val, const std::string &str, bool use_boxed_number = false)
return val == val2; return val == val2;
} }
int main() int main() {
{ if (TEST_LITERAL(0xF) && TEST_LITERAL(0xFF) && TEST_LITERAL(0xFFF) && TEST_LITERAL(0xFFFF) && TEST_LITERAL(0xFFFFF)
if( && TEST_LITERAL(0xFFFFFF) && TEST_LITERAL(0xFFFFFFF) && TEST_LITERAL(0xFFFFFFFF) && TEST_LITERAL(0xFFFFFFFFF)
TEST_LITERAL(0xF) && TEST_LITERAL(0xFFFFFFFFFF) && TEST_LITERAL(0xFFFFFFFFFFF) && TEST_LITERAL(0xFFFFFFFFFFFF) && TEST_LITERAL(0xFFFFFFFFFFFFF)
&& TEST_LITERAL(0xFF) && TEST_LITERAL(0xFFFFFFFFFFFFFF) && TEST_LITERAL(0xFFFFFFFFFFFFFFF) && TEST_LITERAL(0xFFFFFFFFFFFFFFFF)
&& TEST_LITERAL(0xFFF)
&& TEST_LITERAL(0xFFFF)
&& TEST_LITERAL(0xFFFFF)
&& TEST_LITERAL(0xFFFFFF)
&& TEST_LITERAL(0xFFFFFFF)
&& TEST_LITERAL(0xFFFFFFFF)
&& TEST_LITERAL(0xFFFFFFFFF)
&& TEST_LITERAL(0xFFFFFFFFFF)
&& TEST_LITERAL(0xFFFFFFFFFFF)
&& TEST_LITERAL(0xFFFFFFFFFFFF)
&& TEST_LITERAL(0xFFFFFFFFFFFFF)
&& TEST_LITERAL(0xFFFFFFFFFFFFFF)
&& TEST_LITERAL(0xFFFFFFFFFFFFFFF)
&& TEST_LITERAL(0xFFFFFFFFFFFFFFFF)
&& TEST_LITERAL(01) && TEST_LITERAL(017) && TEST_LITERAL(0177) && TEST_LITERAL(01777) && TEST_LITERAL(017777)
&& TEST_LITERAL(0177777) && TEST_LITERAL(01777777) && TEST_LITERAL(017777777) && TEST_LITERAL(0177777777)
&& TEST_LITERAL(01777777777) && TEST_LITERAL(017777777777) && TEST_LITERAL(0177777777777) && TEST_LITERAL(01777777777777)
&& TEST_LITERAL(017777777777777) && TEST_LITERAL(0177777777777777) && TEST_LITERAL(01777777777777777)
&& TEST_LITERAL(017777777777777777) && TEST_LITERAL(0177777777777777777) && TEST_LITERAL(01777777777777777777)
&& TEST_LITERAL(017777777777777777777) && TEST_LITERAL(0177777777777777777777) && TEST_LITERAL(01777777777777777777777)
&& TEST_LITERAL(01) && TEST_LITERAL(1) && TEST_LITERAL(17) && TEST_LITERAL(177) && TEST_LITERAL(1777) && TEST_LITERAL(17777) && TEST_LITERAL(177777)
&& TEST_LITERAL(017) && TEST_LITERAL(1777777) && TEST_LITERAL(17777777) && TEST_LITERAL(177777777) && TEST_LITERAL(1777777777)
&& TEST_LITERAL(0177) && TEST_LITERAL(17777777777) && TEST_LITERAL(177777777777) && TEST_LITERAL(1777777777777) && TEST_LITERAL(17777777777777)
&& TEST_LITERAL(01777) && TEST_LITERAL(177777777777777) && TEST_LITERAL(1777777777777777) && TEST_LITERAL(17777777777777777)
&& TEST_LITERAL(017777) && TEST_LITERAL(177777777777777777) && TEST_LITERAL(1777777777777777777)
&& TEST_LITERAL(0177777)
&& TEST_LITERAL(01777777)
&& TEST_LITERAL(017777777)
&& TEST_LITERAL(0177777777)
&& TEST_LITERAL(01777777777)
&& TEST_LITERAL(017777777777)
&& TEST_LITERAL(0177777777777)
&& TEST_LITERAL(01777777777777)
&& TEST_LITERAL(017777777777777)
&& TEST_LITERAL(0177777777777777)
&& TEST_LITERAL(01777777777777777)
&& TEST_LITERAL(017777777777777777)
&& TEST_LITERAL(0177777777777777777)
&& TEST_LITERAL(01777777777777777777)
&& TEST_LITERAL(017777777777777777777)
&& TEST_LITERAL(0177777777777777777777)
&& TEST_LITERAL(01777777777777777777777)
&& TEST_LITERAL(1) && test_literal(0xF, "0b1111") && test_literal(0xFF, "0b11111111") && test_literal(0xFFF, "0b111111111111")
&& TEST_LITERAL(17) && test_literal(0xFFFF, "0b1111111111111111") && test_literal(0xFFFFF, "0b11111111111111111111")
&& TEST_LITERAL(177) && test_literal(0xFFFFFF, "0b111111111111111111111111") && test_literal(0xFFFFFFF, "0b1111111111111111111111111111")
&& TEST_LITERAL(1777) && test_literal(0xFFFFFFFF, "0b11111111111111111111111111111111") && test_literal(0xFFFFFFFFF, "0b111111111111111111111111111111111111")
&& TEST_LITERAL(17777)
&& TEST_LITERAL(177777)
&& TEST_LITERAL(1777777)
&& TEST_LITERAL(17777777)
&& TEST_LITERAL(177777777)
&& TEST_LITERAL(1777777777)
&& TEST_LITERAL(17777777777)
&& TEST_LITERAL(177777777777)
&& TEST_LITERAL(1777777777777)
&& TEST_LITERAL(17777777777777)
&& TEST_LITERAL(177777777777777)
&& TEST_LITERAL(1777777777777777)
&& TEST_LITERAL(17777777777777777)
&& TEST_LITERAL(177777777777777777)
&& TEST_LITERAL(1777777777777777777)
&& test_literal(0xF, "0b1111")
&& test_literal(0xFF, "0b11111111")
&& test_literal(0xFFF, "0b111111111111")
&& test_literal(0xFFFF, "0b1111111111111111")
&& test_literal(0xFFFFF, "0b11111111111111111111")
&& test_literal(0xFFFFFF, "0b111111111111111111111111")
&& test_literal(0xFFFFFFF, "0b1111111111111111111111111111")
&& test_literal(0xFFFFFFFF, "0b11111111111111111111111111111111")
&& test_literal(0xFFFFFFFFF, "0b111111111111111111111111111111111111")
&& test_literal(0xFFFFFFFFFF, "0b1111111111111111111111111111111111111111") && test_literal(0xFFFFFFFFFF, "0b1111111111111111111111111111111111111111")
&& test_literal(0xFFFFFFFFFFF, "0b11111111111111111111111111111111111111111111") && test_literal(0xFFFFFFFFFFF, "0b11111111111111111111111111111111111111111111")
&& test_literal(0xFFFFFFFFFFFF, "0b111111111111111111111111111111111111111111111111") && test_literal(0xFFFFFFFFFFFF, "0b111111111111111111111111111111111111111111111111")
@ -114,15 +61,10 @@ int main()
&& test_literal(0xFFFFFFFFFFFFFFF, "0b111111111111111111111111111111111111111111111111111111111111") && test_literal(0xFFFFFFFFFFFFFFF, "0b111111111111111111111111111111111111111111111111111111111111")
&& test_literal(0xFFFFFFFFFFFFFFFF, "0b1111111111111111111111111111111111111111111111111111111111111111") && test_literal(0xFFFFFFFFFFFFFFFF, "0b1111111111111111111111111111111111111111111111111111111111111111")
&& test_literal(0x7, "0b111") && test_literal(0x7, "0b111") && test_literal(0x7F, "0b1111111") && test_literal(0x7FF, "0b11111111111")
&& test_literal(0x7F, "0b1111111") && test_literal(0x7FFF, "0b111111111111111") && test_literal(0x7FFFF, "0b1111111111111111111")
&& test_literal(0x7FF, "0b11111111111") && test_literal(0x7FFFFF, "0b11111111111111111111111") && test_literal(0x7FFFFFF, "0b111111111111111111111111111")
&& test_literal(0x7FFF, "0b111111111111111") && test_literal(0x7FFFFFFF, "0b1111111111111111111111111111111") && test_literal(0x7FFFFFFFF, "0b11111111111111111111111111111111111")
&& test_literal(0x7FFFF, "0b1111111111111111111")
&& test_literal(0x7FFFFF, "0b11111111111111111111111")
&& test_literal(0x7FFFFFF, "0b111111111111111111111111111")
&& test_literal(0x7FFFFFFF, "0b1111111111111111111111111111111")
&& test_literal(0x7FFFFFFFF, "0b11111111111111111111111111111111111")
&& test_literal(0x7FFFFFFFFF, "0b111111111111111111111111111111111111111") && test_literal(0x7FFFFFFFFF, "0b111111111111111111111111111111111111111")
&& test_literal(0x7FFFFFFFFFF, "0b1111111111111111111111111111111111111111111") && test_literal(0x7FFFFFFFFFF, "0b1111111111111111111111111111111111111111111")
&& test_literal(0x7FFFFFFFFFFF, "0b11111111111111111111111111111111111111111111111") && test_literal(0x7FFFFFFFFFFF, "0b11111111111111111111111111111111111111111111111")
@ -131,152 +73,82 @@ int main()
&& test_literal(0x7FFFFFFFFFFFFFF, "0b11111111111111111111111111111111111111111111111111111111111") && test_literal(0x7FFFFFFFFFFFFFF, "0b11111111111111111111111111111111111111111111111111111111111")
&& test_literal(0x7FFFFFFFFFFFFFFF, "0b111111111111111111111111111111111111111111111111111111111111111") && test_literal(0x7FFFFFFFFFFFFFFF, "0b111111111111111111111111111111111111111111111111111111111111111")
&& TEST_LITERAL_SIGNED(-0xF) && TEST_LITERAL_SIGNED(-0xFF) && TEST_LITERAL_SIGNED(-0xFFF) && TEST_LITERAL_SIGNED(-0xFFFF)
&& TEST_LITERAL_SIGNED(-0xFFFFF) && TEST_LITERAL_SIGNED(-0xFFFFFF) && TEST_LITERAL_SIGNED(-0xFFFFFFF)
&& TEST_LITERAL_SIGNED(-0xFFFFFFFF) && TEST_LITERAL_SIGNED(-0xFFFFFFFFF) && TEST_LITERAL_SIGNED(-0xFFFFFFFFFF)
&& TEST_LITERAL_SIGNED(-0xFFFFFFFFFFF) && TEST_LITERAL_SIGNED(-0xFFFFFFFFFFFF) && TEST_LITERAL_SIGNED(-0xFFFFFFFFFFFFF)
&& TEST_LITERAL_SIGNED(-0xFFFFFFFFFFFFFF) && TEST_LITERAL_SIGNED(-0xFFFFFFFFFFFFFFF) && TEST_LITERAL_SIGNED(-0xFFFFFFFFFFFFFFFF)
&& TEST_LITERAL_SIGNED(-0xF) && TEST_LITERAL_SIGNED(-01) && TEST_LITERAL_SIGNED(-017) && TEST_LITERAL_SIGNED(-0177) && TEST_LITERAL_SIGNED(-01777)
&& TEST_LITERAL_SIGNED(-0xFF) && TEST_LITERAL_SIGNED(-017777) && TEST_LITERAL_SIGNED(-0177777) && TEST_LITERAL_SIGNED(-01777777) && TEST_LITERAL_SIGNED(-017777777)
&& TEST_LITERAL_SIGNED(-0xFFF) && TEST_LITERAL_SIGNED(-0177777777) && TEST_LITERAL_SIGNED(-01777777777) && TEST_LITERAL_SIGNED(-017777777777)
&& TEST_LITERAL_SIGNED(-0xFFFF) && TEST_LITERAL_SIGNED(-0177777777777) && TEST_LITERAL_SIGNED(-01777777777777) && TEST_LITERAL_SIGNED(-017777777777777)
&& TEST_LITERAL_SIGNED(-0xFFFFF) && TEST_LITERAL_SIGNED(-0177777777777777) && TEST_LITERAL_SIGNED(-01777777777777777) && TEST_LITERAL_SIGNED(-017777777777777777)
&& TEST_LITERAL_SIGNED(-0xFFFFFF) && TEST_LITERAL_SIGNED(-0177777777777777777) && TEST_LITERAL_SIGNED(-01777777777777777777) && TEST_LITERAL_SIGNED(-017777777777777777777)
&& TEST_LITERAL_SIGNED(-0xFFFFFFF) && TEST_LITERAL_SIGNED(-0177777777777777777777) && TEST_LITERAL_SIGNED(-01777777777777777777777)
&& TEST_LITERAL_SIGNED(-0xFFFFFFFF)
&& TEST_LITERAL_SIGNED(-0xFFFFFFFFF)
&& TEST_LITERAL_SIGNED(-0xFFFFFFFFFF)
&& TEST_LITERAL_SIGNED(-0xFFFFFFFFFFF)
&& TEST_LITERAL_SIGNED(-0xFFFFFFFFFFFF)
&& TEST_LITERAL_SIGNED(-0xFFFFFFFFFFFFF)
&& TEST_LITERAL_SIGNED(-0xFFFFFFFFFFFFFF)
&& TEST_LITERAL_SIGNED(-0xFFFFFFFFFFFFFFF)
&& TEST_LITERAL_SIGNED(-0xFFFFFFFFFFFFFFFF)
&& TEST_LITERAL_SIGNED(-1) && TEST_LITERAL_SIGNED(-17) && TEST_LITERAL_SIGNED(-177) && TEST_LITERAL_SIGNED(-1777)
&& TEST_LITERAL_SIGNED(-01) && TEST_LITERAL_SIGNED(-17777) && TEST_LITERAL_SIGNED(-177777) && TEST_LITERAL_SIGNED(-1777777) && TEST_LITERAL_SIGNED(-17777777)
&& TEST_LITERAL_SIGNED(-017) && TEST_LITERAL_SIGNED(-177777777) && TEST_LITERAL_SIGNED(-1777777777) && TEST_LITERAL_SIGNED(-17777777777)
&& TEST_LITERAL_SIGNED(-0177) && TEST_LITERAL_SIGNED(-177777777777) && TEST_LITERAL_SIGNED(-1777777777777) && TEST_LITERAL_SIGNED(-17777777777777)
&& TEST_LITERAL_SIGNED(-01777) && TEST_LITERAL_SIGNED(-177777777777777) && TEST_LITERAL_SIGNED(-1777777777777777) && TEST_LITERAL_SIGNED(-17777777777777777)
&& TEST_LITERAL_SIGNED(-017777)
&& TEST_LITERAL_SIGNED(-0177777)
&& TEST_LITERAL_SIGNED(-01777777)
&& TEST_LITERAL_SIGNED(-017777777)
&& TEST_LITERAL_SIGNED(-0177777777)
&& TEST_LITERAL_SIGNED(-01777777777)
&& TEST_LITERAL_SIGNED(-017777777777)
&& TEST_LITERAL_SIGNED(-0177777777777)
&& TEST_LITERAL_SIGNED(-01777777777777)
&& TEST_LITERAL_SIGNED(-017777777777777)
&& TEST_LITERAL_SIGNED(-0177777777777777)
&& TEST_LITERAL_SIGNED(-01777777777777777)
&& TEST_LITERAL_SIGNED(-017777777777777777)
&& TEST_LITERAL_SIGNED(-0177777777777777777)
&& TEST_LITERAL_SIGNED(-01777777777777777777)
&& TEST_LITERAL_SIGNED(-017777777777777777777)
&& TEST_LITERAL_SIGNED(-0177777777777777777777)
&& TEST_LITERAL_SIGNED(-01777777777777777777777)
&& TEST_LITERAL_SIGNED(-1)
&& TEST_LITERAL_SIGNED(-17)
&& TEST_LITERAL_SIGNED(-177)
&& TEST_LITERAL_SIGNED(-1777)
&& TEST_LITERAL_SIGNED(-17777)
&& TEST_LITERAL_SIGNED(-177777)
&& TEST_LITERAL_SIGNED(-1777777)
&& TEST_LITERAL_SIGNED(-17777777)
&& TEST_LITERAL_SIGNED(-177777777)
&& TEST_LITERAL_SIGNED(-1777777777)
&& TEST_LITERAL_SIGNED(-17777777777)
&& TEST_LITERAL_SIGNED(-177777777777)
&& TEST_LITERAL_SIGNED(-1777777777777)
&& TEST_LITERAL_SIGNED(-17777777777777)
&& TEST_LITERAL_SIGNED(-177777777777777)
&& TEST_LITERAL_SIGNED(-1777777777777777)
&& TEST_LITERAL_SIGNED(-17777777777777777)
&& TEST_LITERAL_SIGNED(-177777777777777777) && TEST_LITERAL_SIGNED(-177777777777777777)
&& TEST_LITERAL_SIGNED(-1777777777777777777) && TEST_LITERAL_SIGNED(-1777777777777777777)
// Test 8/16/24/32 bit boundaries for various types // Test 8/16/24/32 bit boundaries for various types
&& TEST_LITERAL(255) && TEST_LITERAL(255) && TEST_LITERAL(65535)
&& TEST_LITERAL(65535)
&& TEST_LITERAL(16777215) && TEST_LITERAL(16777215)
#ifndef CHAISCRIPT_MSVC #ifndef CHAISCRIPT_MSVC
// bug in cl.exe causes this to be incorrectly parsed as an unsigned // bug in cl.exe causes this to be incorrectly parsed as an unsigned
&& TEST_LITERAL(4294967295) && TEST_LITERAL(4294967295)
#endif #endif
&& TEST_LITERAL_SIGNED(-255) && TEST_LITERAL_SIGNED(-255) && TEST_LITERAL_SIGNED(-65535)
&& TEST_LITERAL_SIGNED(-65535)
&& TEST_LITERAL_SIGNED(-16777215) && TEST_LITERAL_SIGNED(-16777215)
#ifndef CHAISCRIPT_MSVC #ifndef CHAISCRIPT_MSVC
// bug in cl.exe causes this to be incorrectly parsed as an unsigned // bug in cl.exe causes this to be incorrectly parsed as an unsigned
&& TEST_LITERAL_SIGNED(-4294967295) && TEST_LITERAL_SIGNED(-4294967295)
#endif #endif
&& TEST_LITERAL(255u) && TEST_LITERAL(255u) && TEST_LITERAL(65535u) && TEST_LITERAL(16777215u) && TEST_LITERAL(4294967295u)
&& TEST_LITERAL(65535u)
&& TEST_LITERAL(16777215u)
&& TEST_LITERAL(4294967295u)
&& TEST_LITERAL_SIGNED(-255u) && TEST_LITERAL_SIGNED(-255u) && TEST_LITERAL_SIGNED(-65535u) && TEST_LITERAL_SIGNED(-16777215u) && TEST_LITERAL_SIGNED(-4294967295u)
&& TEST_LITERAL_SIGNED(-65535u)
&& TEST_LITERAL_SIGNED(-16777215u)
&& TEST_LITERAL_SIGNED(-4294967295u)
&& TEST_LITERAL(255l) && TEST_LITERAL(255l) && TEST_LITERAL(65535l)
&& TEST_LITERAL(65535l)
&& TEST_LITERAL(16777215l) && TEST_LITERAL(16777215l)
#ifndef CHAISCRIPT_MSVC #ifndef CHAISCRIPT_MSVC
// bug in cl.exe causes this to be incorrectly parsed as an unsigned // bug in cl.exe causes this to be incorrectly parsed as an unsigned
&& TEST_LITERAL(4294967295l) && TEST_LITERAL(4294967295l)
#endif #endif
&& TEST_LITERAL_SIGNED(-255l) && TEST_LITERAL_SIGNED(-255l) && TEST_LITERAL_SIGNED(-65535l)
&& TEST_LITERAL_SIGNED(-65535l)
&& TEST_LITERAL_SIGNED(-16777215l) && TEST_LITERAL_SIGNED(-16777215l)
#ifndef CHAISCRIPT_MSVC #ifndef CHAISCRIPT_MSVC
// bug in cl.exe causes this to be incorrectly parsed as an unsigned // bug in cl.exe causes this to be incorrectly parsed as an unsigned
&& TEST_LITERAL_SIGNED(-4294967295l) && TEST_LITERAL_SIGNED(-4294967295l)
#endif #endif
&& TEST_LITERAL(255ul) && TEST_LITERAL(255ul) && TEST_LITERAL(65535ul) && TEST_LITERAL(16777215ul) && TEST_LITERAL(4294967295ul)
&& TEST_LITERAL(65535ul)
&& TEST_LITERAL(16777215ul)
&& TEST_LITERAL(4294967295ul)
&& TEST_LITERAL_SIGNED(-255ul) && TEST_LITERAL_SIGNED(-255ul) && TEST_LITERAL_SIGNED(-65535ul) && TEST_LITERAL_SIGNED(-16777215ul) && TEST_LITERAL_SIGNED(-4294967295ul)
&& TEST_LITERAL_SIGNED(-65535ul)
&& TEST_LITERAL_SIGNED(-16777215ul)
&& TEST_LITERAL_SIGNED(-4294967295ul)
&& TEST_LITERAL(255ull) && TEST_LITERAL(255ull) && TEST_LITERAL(65535ull) && TEST_LITERAL(16777215ull) && TEST_LITERAL(4294967295ull)
&& TEST_LITERAL(65535ull)
&& TEST_LITERAL(16777215ull)
&& TEST_LITERAL(4294967295ull)
&& TEST_LITERAL_SIGNED(-255ull) && TEST_LITERAL_SIGNED(-255ull) && TEST_LITERAL_SIGNED(-65535ull) && TEST_LITERAL_SIGNED(-16777215ull)
&& TEST_LITERAL_SIGNED(-65535ull)
&& TEST_LITERAL_SIGNED(-16777215ull)
&& TEST_LITERAL_SIGNED(-4294967295ull) && TEST_LITERAL_SIGNED(-4294967295ull)
&& TEST_LITERAL(255ll) && TEST_LITERAL(255ll) && TEST_LITERAL(65535ll) && TEST_LITERAL(16777215ll) && TEST_LITERAL(4294967295ll)
&& TEST_LITERAL(65535ll)
&& TEST_LITERAL(16777215ll)
&& TEST_LITERAL(4294967295ll)
&& TEST_LITERAL_SIGNED(-255ll) && TEST_LITERAL_SIGNED(-255ll) && TEST_LITERAL_SIGNED(-65535ll) && TEST_LITERAL_SIGNED(-16777215ll) && TEST_LITERAL_SIGNED(-4294967295ll)
&& TEST_LITERAL_SIGNED(-65535ll)
&& TEST_LITERAL_SIGNED(-16777215ll)
&& TEST_LITERAL_SIGNED(-4294967295ll)
) {
)
{
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
return EXIT_FAILURE; return EXIT_FAILURE;
} }
#ifdef CHAISCRIPT_MSVC #ifdef CHAISCRIPT_MSVC
#pragma warning(pop) #pragma warning(pop)
#endif #endif

View File

@ -4,13 +4,11 @@
#include <chaiscript/language/chaiscript_parser.hpp> #include <chaiscript/language/chaiscript_parser.hpp>
Multi_Test_Chai::Multi_Test_Chai() Multi_Test_Chai::Multi_Test_Chai()
: m_chai(new chaiscript::ChaiScript_Basic(chaiscript::Std_Lib::library(), : m_chai(new chaiscript::ChaiScript_Basic(
std::make_unique<chaiscript::parser::ChaiScript_Parser<chaiscript::eval::Noop_Tracer, chaiscript::optimizer::Optimizer_Default>>())) chaiscript::Std_Lib::library(),
{ std::make_unique<chaiscript::parser::ChaiScript_Parser<chaiscript::eval::Noop_Tracer, chaiscript::optimizer::Optimizer_Default>>())) {
} }
std::shared_ptr<chaiscript::ChaiScript_Basic> Multi_Test_Chai::get_chai() {
std::shared_ptr<chaiscript::ChaiScript_Basic> Multi_Test_Chai::get_chai()
{
return m_chai; return m_chai;
} }

View File

@ -1,14 +1,11 @@
#include <chaiscript/chaiscript_basic.hpp> #include <chaiscript/chaiscript_basic.hpp>
class Multi_Test_Chai class Multi_Test_Chai {
{ public:
public:
Multi_Test_Chai(); Multi_Test_Chai();
std::shared_ptr<chaiscript::ChaiScript_Basic> get_chai(); std::shared_ptr<chaiscript::ChaiScript_Basic> get_chai();
private: private:
std::shared_ptr<chaiscript::ChaiScript_Basic> m_chai; std::shared_ptr<chaiscript::ChaiScript_Basic> m_chai;
}; };

View File

@ -3,8 +3,7 @@
#include <chaiscript/chaiscript_basic.hpp> #include <chaiscript/chaiscript_basic.hpp>
int main() int main() {
{
Multi_Test_Chai chaitest; Multi_Test_Chai chaitest;
Multi_Test_Module chaimodule; Multi_Test_Module chaimodule;

View File

@ -4,13 +4,11 @@
Multi_Test_Module::Multi_Test_Module() noexcept = default; Multi_Test_Module::Multi_Test_Module() noexcept = default;
int Multi_Test_Module::get_module_value() int Multi_Test_Module::get_module_value() {
{
return 0; return 0;
} }
chaiscript::ModulePtr Multi_Test_Module::get_module() chaiscript::ModulePtr Multi_Test_Module::get_module() {
{
chaiscript::ModulePtr module(new chaiscript::Module()); chaiscript::ModulePtr module(new chaiscript::Module());
module->add(chaiscript::fun(&Multi_Test_Module::get_module_value), "get_module_value"); module->add(chaiscript::fun(&Multi_Test_Module::get_module_value), "get_module_value");

View File

@ -1,8 +1,7 @@
#include <chaiscript/chaiscript_basic.hpp> #include <chaiscript/chaiscript_basic.hpp>
class Multi_Test_Module class Multi_Test_Module {
{ public:
public:
static int get_module_value(); static int get_module_value();
Multi_Test_Module() noexcept; Multi_Test_Module() noexcept;

View File

@ -8,20 +8,17 @@
#include <chaiscript/chaiscript_basic.hpp> #include <chaiscript/chaiscript_basic.hpp>
#include <chaiscript/language/chaiscript_parser.hpp> #include <chaiscript/language/chaiscript_parser.hpp>
int expected_value(int num_iters) int expected_value(int num_iters) {
{
int i = 0; int i = 0;
for (int k = 0; k<num_iters * 10; ++k) for (int k = 0; k < num_iters * 10; ++k) {
{
i += k; i += k;
} }
return i; return i;
} }
void do_work(chaiscript::ChaiScript_Basic &c, const size_t id) void do_work(chaiscript::ChaiScript_Basic &c, const size_t id) {
{ try {
try{
std::stringstream ss; std::stringstream ss;
ss << "MyVar" << rand(); ss << "MyVar" << rand();
c.add(chaiscript::var(5), ss.str()); c.add(chaiscript::var(5), ss.str());
@ -34,9 +31,8 @@ void do_work(chaiscript::ChaiScript_Basic &c, const size_t id)
} }
} }
int main() int main() {
{ // Disable deprecation warning for getenv call.
// Disable deprecation warning for getenv call.
#ifdef CHAISCRIPT_MSVC #ifdef CHAISCRIPT_MSVC
#ifdef max // Why Microsoft? why? #ifdef max // Why Microsoft? why?
#undef max #undef max
@ -54,19 +50,17 @@ int main()
std::vector<std::string> usepaths; std::vector<std::string> usepaths;
usepaths.emplace_back(""); usepaths.emplace_back("");
if (usepath) if (usepath) {
{
usepaths.emplace_back(usepath); usepaths.emplace_back(usepath);
} }
std::vector<std::string> modulepaths; std::vector<std::string> modulepaths;
#ifdef CHAISCRIPT_NO_DYNLOAD #ifdef CHAISCRIPT_NO_DYNLOAD
chaiscript::ChaiScript chai(/* unused */modulepaths, usepaths); chaiscript::ChaiScript chai(/* unused */ modulepaths, usepaths);
#else #else
modulepaths.emplace_back(""); modulepaths.emplace_back("");
if (modulepath) if (modulepath) {
{
modulepaths.emplace_back(modulepath); modulepaths.emplace_back(modulepath);
} }
@ -74,43 +68,36 @@ int main()
// to make sure it continues to work // to make sure it continues to work
chaiscript::ChaiScript_Basic chai( chaiscript::ChaiScript_Basic chai(
std::make_unique<chaiscript::parser::ChaiScript_Parser<chaiscript::eval::Noop_Tracer, chaiscript::optimizer::Optimizer_Default>>(), std::make_unique<chaiscript::parser::ChaiScript_Parser<chaiscript::eval::Noop_Tracer, chaiscript::optimizer::Optimizer_Default>>(),
modulepaths,usepaths); modulepaths,
usepaths);
#endif #endif
std::vector<std::shared_ptr<std::thread> > threads; std::vector<std::shared_ptr<std::thread>> threads;
// Ensure at least two, but say only 7 on an 8 core processor // Ensure at least two, but say only 7 on an 8 core processor
size_t num_threads = static_cast<size_t>(std::max(static_cast<int>(std::thread::hardware_concurrency()) - 1, 2)); size_t num_threads = static_cast<size_t>(std::max(static_cast<int>(std::thread::hardware_concurrency()) - 1, 2));
std::cout << "Num threads: " << num_threads << '\n'; std::cout << "Num threads: " << num_threads << '\n';
for (size_t i = 0; i < num_threads; ++i) for (size_t i = 0; i < num_threads; ++i) {
{
threads.push_back(std::make_shared<std::thread>(do_work, std::ref(chai), i)); threads.push_back(std::make_shared<std::thread>(do_work, std::ref(chai), i));
} }
for (size_t i = 0; i < num_threads; ++i) for (size_t i = 0; i < num_threads; ++i) {
{
threads[i]->join(); threads[i]->join();
} }
for (size_t i = 0; i < num_threads; ++i) {
for (size_t i = 0; i < num_threads; ++i)
{
std::stringstream ss; std::stringstream ss;
ss << i; ss << i;
if (chai.eval<int>("getvalue(" + ss.str() + ")") != expected_value(4000)) if (chai.eval<int>("getvalue(" + ss.str() + ")") != expected_value(4000)) {
{
return EXIT_FAILURE; return EXIT_FAILURE;
} }
if (chai.eval<int>("getid(" + ss.str() + ")") != static_cast<int>(i)) if (chai.eval<int>("getid(" + ss.str() + ")") != static_cast<int>(i)) {
{
return EXIT_FAILURE; return EXIT_FAILURE;
} }
} }
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }

View File

@ -11,25 +11,18 @@
#pragma GCC diagnostic ignored "-Wparentheses" #pragma GCC diagnostic ignored "-Wparentheses"
#endif #endif
#include <chaiscript/chaiscript_defines.hpp> #include <chaiscript/chaiscript_defines.hpp>
#include <chaiscript/dispatchkit/type_info.hpp> #include <chaiscript/dispatchkit/type_info.hpp>
#include <iostream>
#include <cstdlib> #include <cstdlib>
#include <iostream>
#define CATCH_CONFIG_MAIN #define CATCH_CONFIG_MAIN
#include "catch.hpp" #include "catch.hpp"
TEST_CASE("Type_Info objects generate expected results") {
TEST_CASE("Type_Info objects generate expected results") const auto test_type
{ = [](const chaiscript::Type_Info &ti, bool t_is_const, bool t_is_pointer, bool t_is_reference, bool t_is_void, bool t_is_undef, bool t_is_arithmetic) {
const auto test_type = [](const chaiscript::Type_Info &ti, bool t_is_const, bool t_is_pointer, bool t_is_reference, bool t_is_void,
bool t_is_undef, bool t_is_arithmetic)
{
CHECK(ti.is_const() == t_is_const); CHECK(ti.is_const() == t_is_const);
CHECK(ti.is_pointer() == t_is_pointer); CHECK(ti.is_pointer() == t_is_pointer);
CHECK(ti.is_reference() == t_is_reference); CHECK(ti.is_reference() == t_is_reference);
@ -49,6 +42,3 @@ TEST_CASE("Type_Info objects generate expected results")
std::cout << "Size of Type_Info " << sizeof(chaiscript::Type_Info) << '\n'; std::cout << "Size of Type_Info " << sizeof(chaiscript::Type_Info) << '\n';
} }