diff --git a/.clang-format b/.clang-format index d0c095e1..8c8b3b26 100644 --- a/.clang-format +++ b/.clang-format @@ -1,98 +1,33 @@ -AccessModifierOffset: -2 -AlignAfterOpenBracket: DontAlign -AlignConsecutiveAssignments: false -AlignConsecutiveDeclarations: false -AlignEscapedNewlines: Left -AlignOperands: true -AlignTrailingComments: false -AllowAllParametersOfDeclarationOnNextLine: false -AllowShortBlocksOnASingleLine: true -AllowShortCaseLabelsOnASingleLine: false -AllowShortFunctionsOnASingleLine: All -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 -CommentPragmas: '^ IWYU pragma:' -CompactNamespaces: false -ConstructorInitializerAllOnOneLineOrOnePerLine: false -ConstructorInitializerIndentWidth: 2 -ContinuationIndentWidth: 2 -Cpp11BracedListStyle: false -DerivePointerAlignment: true -DisableFormat: false -ExperimentalAutoDetectBinPacking: true -FixNamespaceComments: true -ForEachMacros: -- foreach -- Q_FOREACH -- 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 -IndentWrappedFunctionNames: true -JavaScriptQuotes: Leave -JavaScriptWrapImports: true -KeepEmptyLinesAtTheStartOfBlocks: true -Language: Cpp -MacroBlockBegin: '' -MacroBlockEnd: '' -MaxEmptyLinesToKeep: 2 -NamespaceIndentation: Inner -ObjCBlockIndentWidth: 7 -ObjCSpaceAfterProperty: true -ObjCSpaceBeforeProtocolList: false -PointerAlignment: Right -ReflowComments: true -SortIncludes: false -SortUsingDeclarations: false -SpaceAfterCStyleCast: false -SpaceAfterTemplateKeyword: false -SpaceBeforeAssignmentOperators: true -SpaceBeforeParens: ControlStatements -SpaceInEmptyParentheses: false -SpacesBeforeTrailingComments: 0 -SpacesInAngles: false -SpacesInCStyleCastParentheses: false -SpacesInContainerLiterals: true -SpacesInParentheses: false -SpacesInSquareBrackets: false -Standard: Cpp11 -TabWidth: 8 -UseTab: Never - +# clang-format: 11 +AccessModifierOffset: -2 +AlignAfterOpenBracket: Align +AlignConsecutiveBitFields: false +AllowShortBlocksOnASingleLine: false +AllowShortFunctionsOnASingleLine: Inline +AllowShortLambdasOnASingleLine: All +AlwaysBreakTemplateDeclarations: true +BasedOnStyle: WebKit +BinPackArguments: true +BinPackParameters: true +BreakBeforeBraces: Attach +ColumnLimit: 0 +Cpp11BracedListStyle: true +FixNamespaceComments: true +IncludeBlocks: Preserve +IndentCaseLabels: true +IndentPPDirectives: None +IndentWidth: 2 +KeepEmptyLinesAtTheStartOfBlocks: false +NamespaceIndentation: All +PenaltyBreakBeforeFirstCallParameter: 200 +PenaltyBreakComment: 5 +PenaltyBreakFirstLessLess: 50 +PenaltyExcessCharacter: 4 +PointerAlignment: Right +SortIncludes: true +SpaceAfterTemplateKeyword: false +SpaceBeforeCpp11BracedList: false +SpaceInEmptyBlock: false +Standard: Latest +TabWidth: 2 +UseTab: Never \ No newline at end of file diff --git a/include/chaiscript/chaiscript.hpp b/include/chaiscript/chaiscript.hpp index ee040960..871b353b 100644 --- a/include/chaiscript/chaiscript.hpp +++ b/include/chaiscript/chaiscript.hpp @@ -7,25 +7,23 @@ // This is an open source non-commercial project. Dear PVS-Studio, please check it. // PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com - #ifndef CHAISCRIPT_HPP_ #define CHAISCRIPT_HPP_ - - /// @mainpage /// [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. -/// -/// The parts of the ChaiScript API that the average user will be concerned with are contained in the +/// +/// The parts of the ChaiScript API that the average user will be concerned with are contained in the /// chaiscript namespace and the chaiscript::ChaiScript class. /// /// 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"). /// /// ------------------------------------------------------------ -/// +/// /// @sa chaiscript /// @sa chaiscript::ChaiScript /// @sa ChaiScript_Language for Built in Functions @@ -51,16 +49,16 @@ /// - @ref functionobjects /// - @ref threading /// - @ref exceptions -/// -/// +/// +/// /// @subsection basics Basics -/// +/// /// Basic simple example: /// /// ~~~~~~~{.cpp} /// //main.cpp /// #include -/// +/// /// double function(int i, double j) /// { /// return i * j; @@ -72,7 +70,7 @@ /// chai.add(chaiscript::fun(&function), "function"); /// /// double d = chai.eval("function(3, 4.75);"); -/// } +/// } /// ~~~~~~~ /// /// ------------------------------------------------------ @@ -81,14 +79,14 @@ /// /// ChaiScript is a header only library with only one dependency: The /// operating system provided dynamic library loader, which has to be specified on some platforms. -/// +/// /// @subsubsection compilinggcc Compiling with GCC -/// +/// /// To compile the above application on a Unix like operating system (MacOS, Linux) with GCC you need to link /// the dynamic loader. For example: /// /// ~~~~~~~~ -/// gcc main.cpp -I/path/to/chaiscript/headers -ldl +/// gcc main.cpp -I/path/to/chaiscript/headers -ldl /// ~~~~~~~~ /// /// Alternatively, you may compile without threading support. @@ -111,11 +109,11 @@ /// chaiscript::ChaiScript chai; /// chai("print(@"hello world@")"); /// ~~~~~~~~ -/// +/// /// @sa chaiscript::ChaiScript::operator()(const std::string &) /// /// @subsubsection evalmethod Method 'eval' -/// +/// /// The eval method is somewhat more verbose and can be used to get type safely return values /// from the script. /// @@ -129,15 +127,15 @@ /// @sa chaiscript::ChaiScript::eval /// /// @subsubsection evalfilemethod Method 'eval_file' -/// +/// /// The 'eval_file' method loads a file from disk and executes the script in it -/// +/// /// ~~~~~~~~{.cpp} /// chaiscript::ChaiScript chai; /// chai.eval_file("myfile.chai"); /// std::string result = chai.eval_file("myfile.chai") // extract the last value returned from the file /// ~~~~~~~~ -/// +/// /// @sa chaiscript::ChaiScript::eval_file /// /// -------------------------------------------------- @@ -149,10 +147,10 @@ /// @subsubsection adding_objects Adding Objects /// /// Named objects can be created with the chaiscript::var function. Note: adding a object -/// adds it to the current thread scope, not to a global scope. If you have multiple +/// adds it to the current thread scope, not to a global scope. If you have multiple /// threads that need to access the same variables you will need to add them /// separately for each thread, from the thread itself. -/// +/// /// ~~~~~~~~~{.cpp} /// using namespace chaiscript; /// ChaiScript chai; @@ -167,23 +165,23 @@ /// chai.add(const_var(i), "i"); /// chai("i = 5"); // exception throw, cannot assign const var /// ~~~~~~~~~ -/// +/// /// Named variables can only be accessed from the context they are created in. -/// If you want a global variable, it must be const, and created with the +/// If you want a global variable, it must be const, and created with the /// chaiscript::ChaiScript::add_global_const function. /// /// ~~~~~~~~~{.cpp} /// chai.add_global_const(const_var(i), "i"); /// chai("def somefun() { print(i); }; somefun();"); /// ~~~~~~~~~ -/// +/// /// @subsubsection adding_functions Adding Functions -/// +/// /// Functions, methods and members are all added using the same function: chaiscript::fun. /// /// ~~~~~~~~~{.cpp} /// using namespace chaiscript; -/// +/// /// class MyClass { /// public: /// int memberdata; @@ -193,7 +191,7 @@ /// void overloadedmethod(); /// void overloadedmethod(const std::string &); /// }; -/// +/// /// ChaiScript chai; /// chai.add(fun(&MyClass::memberdata), "memberdata"); /// chai.add(fun(&MyClass::method), "method"); @@ -208,7 +206,7 @@ /// ~~~~~~~~~ /// /// There are also shortcuts built into chaiscript::fun for binding up to the first two parameters of the function. -/// +/// /// ~~~~~~~~~{.cpp} /// MyClass obj; /// chai.add(fun(&MyClass::method, &obj), "method"); @@ -220,7 +218,7 @@ /// @subsubsection addingtypeinfo Adding Type Info /// /// ChaiScript will automatically support any type implicitly provided to it in the form -/// of objects and function parameters / return types. However, it can be nice to let ChaiScript +/// of objects and function parameters / return types. However, it can be nice to let ChaiScript /// know more details about the types you are giving it. For instance, the "clone" functionality /// cannot work unless there is a copy constructor registered and the name of the type is known /// (so that ChaiScript can look up the copy constructor). @@ -232,23 +230,23 @@ /// ~~~~~~~~ /// /// @subsubsection adding_modules Adding Modules -/// +/// /// Modules are holders for collections of ChaiScript registrations. /// /// ~~~~~~~~{.cpp} /// ModulePtr module = get_sum_module(); /// chai.add(module); /// ~~~~~~~~ -/// +/// /// @sa chaiscript::Module /// /// ----------------------------------------------------------------------- /// /// @subsection operatoroverloading Operator Overloading -/// +/// /// Operators are just like any other function in ChaiScript, to overload an operator, simply register it. -/// -/// ~~~~~~~~{.cpp} +/// +/// ~~~~~~~~{.cpp} /// class MyClass { /// MyClass operator+(const MyClass &) const; /// }; @@ -270,7 +268,7 @@ /// ----------------------------------------------------------------------- /// /// @subsection add_class Class Helper Utility -/// +/// /// Much of the work of adding new classes to ChaiScript can be reduced with the help /// of the add_class helper utility. /// @@ -295,8 +293,8 @@ /// constructor() }, /// { {fun(&Test::function), "function"}, /// {fun(&Test::function2), "function2"}, -/// {fun(&Test::function2), "function3"} -/// {fun(static_cast(&Test::functionOverload)), "functionOverload"} +/// {fun(&Test::function2), "function3"} +/// {fun(static_cast(&Test::functionOverload)), "functionOverload"} /// {fun(static_cast(&Test::functionOverload)), "functionOverload"} } /// ); /// @@ -305,7 +303,7 @@ /// chai.add(m); /// } /// ~~~~~~~~ -/// +/// /// @sa @ref adding_modules /// /// ----------------------------------------------------------------------- @@ -315,8 +313,8 @@ /// As much as possible, ChaiScript attempts to convert between &, *, const &, const *, std::shared_ptr, /// std::shared_ptr, std::reference_wrapper, std::reference_wrapper 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). -/// Const may be added, but never removed. +/// 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). 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. /// @@ -359,16 +357,16 @@ /// chai("fun8(i)"); /// chai("fun9(i)"); /// chai("fun10(i)"); -/// } +/// } /// ~~~~~~~~ /// -/// See the unit test unittests/boxed_cast_test.cpp for a complete breakdown of the automatic casts that +/// See the unit test unittests/boxed_cast_test.cpp for a complete breakdown of the automatic casts that /// available and tested. -/// +/// /// ----------------------------------------------------------------------- /// /// @subsection baseclasses Base Classes -/// +/// /// ChaiScript supports handling of passing a derived class object to a function expecting a base class object. /// For the process to work, the base/derived relationship must be registered with the engine. /// @@ -387,7 +385,7 @@ /// chai("myfunction(d)"); /// } /// ~~~~~~~~ -/// +/// /// ----------------------------------------------------------------------- /// /// @@ -401,7 +399,7 @@ /// { /// t_func("bob"); /// } -/// +/// /// int main() /// { /// chaiscript::ChaiScript chai; @@ -413,16 +411,16 @@ /// f(); // call the ChaiScript function dump_system, from C++ /// } /// ~~~~~~~~ -/// +/// /// ----------------------------------------------------------------------- /// /// /// @subsection threading Threading -/// +/// /// Thread safety is automatically handled within the ChaiScript system. Objects can be added /// and scripts executed from multiple threads. For each thread that executes scripts, a new /// context is created and managed by the engine. -/// +/// /// Thread safety can be disabled by defining CHAISCRIPT_NO_THREADS when using the library. /// /// Disabling thread safety increases performance in many cases. @@ -431,10 +429,10 @@ /// /// /// @subsection exceptions Exception Handling -/// +/// /// @subsubsection exceptionsbasics Exception Handling Basics /// -/// Exceptions can be thrown in ChaiScript and caught in C++ or thrown in C++ and caught in +/// Exceptions can be thrown in ChaiScript and caught in C++ or thrown in C++ and caught in /// ChaiScript. /// /// ~~~~~~~~{.cpp} @@ -442,14 +440,14 @@ /// { /// throw std::runtime_error("err"); /// } -/// +/// /// int main() /// { /// // Throw in C++, catch in ChaiScript /// chaiscript::ChaiScript chai; /// chai.add(chaiscript::fun(&throwexception), "throwexception"); /// chai("try { throwexception(); } catch (e) { print(e.what()); }"); // prints "err" -/// +/// /// // Throw in ChaiScript, catch in C++ /// try { /// chai("throw(1)"); @@ -459,18 +457,19 @@ /// } /// } /// ~~~~~~~~ -/// +/// /// @subsubsection exceptionsautomatic Exception Handling Automatic Unboxing /// -/// As an alternative to the manual unboxing of exceptions shown above, exception specifications allow the user to tell -/// ChaiScript what possible exceptions are expected from the script being executed. +/// As an alternative to the manual unboxing of exceptions shown above, exception specifications allow the user to tell +/// ChaiScript what possible exceptions are expected from the script being executed. /// /// Example: /// ~~~~~~~~{.cpp} /// chaiscript::ChaiScript chai; /// /// try { -/// chai.eval("throw(runtime_error(@"error@"))", chaiscript::exception_specification()); +/// chai.eval("throw(runtime_error(@"error@"))", chaiscript::exception_specification()); /// } catch (const double e) { /// } catch (int) { /// } catch (float) { @@ -480,11 +479,9 @@ /// } /// ~~~~~~~~ /// -/// @sa chaiscript::Exception_Handler for details on automatic exception unboxing +/// @sa chaiscript::Exception_Handler for details on automatic exception unboxing /// @sa chaiscript::exception_specification - - /// @page LangObjectSystemRef ChaiScript Language Object Model Reference /// /// @@ -495,7 +492,7 @@ /// attr Rectangle::width /// def Rectangle::Rectangle() { this.height = 10; this.width = 20 } /// def Rectangle::area() { this.height * this.width } -/// +/// /// var rect = Rectangle() /// rect.height = 30 /// print(rect.area()) @@ -521,7 +518,7 @@ /// @page LangInPlaceRef ChaiScript Language In-Place Creation Reference /// @section inplacevector Vector -/// +/// /// ~~~~~~~~~ /// In-place Vector ::= "[" [expression ("," expression)*] "]" /// ~~~~~~~~~ @@ -541,9 +538,9 @@ /// ~~~~~~~~ /// @page LangGettingStarted ChaiScript Language Getting Started -/// +/// /// ChaiScript is a simple language that should feel familiar to anyone who knows -/// C++ or ECMAScript (JavaScript). +/// C++ or ECMAScript (JavaScript). /// /// ----------------------------------------------------------------------- /// @@ -575,10 +572,10 @@ /// @section chaiscriptifs Conditionals /// /// If statements work as expected -/// +/// /// ~~~~~~~~ /// var b = true; -/// +/// /// if (b) { /// // do something /// } else if (c < 10) { @@ -593,9 +590,9 @@ /// ----------------------------------------------------------------------- /// /// @section chaiscriptfunctions Functions -/// +/// /// Functions are defined with the def keyword -/// +/// /// ~~~~~~~~ /// def myfun(x) { print(x); } /// @@ -612,7 +609,7 @@ /// eval> myfun2(12) /// 10 or greater /// ~~~~~~~~ -/// +/// /// @sa @ref keyworddef /// @sa @ref keywordattr /// @sa @ref LangObjectSystemRef @@ -620,7 +617,7 @@ /// ----------------------------------------------------------------------- /// /// @section chaiscriptfunctionobjects Function Objects -/// +/// /// Functions are first class types in ChaiScript and can be used as variables. /// /// ~~~~~~~~ @@ -628,8 +625,8 @@ /// eval> p(1); /// 1 /// ~~~~~~~~ -/// -/// They can also be passed to functions. +/// +/// They can also be passed to functions. /// /// ~~~~~~~~ /// eval> def callfunc(f, lhs, rhs) { return f(lhs, rhs); } @@ -639,7 +636,7 @@ /// ~~~~~~~~ /// /// Operators can also be treated as functions by using the back tick operator. Building on the above example: -/// +/// /// ~~~~~~~~ /// eval> callfunc(`+`, 1, 4); /// 5 @@ -652,7 +649,6 @@ /// @sa @ref LangKeywordRef /// @sa ChaiScript_Language for Built in Functions - /// @page LangKeywordRef ChaiScript Language Keyword Reference /// /// @@ -660,8 +656,8 @@ /// /// @section keywordattr attr /// Defines a ChaiScript object attribute -/// -/// ~~~~~~~~ +/// +/// ~~~~~~~~ /// Attribute Definition ::= "attr" class_name "::" attribute_name /// ~~~~~~~~ /// @@ -690,7 +686,7 @@ /// ~~~~~~~~ /// /// @sa @ref keywordfor -/// @sa @ref keywordwhile +/// @sa @ref keywordwhile /// /// /// ----------------------------------------------------------------------- @@ -702,7 +698,7 @@ /// Function Definition ::= "def" identifier "(" [[type] arg ("," [type] arg)*] ")" [":" guard] block /// Method Definition ::= "def" class_name "::" method_name "(" [[type] arg ("," [type] arg)*] ")" [":" guard] block /// ~~~~~~~~ -/// +/// /// identifier: name of function. Required. /// args: comma-delimited list of parameter names with optional type specifiers. Optional. /// guards: guarding statement that act as a prerequisite for the function. Optional. @@ -722,7 +718,7 @@ /// ----------------------------------------------------------------------- /// /// @section keywordelse else -/// @sa @ref keywordif +/// @sa @ref keywordif /// /// /// ----------------------------------------------------------------------- @@ -762,7 +758,7 @@ /// Else If Block ::= "else if" "(" condition ")" block /// Else Block ::= "else" block /// ~~~~~~~~ -/// +/// /// _Example_ /// /// ~~~~~~~~ @@ -780,8 +776,8 @@ /// /// @section keywordtry try /// ~~~~~~~~ -/// Try Block ::= "try" block -/// ("catch" ["(" [type] variable ")"] [":" guards] block)+ +/// Try Block ::= "try" block +/// ("catch" ["(" [type] variable ")"] [":" guards] block)+ /// ["finally" block] /// ~~~~~~~~ /// @@ -791,7 +787,7 @@ /// ----------------------------------------------------------------------- /// /// @section keywordwhile while -/// +/// /// Begins a conditional block of code that loops 0 or more times, as long as the condition is true /// /// ~~~~~~~~ @@ -804,7 +800,7 @@ /// ----------------------------------------------------------------------- /// /// @section keywordvar var -/// +/// /// Defines a variable /// /// ~~~~~~~~ @@ -813,7 +809,6 @@ /// /// Synonym for @ref keywordauto - /// @namespace chaiscript /// @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. #include "chaiscript_basic.hpp" -#include "language/chaiscript_parser.hpp" #include "chaiscript_stdlib.hpp" +#include "language/chaiscript_parser.hpp" - -namespace chaiscript -{ - class ChaiScript : public ChaiScript_Basic - { - public: - ChaiScript(std::vector t_modulepaths = {}, - std::vector t_usepaths = {}, - std::vector t_opts = chaiscript::default_options()) - : ChaiScript_Basic( - chaiscript::Std_Lib::library(), - std::make_unique>(), - std::move(t_modulepaths), std::move(t_usepaths), std::move(t_opts)) - { - } +namespace chaiscript { + class ChaiScript : public ChaiScript_Basic { + public: + ChaiScript(std::vector t_modulepaths = {}, + std::vector t_usepaths = {}, + std::vector t_opts = chaiscript::default_options()) + : ChaiScript_Basic(chaiscript::Std_Lib::library(), + std::make_unique>(), + std::move(t_modulepaths), + std::move(t_usepaths), + std::move(t_opts)) { + } }; -} +} // namespace chaiscript #endif /* CHAISCRIPT_HPP_ */ diff --git a/include/chaiscript/chaiscript_basic.hpp b/include/chaiscript/chaiscript_basic.hpp index 0e638450..a75c731b 100644 --- a/include/chaiscript/chaiscript_basic.hpp +++ b/include/chaiscript/chaiscript_basic.hpp @@ -9,13 +9,13 @@ #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/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_eval.hpp" // This file includes all of the basic requirements for ChaiScript, // 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 - - #endif /* CHAISCRIPT_BASIC_HPP_ */ diff --git a/include/chaiscript/chaiscript_defines.hpp b/include/chaiscript/chaiscript_defines.hpp index 68dee8b6..e01aadd3 100644 --- a/include/chaiscript/chaiscript_defines.hpp +++ b/include/chaiscript/chaiscript_defines.hpp @@ -20,10 +20,10 @@ static_assert(_MSC_FULL_VER >= 190024210, "Visual C++ 2015 Update 3 or later req #define CHAISCRIPT_COMPILER_VERSION __VERSION__ #endif -#include #include +#include -#if defined( _LIBCPP_VERSION ) +#if defined(_LIBCPP_VERSION) #define CHAISCRIPT_LIBCPP #endif @@ -49,16 +49,14 @@ static_assert(_MSC_FULL_VER >= 190024210, "Visual C++ 2015 Update 3 or later req #endif #endif - #if defined(__llvm__) #define CHAISCRIPT_CLANG #endif - -#ifdef CHAISCRIPT_HAS_DECLSPEC +#ifdef CHAISCRIPT_HAS_DECLSPEC #define CHAISCRIPT_MODULE_EXPORT extern "C" __declspec(dllexport) #else -#define CHAISCRIPT_MODULE_EXPORT extern "C" +#define CHAISCRIPT_MODULE_EXPORT extern "C" #endif #if defined(CHAISCRIPT_MSVC) || (defined(__GNUC__) && __GNUC__ >= 5) || defined(CHAISCRIPT_CLANG) @@ -71,9 +69,9 @@ static_assert(_MSC_FULL_VER >= 190024210, "Visual C++ 2015 Update 3 or later req #define CHAISCRIPT_DEBUG false #endif +#include #include #include -#include namespace chaiscript { constexpr static const int version_major = 7; @@ -84,166 +82,129 @@ namespace chaiscript { constexpr static const char *compiler_name = CHAISCRIPT_COMPILER_NAME; constexpr static const bool debug_build = CHAISCRIPT_DEBUG; - template - inline std::shared_ptr make_shared(Arg && ... arg) - { + template + inline std::shared_ptr make_shared(Arg &&...arg) { #ifdef CHAISCRIPT_USE_STD_MAKE_SHARED return std::make_shared(std::forward(arg)...); #else - return std::shared_ptr(static_cast(new D(std::forward(arg)...))); + return std::shared_ptr(static_cast(new D(std::forward(arg)...))); #endif } - template - inline std::unique_ptr make_unique(Arg && ... arg) - { + template + inline std::unique_ptr make_unique(Arg &&...arg) { #ifdef CHAISCRIPT_USE_STD_MAKE_SHARED return std::make_unique(std::forward(arg)...); #else - return std::unique_ptr(static_cast(new D(std::forward(arg)...))); + return std::unique_ptr(static_cast(new D(std::forward(arg)...))); #endif } struct Build_Info { - [[nodiscard]] constexpr static int version_major() noexcept - { - return chaiscript::version_major; - } + [[nodiscard]] constexpr static int version_major() noexcept { return chaiscript::version_major; } - [[nodiscard]] constexpr static int version_minor() noexcept - { - return chaiscript::version_minor; - } + [[nodiscard]] constexpr static int version_minor() noexcept { return chaiscript::version_minor; } - [[nodiscard]] constexpr static int version_patch() noexcept - { - return chaiscript::version_patch; - } + [[nodiscard]] constexpr static int version_patch() noexcept { 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()); } - [[nodiscard]] static std::string compiler_id() - { - return compiler_name() + '-' + compiler_version(); - } + [[nodiscard]] static std::string compiler_id() { return compiler_name() + '-' + compiler_version(); } - [[nodiscard]] static std::string build_id() - { - return compiler_id() + (debug_build()?"-Debug":"-Release"); - } + [[nodiscard]] static std::string build_id() { return compiler_id() + (debug_build() ? "-Debug" : "-Release"); } - [[nodiscard]] static std::string compiler_version() - { - return chaiscript::compiler_version; - } + [[nodiscard]] static std::string compiler_version() { return chaiscript::compiler_version; } - [[nodiscard]] static std::string compiler_name() - { - return chaiscript::compiler_name; - } + [[nodiscard]] static std::string compiler_name() { return chaiscript::compiler_name; } - [[nodiscard]] constexpr static bool debug_build() noexcept - { - return chaiscript::debug_build; - } + [[nodiscard]] constexpr static bool debug_build() noexcept { return chaiscript::debug_build; } }; - template - [[nodiscard]] constexpr auto parse_num(const std::string_view t_str) noexcept -> typename std::enable_if::value, T>::type - { - T t = 0; - for (const auto c : t_str) { - if (c < '0' || c > '9') { - return t; - } - t *= 10; - t += c - '0'; + [[nodiscard]] constexpr auto parse_num(const std::string_view t_str) noexcept -> typename std::enable_if::value, T>::type { + T t = 0; + for (const auto c : t_str) { + if (c < '0' || c > '9') { + return t; } - return t; + t *= 10; + t += c - '0'; } + return t; + } + template + [[nodiscard]] auto parse_num(const std::string_view t_str) -> typename std::enable_if::value, T>::type { + T t = 0; + T base{}; + T decimal_place = 0; + int exponent = 0; - template - [[nodiscard]] auto parse_num(const std::string_view t_str) -> typename std::enable_if::value, T>::type - { - T t = 0; - T base{}; - T decimal_place = 0; - int exponent = 0; - - for (const auto c : t_str) { - switch (c) - { - case '.': - decimal_place = 10; - break; - case 'e': - case 'E': - exponent = 1; - decimal_place = 0; - base = t; - t = 0; - break; - case '-': - exponent = -1; - break; - case '+': - break; - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - if (decimal_place < 10) { - t *= 10; - t += static_cast(c - '0'); - } - else { - t += static_cast(c - '0') / decimal_place; - decimal_place *= 10; - } - break; - default: - break; + for (const auto c : t_str) { + switch (c) { + case '.': + decimal_place = 10; + break; + case 'e': + case 'E': + exponent = 1; + decimal_place = 0; + base = t; + t = 0; + break; + case '-': + exponent = -1; + break; + case '+': + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (decimal_place < 10) { + t *= 10; + t += static_cast(c - '0'); + } else { + t += static_cast(c - '0') / decimal_place; + decimal_place *= 10; } - } - return exponent ? base * std::pow(T(10), t * static_cast(exponent)) : t; + break; + default: + break; + } } + return exponent ? base * std::pow(T(10), t * static_cast(exponent)) : t; + } struct str_equal { - [[nodiscard]] bool operator()(const std::string &t_lhs, const std::string &t_rhs) const noexcept { - return t_lhs == t_rhs; - } + [[nodiscard]] bool operator()(const std::string &t_lhs, const std::string &t_rhs) const noexcept { return t_lhs == t_rhs; } template - [[nodiscard]] constexpr bool operator()(const LHS &t_lhs, const RHS &t_rhs) const noexcept { - return std::equal(t_lhs.begin(), t_lhs.end(), t_rhs.begin(), t_rhs.end()); - } - struct is_transparent{}; + [[nodiscard]] constexpr bool operator()(const LHS &t_lhs, const RHS &t_rhs) const noexcept { + return std::equal(t_lhs.begin(), t_lhs.end(), t_rhs.begin(), t_rhs.end()); + } + struct is_transparent { + }; }; - struct str_less { - [[nodiscard]] bool operator()(const std::string &t_lhs, const std::string &t_rhs) const noexcept { - return t_lhs < t_rhs; - } + [[nodiscard]] bool operator()(const std::string &t_lhs, const std::string &t_rhs) const noexcept { return t_lhs < t_rhs; } template - [[nodiscard]] constexpr bool operator()(const LHS &t_lhs, const RHS &t_rhs) const noexcept { - return std::lexicographical_compare(t_lhs.begin(), t_lhs.end(), t_rhs.begin(), t_rhs.end()); - } - struct is_transparent{}; + [[nodiscard]] constexpr bool operator()(const LHS &t_lhs, const RHS &t_rhs) const noexcept { + return std::lexicographical_compare(t_lhs.begin(), t_lhs.end(), t_rhs.begin(), t_rhs.end()); + } + struct is_transparent { + }; }; - enum class Options - { + enum class Options { No_Load_Modules, Load_Modules, No_External_Scripts, @@ -251,44 +212,33 @@ namespace chaiscript { }; template - struct is_nothrow_forward_constructible - : std::bool_constant()})> - { + struct is_nothrow_forward_constructible : std::bool_constant()})> { }; - template< class From, class To > - static inline constexpr bool is_nothrow_forward_constructible_v - = is_nothrow_forward_constructible::value; + template + static inline constexpr bool is_nothrow_forward_constructible_v = is_nothrow_forward_constructible::value; - template - [[nodiscard]] constexpr auto make_container(T && ... t) - { + template + [[nodiscard]] constexpr auto make_container(T &&...t) { Container c; c.reserve(sizeof...(t)); (c.push_back(std::forward(t)), ...); return c; } - - template - [[nodiscard]] auto make_vector(T &&... t) -> std::vector...>> - { - using container_type = - std::vector...>>; + template + [[nodiscard]] auto make_vector(T &&...t) -> std::vector...>> { + using container_type = std::vector...>>; return make_container(std::forward(t)...); } - - - [[nodiscard]] inline std::vector default_options() - { + [[nodiscard]] inline std::vector default_options() { #ifdef CHAISCRIPT_NO_DYNLOAD return {Options::No_Load_Modules, Options::External_Scripts}; #else return {Options::Load_Modules, Options::External_Scripts}; #endif } -} +} // namespace chaiscript #endif - diff --git a/include/chaiscript/chaiscript_stdlib.hpp b/include/chaiscript/chaiscript_stdlib.hpp index 2407fcf0..5cb4fa68 100644 --- a/include/chaiscript/chaiscript_stdlib.hpp +++ b/include/chaiscript/chaiscript_stdlib.hpp @@ -19,53 +19,48 @@ #include "dispatchkit/function_call.hpp" //#include "dispatchkit/dispatchkit.hpp" -#include "dispatchkit/operators.hpp" #include "dispatchkit/bootstrap.hpp" #include "dispatchkit/bootstrap_stl.hpp" +#include "dispatchkit/operators.hpp" //#include "dispatchkit/boxed_value.hpp" -#include "language/chaiscript_prelude.hpp" #include "dispatchkit/register_function.hpp" +#include "language/chaiscript_prelude.hpp" #include "utility/json_wrap.hpp" #ifndef CHAISCRIPT_NO_THREADS #include #endif - /// @file /// /// This file generates the standard library that normal ChaiScript usage requires. -namespace chaiscript -{ - class Std_Lib - { - public: +namespace chaiscript { + class Std_Lib { + public: + [[nodiscard]] static ModulePtr library() { + auto lib = std::make_shared(); + bootstrap::Bootstrap::bootstrap(*lib); - [[nodiscard]] static ModulePtr library() - { - auto lib = std::make_shared(); - bootstrap::Bootstrap::bootstrap(*lib); - - bootstrap::standard_library::vector_type >("Vector", *lib); - bootstrap::standard_library::string_type("string", *lib); - bootstrap::standard_library::map_type >("Map", *lib); - bootstrap::standard_library::pair_type >("Pair", *lib); + bootstrap::standard_library::vector_type>("Vector", *lib); + bootstrap::standard_library::string_type("string", *lib); + bootstrap::standard_library::map_type>("Map", *lib); + bootstrap::standard_library::pair_type>("Pair", *lib); #ifndef CHAISCRIPT_NO_THREADS - bootstrap::standard_library::future_type>("future", *lib); - lib->add(chaiscript::fun([](const std::function &t_func){ return std::async(std::launch::async, t_func);}), "async"); + bootstrap::standard_library::future_type>("future", *lib); + lib->add(chaiscript::fun( + [](const std::function &t_func) { return std::async(std::launch::async, t_func); }), + "async"); #endif - json_wrap::library(*lib); + json_wrap::library(*lib); - lib->eval(ChaiScript_Prelude::chaiscript_prelude() /*, "standard prelude"*/ ); - - return lib; - } + lib->eval(ChaiScript_Prelude::chaiscript_prelude() /*, "standard prelude"*/); + return lib; + } }; -} +} // namespace chaiscript #endif - diff --git a/include/chaiscript/chaiscript_threading.hpp b/include/chaiscript/chaiscript_threading.hpp index 9bfa44fc..d0145c87 100644 --- a/include/chaiscript/chaiscript_threading.hpp +++ b/include/chaiscript/chaiscript_threading.hpp @@ -7,20 +7,18 @@ // This is an open source non-commercial project. Dear PVS-Studio, please check it. // PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com - #ifndef CHAISCRIPT_THREADING_HPP_ #define CHAISCRIPT_THREADING_HPP_ - #include #ifndef CHAISCRIPT_NO_THREADS -#include #include #include +#include #else #ifndef CHAISCRIPT_NO_THREADS_WARNING -#pragma message ("ChaiScript is compiling without thread safety.") +#pragma message("ChaiScript is compiling without thread safety.") #endif #endif @@ -34,143 +32,102 @@ /// It also has the side effect that the chaiscript::ChaiScript object may not be accessed from more than /// one thread simultaneously. -namespace chaiscript -{ - namespace detail - { - /// 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 - { - +/// 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 chaiscript::detail::threading { #ifndef CHAISCRIPT_NO_THREADS - template - using unique_lock = std::unique_lock; + template + using unique_lock = std::unique_lock; - template - using shared_lock = std::shared_lock; + template + using shared_lock = std::shared_lock; - template - using lock_guard = std::lock_guard; + template + using lock_guard = std::lock_guard; + using std::shared_mutex; - using std::shared_mutex; + using std::mutex; - using std::mutex; + using std::recursive_mutex; - using std::recursive_mutex; + /// 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. + template + class Thread_Storage { + public: + Thread_Storage() = default; + Thread_Storage(const Thread_Storage &) = delete; + Thread_Storage(Thread_Storage &&) = delete; + Thread_Storage &operator=(const Thread_Storage &) = delete; + Thread_Storage &operator=(Thread_Storage &&) = delete; - /// 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. - template - class Thread_Storage - { - public: - Thread_Storage() = default; - Thread_Storage(const Thread_Storage &) = delete; - Thread_Storage(Thread_Storage &&) = delete; - Thread_Storage &operator=(const Thread_Storage &) = delete; - Thread_Storage &operator=(Thread_Storage &&) = delete; + ~Thread_Storage() { t().erase(this); } - ~Thread_Storage() - { - t().erase(this); - } + inline const T *operator->() const noexcept { return &(t()[this]); } - inline const T *operator->() const noexcept - { - return &(t()[this]); - } + inline const T &operator*() const noexcept { return t()[this]; } - inline const T &operator*() const noexcept - { - return t()[this]; - } + inline T *operator->() noexcept { return &(t()[this]); } - inline T *operator->() noexcept - { - return &(t()[this]); - } + inline T &operator*() noexcept { return t()[this]; } - inline T &operator*() noexcept - { - return t()[this]; - } + void *m_key; - - void *m_key; - - private: - /// todo: is it valid to make this noexcept? The allocation could fail, but if it - /// does there is no possible way to recover - static std::unordered_map &t() noexcept - { - static thread_local std::unordered_map my_t; - return my_t; - } - }; + private: + /// todo: is it valid to make this noexcept? The allocation could fail, but if it + /// does there is no possible way to recover + static std::unordered_map &t() noexcept { + static thread_local std::unordered_map my_t; + return my_t; + } + }; #else // threading disabled - template - class unique_lock - { - public: - constexpr explicit unique_lock(T &) noexcept {} - constexpr void lock() noexcept {} - constexpr void unlock() noexcept {} - }; + template + class unique_lock { + public: + constexpr explicit unique_lock(T &) noexcept {} + constexpr void lock() noexcept {} + constexpr void unlock() noexcept {} + }; - template - class shared_lock - { - public: - constexpr explicit shared_lock(T &) noexcept {} - constexpr void lock() noexcept {} - constexpr void unlock() noexcept {} - }; + template + class shared_lock { + public: + constexpr explicit shared_lock(T &) noexcept {} + constexpr void lock() noexcept {} + constexpr void unlock() noexcept {} + }; - template - class lock_guard - { - public: - constexpr explicit lock_guard(T &) noexcept {} - }; + template + class lock_guard { + public: + constexpr explicit lock_guard(T &) noexcept {} + }; - class shared_mutex { }; + class shared_mutex { + }; - class recursive_mutex {}; + class recursive_mutex { + }; + template + class Thread_Storage { + public: + constexpr explicit Thread_Storage() noexcept {} - template - class Thread_Storage - { - public: - constexpr explicit Thread_Storage() noexcept - { - } + constexpr inline T *operator->() const noexcept { return &obj; } - constexpr inline T *operator->() const noexcept - { - return &obj; - } + constexpr inline T &operator*() const noexcept { return obj; } - constexpr inline T &operator*() const noexcept - { - return obj; - } - - private: - mutable T obj; - }; + private: + mutable T obj; + }; #endif - } - } -} - - +} // namespace chaiscript::detail::threading #endif - diff --git a/include/chaiscript/dispatchkit/any.hpp b/include/chaiscript/dispatchkit/any.hpp index f8f94f26..0b1f5b13 100644 --- a/include/chaiscript/dispatchkit/any.hpp +++ b/include/chaiscript/dispatchkit/any.hpp @@ -11,139 +11,105 @@ namespace chaiscript { namespace detail { - namespace exception - { + namespace exception { /// \brief Thrown in the event that an Any cannot be cast to the desired type /// /// It is used internally during function dispatch. /// /// \sa chaiscript::detail::Any - class bad_any_cast : public std::bad_cast - { - public: - /// \brief Description of what error occurred - const char * what() const noexcept override - { - return "bad any cast"; - } + class bad_any_cast : public std::bad_cast { + public: + /// \brief Description of what error occurred + const char *what() const noexcept override { return "bad any cast"; } }; - } - + } // namespace exception class Any { - private: - struct Data - { - constexpr explicit Data(const std::type_info &t_type) noexcept - : m_type(t_type) - { - } - - Data &operator=(const Data &) = delete; - - virtual ~Data() noexcept = default; - - virtual void *data() noexcept = 0; - - const std::type_info &type() const noexcept - { - return m_type; - } - - virtual std::unique_ptr clone() const = 0; - const std::type_info &m_type; - }; - - template - struct Data_Impl : Data - { - explicit Data_Impl(T t_type) - : Data(typeid(T)), - m_data(std::move(t_type)) - { - } - - void *data() noexcept override - { - return &m_data; - } - - std::unique_ptr clone() const override - { - return std::make_unique>(m_data); - } - - Data_Impl &operator=(const Data_Impl&) = delete; - - T m_data; - }; - - std::unique_ptr m_data; - - public: - // construct/copy/destruct - constexpr Any() noexcept = default; - Any(Any &&) noexcept = default; - Any &operator=(Any &&t_any) = default; - - Any(const Any &t_any) - : m_data(t_any.empty() ? nullptr : t_any.m_data->clone()) - { + private: + struct Data { + constexpr explicit Data(const std::type_info &t_type) noexcept + : m_type(t_type) { } - template>>> - explicit Any(ValueType &&t_value) - : m_data(std::make_unique>>(std::forward(t_value))) - { + Data &operator=(const Data &) = delete; + + virtual ~Data() noexcept = default; + + virtual void *data() noexcept = 0; + + const std::type_info &type() const noexcept { return m_type; } + + virtual std::unique_ptr clone() const = 0; + const std::type_info &m_type; + }; + + template + struct Data_Impl : Data { + explicit Data_Impl(T t_type) + : Data(typeid(T)) + , m_data(std::move(t_type)) { } + void *data() noexcept override { return &m_data; } - Any & operator=(const Any &t_any) - { - Any copy(t_any); - swap(copy); - return *this; + std::unique_ptr clone() const override { return std::make_unique>(m_data); } + + Data_Impl &operator=(const Data_Impl &) = delete; + + T m_data; + }; + + std::unique_ptr m_data; + + public: + // construct/copy/destruct + constexpr Any() noexcept = default; + Any(Any &&) noexcept = default; + Any &operator=(Any &&t_any) = default; + + Any(const Any &t_any) + : m_data(t_any.empty() ? nullptr : t_any.m_data->clone()) { + } + + template>>> + explicit Any(ValueType &&t_value) + : m_data(std::make_unique>>(std::forward(t_value))) { + } + + Any &operator=(const Any &t_any) { + Any copy(t_any); + swap(copy); + return *this; + } + + template + ToType &cast() const { + if (m_data && typeid(ToType) == m_data->type()) { + return *static_cast(m_data->data()); + } else { + throw chaiscript::detail::exception::bad_any_cast(); } + } - template - ToType &cast() const - { - if (m_data && typeid(ToType) == m_data->type()) - { - return *static_cast(m_data->data()); - } else { - throw chaiscript::detail::exception::bad_any_cast(); - } - } + // modifiers + Any &swap(Any &t_other) { + std::swap(t_other.m_data, m_data); + return *this; + } + // queries + bool empty() const noexcept { return !static_cast(m_data); } - // modifiers - Any & swap(Any &t_other) - { - std::swap(t_other.m_data, m_data); - return *this; - } - - // queries - bool empty() const noexcept - { - return !static_cast(m_data); - } - - const std::type_info & type() const noexcept - { - if (m_data) { - return m_data->type(); - } else { - return typeid(void); - } + const std::type_info &type() const noexcept { + if (m_data) { + return m_data->type(); + } else { + return typeid(void); } + } }; - } -} + } // namespace detail +} // namespace chaiscript #endif - - diff --git a/include/chaiscript/dispatchkit/bad_boxed_cast.hpp b/include/chaiscript/dispatchkit/bad_boxed_cast.hpp index 9a779020..d3b22167 100644 --- a/include/chaiscript/dispatchkit/bad_boxed_cast.hpp +++ b/include/chaiscript/dispatchkit/bad_boxed_cast.hpp @@ -7,7 +7,6 @@ // This is an open source non-commercial project. Dear PVS-Studio, please check it. // PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com - #ifndef CHAISCRIPT_BAD_BOXED_CAST_HPP_ #define CHAISCRIPT_BAD_BOXED_CAST_HPP_ @@ -19,56 +18,47 @@ #include "type_info.hpp" namespace chaiscript { -class Type_Info; -} // namespace chaiscript + class Type_Info; +} // namespace chaiscript -namespace chaiscript -{ - namespace exception - { +namespace chaiscript { + namespace exception { /// \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. /// /// \sa chaiscript::boxed_cast - class bad_boxed_cast : public std::bad_cast - { - public: - bad_boxed_cast(Type_Info t_from, const std::type_info &t_to, - utility::Static_String t_what) noexcept - : from(t_from), to(&t_to), m_what(std::move(t_what)) - { - } + class bad_boxed_cast : public std::bad_cast { + public: + bad_boxed_cast(Type_Info t_from, const std::type_info &t_to, utility::Static_String t_what) noexcept + : from(t_from) + , to(&t_to) + , m_what(std::move(t_what)) { + } - bad_boxed_cast(Type_Info t_from, const std::type_info &t_to) noexcept - : from(t_from), to(&t_to), m_what("Cannot perform boxed_cast") - { - } + bad_boxed_cast(Type_Info t_from, const std::type_info &t_to) noexcept + : from(t_from) + , to(&t_to) + , m_what("Cannot perform boxed_cast") { + } - explicit bad_boxed_cast(utility::Static_String t_what) noexcept - : m_what(std::move(t_what)) - { - } + explicit bad_boxed_cast(utility::Static_String t_what) noexcept + : m_what(std::move(t_what)) { + } - bad_boxed_cast(const bad_boxed_cast &) noexcept = default; - ~bad_boxed_cast() noexcept override = default; + bad_boxed_cast(const bad_boxed_cast &) noexcept = default; + ~bad_boxed_cast() noexcept override = default; - /// \brief Description of what error occurred - const char * what() const noexcept override - { - return m_what.c_str(); - } + /// \brief Description of what error occurred + const char *what() const noexcept override { return m_what.c_str(); } - 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 + 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 - private: - utility::Static_String m_what; + private: + utility::Static_String m_what; }; - } -} - - + } // namespace exception +} // namespace chaiscript #endif - diff --git a/include/chaiscript/dispatchkit/bind_first.hpp b/include/chaiscript/dispatchkit/bind_first.hpp index cc794c08..a9815193 100644 --- a/include/chaiscript/dispatchkit/bind_first.hpp +++ b/include/chaiscript/dispatchkit/bind_first.hpp @@ -7,79 +7,54 @@ // This is an open source non-commercial project. Dear PVS-Studio, please check it. // PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com - #ifndef CHAISCRIPT_BIND_FIRST_HPP_ #define CHAISCRIPT_BIND_FIRST_HPP_ #include -namespace chaiscript -{ - namespace detail - { +namespace chaiscript { + namespace detail { + template + constexpr T *get_pointer(T *t) noexcept { + return t; + } template - constexpr T* get_pointer(T *t) noexcept - { - return t; - } + T *get_pointer(const std::reference_wrapper &t) noexcept { + return &t.get(); + } - template - T* get_pointer(const std::reference_wrapper &t) noexcept - { - return &t.get(); - } + template + constexpr auto bind_first(Ret (*f)(P1, Param...), O &&o) { + return [f, o = std::forward(o)](Param... param) -> Ret { return f(o, std::forward(param)...); }; + } - template - constexpr auto bind_first(Ret (*f)(P1, Param...), O&& o) - { - return [f, o = std::forward(o)](Param...param) -> Ret { - return f(o, std::forward(param)...); - }; - } + template + constexpr auto bind_first(Ret (Class::*f)(Param...), O &&o) { + return [f, o = std::forward(o)](Param... param) -> Ret { return (get_pointer(o)->*f)(std::forward(param)...); }; + } - template - constexpr auto bind_first(Ret (Class::*f)(Param...), O&& o) - { - return [f, o = std::forward(o)](Param...param) -> Ret { - return (get_pointer(o)->*f)(std::forward(param)...); - }; - } + template + constexpr auto bind_first(Ret (Class::*f)(Param...) const, O &&o) { + return [f, o = std::forward(o)](Param... param) -> Ret { return (get_pointer(o)->*f)(std::forward(param)...); }; + } - template - constexpr auto bind_first(Ret (Class::*f)(Param...) const, O&& o) - { - return [f, o = std::forward(o)](Param...param) -> Ret { - return (get_pointer(o)->*f)(std::forward(param)...); - }; + template + auto bind_first(const std::function &f, O &&o) { + return [f, o = std::forward(o)](Param... param) -> Ret { return f(o, std::forward(param)...); }; + } - } - - template - auto bind_first(const std::function &f, O&& o) - { - return [f, o = std::forward(o)](Param...param) -> Ret { - return f(o, std::forward(param)...); - }; - } - - template - constexpr auto bind_first(const F &fo, O&& o, Ret (Class::*f)(P1, Param...) const) - { - return [fo, o = std::forward(o), f](Param ...param) -> Ret { - return (fo.*f)(o, std::forward(param)...); - }; - - } + template + constexpr auto bind_first(const F &fo, O &&o, Ret (Class::*f)(P1, Param...) const) { + return [fo, o = std::forward(o), f](Param... param) -> Ret { return (fo.*f)(o, std::forward(param)...); }; + } template - constexpr auto bind_first(const F &f, O&& o) - { - return bind_first(f, std::forward(o), &F::operator()); - } - - } -} + constexpr auto bind_first(const F &f, O &&o) { + return bind_first(f, std::forward(o), &F::operator()); + } + } // namespace detail +} // namespace chaiscript #endif diff --git a/include/chaiscript/dispatchkit/bootstrap.hpp b/include/chaiscript/dispatchkit/bootstrap.hpp index a9c41d30..ba1de5ad 100644 --- a/include/chaiscript/dispatchkit/bootstrap.hpp +++ b/include/chaiscript/dispatchkit/bootstrap.hpp @@ -7,381 +7,327 @@ // This is an open source non-commercial project. Dear PVS-Studio, please check it. // PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com - #ifndef CHAISCRIPT_BOOTSTRAP_HPP_ #define CHAISCRIPT_BOOTSTRAP_HPP_ #include "../utility/utility.hpp" #include "register_function.hpp" -namespace chaiscript -{ - /// \brief Classes and functions useful for bootstrapping of ChaiScript and adding of new types - namespace bootstrap - { - template::value>::type > - void array(const std::string &type, Module& m) - { - using ReturnType = typename std::remove_extent::type; +/// \brief Classes and functions useful for bootstrapping of ChaiScript and adding of new types +namespace chaiscript::bootstrap { + template::value>::type> + void array(const std::string &type, Module &m) { + using ReturnType = typename std::remove_extent::type; - m.add(user_type(), type); - m.add(fun( - [](T& t, size_t index)->ReturnType &{ - constexpr const auto extent = std::extent::value; - if (extent > 0 && index >= extent) { - throw std::range_error("Array index out of range. Received: " + std::to_string(index) + " expected < " + std::to_string(extent)); - } else { - return t[index]; - } - } - ), "[]" - ); + m.add(user_type(), type); + m.add(fun([](T &t, size_t index) -> ReturnType & { + constexpr const auto extent = std::extent::value; + if (extent > 0 && index >= extent) { + throw std::range_error("Array index out of range. Received: " + std::to_string(index) + " expected < " + + std::to_string(extent)); + } else { + return t[index]; + } + }), + "[]"); - m.add(fun( - [](const T &t, size_t index)->const ReturnType &{ - constexpr const auto extent = std::extent::value; - if (extent > 0 && index >= extent) { - throw std::range_error("Array index out of range. Received: " + std::to_string(index) + " expected < " + std::to_string(extent)); - } else { - return t[index]; - } - } - ), "[]" - ); + m.add(fun([](const T &t, size_t index) -> const ReturnType & { + constexpr const auto extent = std::extent::value; + if (extent > 0 && index >= extent) { + throw std::range_error("Array index out of range. Received: " + std::to_string(index) + " expected < " + + std::to_string(extent)); + } else { + return t[index]; + } + }), + "[]"); - m.add(fun( - [](const T &) { - return std::extent::value; - }), "size"); - } + m.add(fun([](const T &) { return std::extent::value; }), "size"); + } - /// \brief Adds a copy constructor for the given type to the given Model - /// \param[in] type The name of the type. The copy constructor will be named "type". - /// \param[in,out] m The Module to add the copy constructor to - /// \tparam T The type to add a copy constructor for - /// \returns The passed in Module - template - void copy_constructor(const std::string &type, Module& m) - { - m.add(constructor(), type); + /// \brief Adds a copy constructor for the given type to the given Model + /// \param[in] type The name of the type. The copy constructor will be named "type". + /// \param[in,out] m The Module to add the copy constructor to + /// \tparam T The type to add a copy constructor for + /// \returns The passed in Module + template + void copy_constructor(const std::string &type, Module &m) { + m.add(constructor(), type); + } + + /// \brief Add all comparison operators for the templated type. Used during bootstrap, also available to users. + /// \tparam T Type to create comparison operators for + /// \param[in,out] m module to add comparison operators to + /// \returns the passed in Module. + template + void opers_comparison(Module &m) { + operators::equal(m); + operators::greater_than(m); + operators::greater_than_equal(m); + operators::less_than(m); + operators::less_than_equal(m); + operators::not_equal(m); + } + + /// \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,out] m The Module to add the basic constructors to + /// \tparam T Type to generate basic constructors for + /// \returns The passed in Module + /// \sa copy_constructor + /// \sa constructor + template + void basic_constructors(const std::string &type, Module &m) { + m.add(constructor(), type); + copy_constructor(type, m); + } + + /// \brief Adds a constructor for a POD type + /// \tparam T The type to add the constructor for + /// \param[in] type The name of the type + /// \param[in,out] m The Module to add the constructor to + template + void construct_pod(const std::string &type, Module &m) { + m.add(fun([](const Boxed_Number &bn) { return bn.get_as(); }), type); + } + + /// Internal function for converting from a string to a value + /// uses ostream operator >> to perform the conversion + template + Input parse_string(const std::string &i) { + if constexpr (!std::is_same::value && !std::is_same::value && !std::is_same::value) { + std::stringstream ss(i); + Input t; + ss >> t; + return t; + } else { + throw std::runtime_error("Parsing of wide characters is not yet supported"); } + } - /// \brief Add all comparison operators for the templated type. Used during bootstrap, also available to users. - /// \tparam T Type to create comparison operators for - /// \param[in,out] m module to add comparison operators to - /// \returns the passed in Module. - template - void opers_comparison(Module& m) - { - operators::equal(m); - operators::greater_than(m); - operators::greater_than_equal(m); - operators::less_than(m); - operators::less_than_equal(m); - operators::not_equal(m); + /// Add all common functions for a POD type. All operators, and + /// common conversions + template + void bootstrap_pod_type(const std::string &name, Module &m) { + m.add(user_type(), name); + m.add(constructor(), name); + construct_pod(name, m); + + m.add(fun(&parse_string), "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 + /// 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 + /// for handling of Proxy_Function object (that is, + /// function variables. + template + auto shared_ptr_clone(const std::shared_ptr &p) { + return p; + } + + /// Specific version of shared_ptr_clone just for Proxy_Functions + template + std::shared_ptr> shared_ptr_unconst_clone(const std::shared_ptr> &p) { + return std::const_pointer_cast::type>(p); + } + + /// Assignment function for shared_ptr objects, does not perform a copy of the + /// object pointed to, instead maintains the shared_ptr concept. + /// Similar to shared_ptr_clone. Used for Proxy_Function. + template + Boxed_Value ptr_assign(Boxed_Value lhs, const std::shared_ptr &rhs) { + if (lhs.is_undef() || (!lhs.get_type_info().is_const() && lhs.get_type_info().bare_equal(chaiscript::detail::Get_Type_Info::get()))) { + lhs.assign(Boxed_Value(rhs)); + return lhs; + } else { + throw exception::bad_boxed_cast("type mismatch in pointer assignment"); } + } - - - /// \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,out] m The Module to add the basic constructors to - /// \tparam T Type to generate basic constructors for - /// \returns The passed in Module - /// \sa copy_constructor - /// \sa constructor - template - void basic_constructors(const std::string &type, Module& m) - { - m.add(constructor(), type); - copy_constructor(type, m); - } - - /// \brief Adds a constructor for a POD type - /// \tparam T The type to add the constructor for - /// \param[in] type The name of the type - /// \param[in,out] m The Module to add the constructor to - template - void construct_pod(const std::string &type, Module& m) - { - m.add(fun([](const Boxed_Number &bn){ return bn.get_as(); }), type); - } - - - /// Internal function for converting from a string to a value - /// uses ostream operator >> to perform the conversion - template - Input parse_string(const std::string &i) - { - if constexpr (!std::is_same::value - && !std::is_same::value - && !std::is_same::value) { - std::stringstream ss(i); - Input t; - ss >> t; - return t; + /// Class consisting of only static functions. All default bootstrapping occurs + /// from this class. + class Bootstrap { + private: + /// Function allowing for assignment of an unknown type to any other value + static Boxed_Value unknown_assign(Boxed_Value lhs, Boxed_Value rhs) { + if (lhs.is_undef()) { + return (lhs.assign(rhs)); } else { - throw std::runtime_error("Parsing of wide characters is not yet supported"); + throw exception::bad_boxed_cast("boxed_value has a set type already"); } } - /// Add all common functions for a POD type. All operators, and - /// common conversions - template - void bootstrap_pod_type(const std::string &name, Module& m) - { - m.add(user_type(), name); - m.add(constructor(), name); - construct_pod(name, m); + static void print(const std::string &s) noexcept { fwrite(s.c_str(), 1, s.size(), stdout); } - m.add(fun(&parse_string), "to_" + name); - m.add(fun([](const T t){ return t; }), "to_" + name); + static void println(const std::string &s) noexcept { puts(s.c_str()); } + + /// Add all arithmetic operators for PODs + static void opers_arithmetic_pod(Module &m) { + m.add(fun(&Boxed_Number::equals), "=="); + m.add(fun(&Boxed_Number::less_than), "<"); + m.add(fun(&Boxed_Number::greater_than), ">"); + m.add(fun(&Boxed_Number::greater_than_equal), ">="); + m.add(fun(&Boxed_Number::less_than_equal), "<="); + m.add(fun(&Boxed_Number::not_equal), "!="); + + m.add(fun(&Boxed_Number::pre_decrement), "--"); + m.add(fun(&Boxed_Number::pre_increment), "++"); + m.add(fun(&Boxed_Number::sum), "+"); + m.add(fun(&Boxed_Number::unary_plus), "+"); + m.add(fun(&Boxed_Number::unary_minus), "-"); + m.add(fun(&Boxed_Number::difference), "-"); + m.add(fun(&Boxed_Number::assign_bitwise_and), "&="); + m.add(fun(&Boxed_Number::assign), "="); + m.add(fun(&Boxed_Number::assign_bitwise_or), "|="); + m.add(fun(&Boxed_Number::assign_bitwise_xor), "^="); + m.add(fun(&Boxed_Number::assign_remainder), "%="); + m.add(fun(&Boxed_Number::assign_shift_left), "<<="); + m.add(fun(&Boxed_Number::assign_shift_right), ">>="); + m.add(fun(&Boxed_Number::bitwise_and), "&"); + m.add(fun(&Boxed_Number::bitwise_complement), "~"); + m.add(fun(&Boxed_Number::bitwise_xor), "^"); + m.add(fun(&Boxed_Number::bitwise_or), "|"); + m.add(fun(&Boxed_Number::assign_product), "*="); + m.add(fun(&Boxed_Number::assign_quotient), "/="); + m.add(fun(&Boxed_Number::assign_sum), "+="); + m.add(fun(&Boxed_Number::assign_difference), "-="); + m.add(fun(&Boxed_Number::quotient), "/"); + m.add(fun(&Boxed_Number::shift_left), "<<"); + m.add(fun(&Boxed_Number::product), "*"); + m.add(fun(&Boxed_Number::remainder), "%"); + m.add(fun(&Boxed_Number::shift_right), ">>"); } + /// Create a bound function object. The first param is the function to bind + /// the remaining parameters are the args to bind into the result + static Boxed_Value bind_function(const Function_Params ¶ms) { + if (params.empty()) { + throw exception::arity_error(0, 1); + } - /// "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 - /// but want to instead maintain the shared_ptr. It is needed internally - /// for handling of Proxy_Function object (that is, - /// function variables. - template - auto shared_ptr_clone(const std::shared_ptr &p) - { - return p; + Const_Proxy_Function f = boxed_cast(params[0]); + + if (f->get_arity() != -1 && size_t(f->get_arity()) != params.size() - 1) { + throw exception::arity_error(static_cast(params.size()), f->get_arity()); + } + + return Boxed_Value(Const_Proxy_Function( + std::make_shared(std::move(f), std::vector(params.begin() + 1, params.end())))); } - /// Specific version of shared_ptr_clone just for Proxy_Functions - template - std::shared_ptr> shared_ptr_unconst_clone(const std::shared_ptr> &p) - { - return std::const_pointer_cast::type>(p); + static bool has_guard(const Const_Proxy_Function &t_pf) noexcept { + auto pf = std::dynamic_pointer_cast(t_pf); + return pf && pf->has_guard(); } - - - /// Assignment function for shared_ptr objects, does not perform a copy of the - /// object pointed to, instead maintains the shared_ptr concept. - /// Similar to shared_ptr_clone. Used for Proxy_Function. - template - Boxed_Value ptr_assign(Boxed_Value lhs, const std::shared_ptr &rhs) - { - if (lhs.is_undef() - || (!lhs.get_type_info().is_const() && lhs.get_type_info().bare_equal(chaiscript::detail::Get_Type_Info::get()))) - { - lhs.assign(Boxed_Value(rhs)); - return lhs; + static Const_Proxy_Function get_guard(const Const_Proxy_Function &t_pf) { + const auto pf = std::dynamic_pointer_cast(t_pf); + if (pf && pf->get_guard()) { + return pf->get_guard(); } else { - throw exception::bad_boxed_cast("type mismatch in pointer assignment"); + throw std::runtime_error("Function does not have a guard"); } } - /// Class consisting of only static functions. All default bootstrapping occurs - /// from this class. - class Bootstrap - { - private: - /// Function allowing for assignment of an unknown type to any other value - static Boxed_Value unknown_assign(Boxed_Value lhs, Boxed_Value rhs) - { - if (lhs.is_undef()) - { - return (lhs.assign(rhs)); - } else { - throw exception::bad_boxed_cast("boxed_value has a set type already"); - } + template + static std::vector do_return_boxed_value_vector(FunctionType f, const dispatch::Proxy_Function_Base *b) { + auto v = (b->*f)(); + + std::vector vbv; + + for (const auto &o : v) { + vbv.push_back(const_var(o)); } - static void print(const std::string &s) noexcept - { - fwrite(s.c_str(), 1, s.size(), stdout); + return vbv; + } + + static bool has_parse_tree(const chaiscript::Const_Proxy_Function &t_pf) noexcept { + const auto pf = std::dynamic_pointer_cast(t_pf); + return bool(pf); + } + + static const chaiscript::AST_Node &get_parse_tree(const chaiscript::Const_Proxy_Function &t_pf) { + const auto pf = std::dynamic_pointer_cast(t_pf); + if (pf) { + return pf->get_parse_tree(); + } else { + throw std::runtime_error("Function does not have a parse tree"); } + } - static void println(const std::string &s) noexcept - { - puts(s.c_str()); - } + template + 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); }; + } + public: + /// \brief perform all common bootstrap functions for std::string, void and POD types + /// \param[in,out] m Module to add bootstrapped functions to + /// \returns passed in Module + static void bootstrap(Module &m) { + m.add(user_type(), "void"); + m.add(user_type(), "bool"); + m.add(user_type(), "Object"); + m.add(user_type(), "Number"); + m.add(user_type(), "Function"); + m.add(user_type(), "Assignable_Function"); + m.add(user_type(), "exception"); - /// Add all arithmetic operators for PODs - static void opers_arithmetic_pod(Module& m) - { - m.add(fun(&Boxed_Number::equals), "=="); - m.add(fun(&Boxed_Number::less_than), "<"); - m.add(fun(&Boxed_Number::greater_than), ">"); - m.add(fun(&Boxed_Number::greater_than_equal), ">="); - m.add(fun(&Boxed_Number::less_than_equal), "<="); - m.add(fun(&Boxed_Number::not_equal), "!="); + m.add(fun(&dispatch::Proxy_Function_Base::get_arity), "get_arity"); + m.add(fun(&dispatch::Proxy_Function_Base::operator==), "=="); - m.add(fun(&Boxed_Number::pre_decrement), "--"); - m.add(fun(&Boxed_Number::pre_increment), "++"); - m.add(fun(&Boxed_Number::sum), "+"); - m.add(fun(&Boxed_Number::unary_plus), "+"); - m.add(fun(&Boxed_Number::unary_minus), "-"); - m.add(fun(&Boxed_Number::difference), "-"); - m.add(fun(&Boxed_Number::assign_bitwise_and), "&="); - m.add(fun(&Boxed_Number::assign), "="); - m.add(fun(&Boxed_Number::assign_bitwise_or), "|="); - m.add(fun(&Boxed_Number::assign_bitwise_xor), "^="); - m.add(fun(&Boxed_Number::assign_remainder), "%="); - m.add(fun(&Boxed_Number::assign_shift_left), "<<="); - m.add(fun(&Boxed_Number::assign_shift_right), ">>="); - m.add(fun(&Boxed_Number::bitwise_and), "&"); - m.add(fun(&Boxed_Number::bitwise_complement), "~"); - m.add(fun(&Boxed_Number::bitwise_xor), "^"); - m.add(fun(&Boxed_Number::bitwise_or), "|"); - m.add(fun(&Boxed_Number::assign_product), "*="); - m.add(fun(&Boxed_Number::assign_quotient), "/="); - m.add(fun(&Boxed_Number::assign_sum), "+="); - m.add(fun(&Boxed_Number::assign_difference), "-="); - m.add(fun(&Boxed_Number::quotient), "/"); - m.add(fun(&Boxed_Number::shift_left), "<<"); - m.add(fun(&Boxed_Number::product), "*"); - m.add(fun(&Boxed_Number::remainder), "%"); - m.add(fun(&Boxed_Number::shift_right), ">>"); - } + 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"); - /// Create a bound function object. The first param is the function to bind - /// the remaining parameters are the args to bind into the result - static Boxed_Value bind_function(const Function_Params ¶ms) - { - if (params.empty()) { - throw exception::arity_error(0, 1); - } + m.add(fun([](const std::exception &e) { return std::string(e.what()); }), "what"); - Const_Proxy_Function f = boxed_cast(params[0]); + m.add(user_type(), "out_of_range"); + m.add(user_type(), "logic_error"); + m.add(chaiscript::base_class()); + m.add(chaiscript::base_class()); + m.add(chaiscript::base_class()); - if (f->get_arity() != -1 && size_t(f->get_arity()) != params.size() - 1) - { - throw exception::arity_error(static_cast(params.size()), f->get_arity()); - } + m.add(user_type(), "runtime_error"); + m.add(chaiscript::base_class()); - return Boxed_Value(Const_Proxy_Function(std::make_shared(std::move(f), - std::vector(params.begin() + 1, params.end())))); - } + m.add(constructor(), "runtime_error"); + m.add(user_type(), "Dynamic_Object"); + m.add(constructor(), "Dynamic_Object"); + m.add(constructor(), "Dynamic_Object"); + 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::set_explicit), "set_explicit"); + m.add(fun(&dispatch::Dynamic_Object::is_explicit), "is_explicit"); + m.add(fun(&dispatch::Dynamic_Object::has_attr), "has_attr"); - static bool has_guard(const Const_Proxy_Function &t_pf) noexcept - { - auto pf = std::dynamic_pointer_cast(t_pf); - return pf && pf->has_guard(); - } + m.add(fun(static_cast(&dispatch::Dynamic_Object::get_attr)), "get_attr"); + m.add(fun(static_cast(&dispatch::Dynamic_Object::get_attr)), + "get_attr"); - static Const_Proxy_Function get_guard(const Const_Proxy_Function &t_pf) - { - const auto pf = std::dynamic_pointer_cast(t_pf); - if (pf && pf->get_guard()) - { - return pf->get_guard(); - } else { - throw std::runtime_error("Function does not have a guard"); - } - } + m.add(fun(static_cast(&dispatch::Dynamic_Object::method_missing)), + "method_missing"); + m.add(fun(static_cast( + &dispatch::Dynamic_Object::method_missing)), + "method_missing"); - template - static std::vector do_return_boxed_value_vector(FunctionType f, - const dispatch::Proxy_Function_Base *b) - { - auto v = (b->*f)(); - - std::vector vbv; + m.add(fun(static_cast(&dispatch::Dynamic_Object::get_attr)), "[]"); + m.add(fun(static_cast(&dispatch::Dynamic_Object::get_attr)), + "[]"); - for (const auto &o: v) - { - vbv.push_back(const_var(o)); - } - - return vbv; - } - - - static bool has_parse_tree(const chaiscript::Const_Proxy_Function &t_pf) noexcept - { - const auto pf = std::dynamic_pointer_cast(t_pf); - return bool(pf); - } - - static const chaiscript::AST_Node &get_parse_tree(const chaiscript::Const_Proxy_Function &t_pf) - { - const auto pf = std::dynamic_pointer_cast(t_pf); - if (pf) - { - return pf->get_parse_tree(); - } else { - throw std::runtime_error("Function does not have a parse tree"); - } - } - - template - 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); - }; - } - - - public: - /// \brief perform all common bootstrap functions for std::string, void and POD types - /// \param[in,out] m Module to add bootstrapped functions to - /// \returns passed in Module - static void bootstrap(Module& m) - { - m.add(user_type(), "void"); - m.add(user_type(), "bool"); - m.add(user_type(), "Object"); - m.add(user_type(), "Number"); - m.add(user_type(), "Function"); - m.add(user_type(), "Assignable_Function"); - m.add(user_type(), "exception"); - - m.add(fun(&dispatch::Proxy_Function_Base::get_arity), "get_arity"); - 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_contained_functions)), "get_contained_functions"); - - m.add(fun([](const std::exception &e){ return std::string(e.what()); }), "what"); - - m.add(user_type(), "out_of_range"); - m.add(user_type(), "logic_error"); - m.add(chaiscript::base_class()); - m.add(chaiscript::base_class()); - m.add(chaiscript::base_class()); - - m.add(user_type(), "runtime_error"); - m.add(chaiscript::base_class()); - - m.add(constructor(), "runtime_error"); - - m.add(user_type(), "Dynamic_Object"); - m.add(constructor(), "Dynamic_Object"); - m.add(constructor(), "Dynamic_Object"); - 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::set_explicit), "set_explicit"); - m.add(fun(&dispatch::Dynamic_Object::is_explicit), "is_explicit"); - m.add(fun(&dispatch::Dynamic_Object::has_attr), "has_attr"); - - m.add(fun(static_cast(&dispatch::Dynamic_Object::get_attr)), "get_attr"); - m.add(fun(static_cast(&dispatch::Dynamic_Object::get_attr)), "get_attr"); - - m.add(fun(static_cast(&dispatch::Dynamic_Object::method_missing)), "method_missing"); - m.add(fun(static_cast(&dispatch::Dynamic_Object::method_missing)), "method_missing"); - - m.add(fun(static_cast(&dispatch::Dynamic_Object::get_attr)), "[]"); - m.add(fun(static_cast(&dispatch::Dynamic_Object::get_attr)), "[]"); - - m.eval(R"chaiscript( - def Dynamic_Object::clone() { - auto &new_o = Dynamic_Object(this.get_type_name()); - for_each(this.get_attrs(), fun[new_o](x) { new_o.get_attr(x.first) = x.second; } ); - new_o; + m.eval(R"chaiscript( + def Dynamic_Object::clone() { + auto &new_o = Dynamic_Object(this.get_type_name()); + for_each(this.get_attrs(), fun[new_o](x) { new_o.get_attr(x.first) = x.second; } ); + new_o; } def `=`(Dynamic_Object lhs, Dynamic_Object rhs) : lhs.get_type_name() == rhs.get_type_name() { - for_each(rhs.get_attrs(), fun[lhs](x) { lhs.get_attr(x.first) = clone(x.second); } ); + for_each(rhs.get_attrs(), fun[lhs](x) { lhs.get_attr(x.first) = clone(x.second); } ); } def `!=`(Dynamic_Object lhs, Dynamic_Object rhs) : lhs.get_type_name() == rhs.get_type_name() @@ -409,173 +355,157 @@ namespace chaiscript } )chaiscript"); - m.add(fun(&has_guard), "has_guard"); - m.add(fun(&get_guard), "get_guard"); + m.add(fun(&has_guard), "has_guard"); + m.add(fun(&get_guard), "get_guard"); - m.add(fun(&Boxed_Value::is_undef), "is_var_undef"); - m.add(fun(&Boxed_Value::is_null), "is_var_null"); - m.add(fun(&Boxed_Value::is_const), "is_var_const"); - m.add(fun(&Boxed_Value::is_ref), "is_var_reference"); - m.add(fun(&Boxed_Value::is_pointer), "is_var_pointer"); - m.add(fun(&Boxed_Value::is_return_value), "is_var_return_value"); - m.add(fun(&Boxed_Value::reset_return_value), "reset_var_return_value"); - m.add(fun(&Boxed_Value::is_type), "is_type"); - m.add(fun(&Boxed_Value::get_attr), "get_var_attr"); - m.add(fun(&Boxed_Value::copy_attrs), "copy_var_attrs"); - m.add(fun(&Boxed_Value::clone_attrs), "clone_var_attrs"); + m.add(fun(&Boxed_Value::is_undef), "is_var_undef"); + m.add(fun(&Boxed_Value::is_null), "is_var_null"); + m.add(fun(&Boxed_Value::is_const), "is_var_const"); + m.add(fun(&Boxed_Value::is_ref), "is_var_reference"); + m.add(fun(&Boxed_Value::is_pointer), "is_var_pointer"); + m.add(fun(&Boxed_Value::is_return_value), "is_var_return_value"); + m.add(fun(&Boxed_Value::reset_return_value), "reset_var_return_value"); + m.add(fun(&Boxed_Value::is_type), "is_type"); + m.add(fun(&Boxed_Value::get_attr), "get_var_attr"); + m.add(fun(&Boxed_Value::copy_attrs), "copy_var_attrs"); + m.add(fun(&Boxed_Value::clone_attrs), "clone_var_attrs"); - m.add(fun(&Boxed_Value::get_type_info), "get_type_info"); - m.add(user_type(), "Type_Info"); - m.add(constructor(), "Type_Info"); + m.add(fun(&Boxed_Value::get_type_info), "get_type_info"); + m.add(user_type(), "Type_Info"); + m.add(constructor(), "Type_Info"); + operators::equal(m); - operators::equal(m); + m.add(fun(&Type_Info::is_const), "is_type_const"); + m.add(fun(&Type_Info::is_reference), "is_type_reference"); + m.add(fun(&Type_Info::is_void), "is_type_void"); + m.add(fun(&Type_Info::is_undef), "is_type_undef"); + m.add(fun(&Type_Info::is_pointer), "is_type_pointer"); + m.add(fun(&Type_Info::is_arithmetic), "is_type_arithmetic"); + m.add(fun(&Type_Info::name), "cpp_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::is_const), "is_type_const"); - m.add(fun(&Type_Info::is_reference), "is_type_reference"); - m.add(fun(&Type_Info::is_void), "is_type_void"); - m.add(fun(&Type_Info::is_undef), "is_type_undef"); - m.add(fun(&Type_Info::is_pointer), "is_type_pointer"); - m.add(fun(&Type_Info::is_arithmetic), "is_type_arithmetic"); - m.add(fun(&Type_Info::name), "cpp_name"); - m.add(fun(&Type_Info::bare_name), "cpp_bare_name"); - m.add(fun(&Type_Info::bare_equal), "bare_equal"); + basic_constructors("bool", m); + operators::assign(m); + operators::equal(m); + operators::not_equal(m); + 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(&unknown_assign), "="); + m.add(fun([](const Boxed_Value &bv) { throw bv; }), "throw"); - basic_constructors("bool", m); - operators::assign(m); - operators::equal(m); - operators::not_equal(m); + 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([](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(&unknown_assign), "="); - m.add(fun([](const Boxed_Value &bv) { throw bv; }), "throw"); + bootstrap_pod_type("double", m); + bootstrap_pod_type("long_double", m); + bootstrap_pod_type("float", m); + bootstrap_pod_type("int", m); + bootstrap_pod_type("long", m); + bootstrap_pod_type("unsigned_int", m); + bootstrap_pod_type("unsigned_long", m); + bootstrap_pod_type("long_long", m); + bootstrap_pod_type("unsigned_long_long", m); + bootstrap_pod_type("size_t", m); + bootstrap_pod_type("char", m); + bootstrap_pod_type("wchar_t", m); + bootstrap_pod_type("char16_t", m); + bootstrap_pod_type("char32_t", m); + bootstrap_pod_type("int8_t", m); + bootstrap_pod_type("int16_t", m); + bootstrap_pod_type("int32_t", m); + bootstrap_pod_type("int64_t", m); + bootstrap_pod_type("uint8_t", m); + bootstrap_pod_type("uint16_t", m); + bootstrap_pod_type("uint32_t", m); + bootstrap_pod_type("uint64_t", m); - m.add(fun([](const char c) { return std::string(1, c); }), "to_string"); - m.add(fun(&Boxed_Number::to_string), "to_string"); + operators::logical_compliment(m); + opers_arithmetic_pod(m); - bootstrap_pod_type("double", m); - bootstrap_pod_type("long_double", m); - bootstrap_pod_type("float", m); - bootstrap_pod_type("int", m); - bootstrap_pod_type("long", m); - bootstrap_pod_type("unsigned_int", m); - bootstrap_pod_type("unsigned_long", m); - bootstrap_pod_type("long_long", m); - bootstrap_pod_type("unsigned_long_long", m); - bootstrap_pod_type("size_t", m); - bootstrap_pod_type("char", m); - bootstrap_pod_type("wchar_t", m); - bootstrap_pod_type("char16_t", m); - bootstrap_pod_type("char32_t", m); - bootstrap_pod_type("int8_t", m); - bootstrap_pod_type("int16_t", m); - bootstrap_pod_type("int32_t", m); - bootstrap_pod_type("int64_t", m); - bootstrap_pod_type("uint8_t", m); - bootstrap_pod_type("uint16_t", m); - bootstrap_pod_type("uint32_t", m); - bootstrap_pod_type("uint64_t", m); + m.add(fun(&Build_Info::version_major), "version_major"); + m.add(fun(&Build_Info::version_minor), "version_minor"); + m.add(fun(&Build_Info::version_patch), "version_patch"); + m.add(fun(&Build_Info::version), "version"); + m.add(fun(&Build_Info::compiler_version), "compiler_version"); + m.add(fun(&Build_Info::compiler_name), "compiler_name"); + m.add(fun(&Build_Info::compiler_id), "compiler_id"); + m.add(fun(&Build_Info::debug_build), "debug_build"); + m.add(fun(&print), "print_string"); + m.add(fun(&println), "println_string"); - operators::logical_compliment(m); + m.add(dispatch::make_dynamic_proxy_function(&bind_function), "bind"); - opers_arithmetic_pod(m); + m.add(fun(&shared_ptr_unconst_clone), "clone"); + m.add(fun(&ptr_assign::type>), "="); + m.add(fun(&ptr_assign::type>), "="); + m.add(chaiscript::base_class()); + m.add(fun([](dispatch::Assignable_Proxy_Function &t_lhs, const std::shared_ptr &t_rhs) { + t_lhs.assign(t_rhs); + }), + "="); + m.add(fun(&Boxed_Value::type_match), "type_match"); - m.add(fun(&Build_Info::version_major), "version_major"); - m.add(fun(&Build_Info::version_minor), "version_minor"); - m.add(fun(&Build_Info::version_patch), "version_patch"); - m.add(fun(&Build_Info::version), "version"); - m.add(fun(&Build_Info::compiler_version), "compiler_version"); - m.add(fun(&Build_Info::compiler_name), "compiler_name"); - m.add(fun(&Build_Info::compiler_id), "compiler_id"); - m.add(fun(&Build_Info::debug_build), "debug_build"); + m.add(chaiscript::fun(&has_parse_tree), "has_parse_tree"); + m.add(chaiscript::fun(&get_parse_tree), "get_parse_tree"); + m.add(chaiscript::base_class()); + m.add(chaiscript::base_class()); - m.add(fun(&print), "print_string"); - m.add(fun(&println), "println_string"); + m.add(chaiscript::user_type(), "arithmetic_error"); + m.add(chaiscript::base_class()); + m.add(chaiscript::base_class()); - m.add(dispatch::make_dynamic_proxy_function(&bind_function), "bind"); + // chaiscript::bootstrap::standard_library::vector_type > + // >("AST_NodeVector", m); - m.add(fun(&shared_ptr_unconst_clone), "clone"); - m.add(fun(&ptr_assign::type>), "="); - m.add(fun(&ptr_assign::type>), "="); - m.add(chaiscript::base_class()); - m.add(fun( - [](dispatch::Assignable_Proxy_Function &t_lhs, const std::shared_ptr &t_rhs) { - t_lhs.assign(t_rhs); - } - ), "=" - ); + chaiscript::utility::add_class(m, + "eval_error", + {}, + {{fun(&chaiscript::exception::eval_error::reason), "reason"}, + {fun(&chaiscript::exception::eval_error::pretty_print), "pretty_print"}, + {fun([](const chaiscript::exception::eval_error &t_eval_error) { + std::vector retval; + std::transform(t_eval_error.call_stack.begin(), + t_eval_error.call_stack.end(), + std::back_inserter(retval), + &chaiscript::var); + return retval; + }), + "call_stack"}}); - m.add(fun(&Boxed_Value::type_match), "type_match"); + chaiscript::utility::add_class(m, + "File_Position", + {constructor(), constructor()}, + {{fun(&File_Position::line), "line"}, + {fun(&File_Position::column), "column"}}); - - m.add(chaiscript::fun(&has_parse_tree), "has_parse_tree"); - m.add(chaiscript::fun(&get_parse_tree), "get_parse_tree"); - - m.add(chaiscript::base_class()); - m.add(chaiscript::base_class()); - - m.add(chaiscript::user_type(), "arithmetic_error"); - m.add(chaiscript::base_class()); - m.add(chaiscript::base_class()); - - -// chaiscript::bootstrap::standard_library::vector_type > >("AST_NodeVector", m); - - - chaiscript::utility::add_class(m, - "eval_error", - { }, - { {fun(&chaiscript::exception::eval_error::reason), "reason"}, - {fun(&chaiscript::exception::eval_error::pretty_print), "pretty_print"}, - {fun([](const chaiscript::exception::eval_error &t_eval_error) { - std::vector retval; - std::transform(t_eval_error.call_stack.begin(), t_eval_error.call_stack.end(), - std::back_inserter(retval), - &chaiscript::var); - return retval; - }), "call_stack"} } - ); - - - chaiscript::utility::add_class(m, - "File_Position", - { constructor(), - constructor() }, - { {fun(&File_Position::line), "line"}, - {fun(&File_Position::column), "column"} } - ); - - - chaiscript::utility::add_class(m, - "AST_Node", - { }, - { {fun(&AST_Node::text), "text"}, - {fun(&AST_Node::identifier), "identifier"}, - {fun(&AST_Node::filename), "filename"}, - {fun(&AST_Node::start), "start"}, - {fun(&AST_Node::end), "end"}, - {fun(&AST_Node::to_string), "to_string"}, - {fun([](const chaiscript::AST_Node &t_node) -> std::vector { - std::vector retval; - const auto children = t_node.get_children(); - std::transform(children.begin(), children.end(), - std::back_inserter(retval), - &chaiscript::var &>); - return retval; - }), "children"} - } - ); - - } - }; - } -} + chaiscript::utility::add_class(m, + "AST_Node", + {}, + {{fun(&AST_Node::text), "text"}, + {fun(&AST_Node::identifier), "identifier"}, + {fun(&AST_Node::filename), "filename"}, + {fun(&AST_Node::start), "start"}, + {fun(&AST_Node::end), "end"}, + {fun(&AST_Node::to_string), "to_string"}, + {fun([](const chaiscript::AST_Node &t_node) -> std::vector { + std::vector retval; + const auto children = t_node.get_children(); + std::transform(children.begin(), + children.end(), + std::back_inserter(retval), + &chaiscript::var &>); + return retval; + }), + "children"}}); + } + }; +} // namespace chaiscript::bootstrap #endif - diff --git a/include/chaiscript/dispatchkit/bootstrap_stl.hpp b/include/chaiscript/dispatchkit/bootstrap_stl.hpp index 04ca84d0..7592c511 100644 --- a/include/chaiscript/dispatchkit/bootstrap_stl.hpp +++ b/include/chaiscript/dispatchkit/bootstrap_stl.hpp @@ -7,13 +7,11 @@ // 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 - /// \file /// This file contains utility functions for registration of STL container /// classes. The methodology used is based on the SGI STL concepts. /// http://www.sgi.com/tech/stl/table_of_contents.html - #ifndef CHAISCRIPT_BOOTSTRAP_STL_HPP_ #define CHAISCRIPT_BOOTSTRAP_STL_HPP_ @@ -31,412 +29,353 @@ #include "register_function.hpp" #include "type_info.hpp" -namespace chaiscript -{ - namespace bootstrap - { - namespace standard_library - { +namespace chaiscript::bootstrap::standard_library { + /// Bidir_Range, based on the D concept of ranges. + /// \todo Update the Range code to base its capabilities on + /// the user_typetraits of the iterator passed in + template + struct Bidir_Range { + using container_type = Container; - /// Bidir_Range, based on the D concept of ranges. - /// \todo Update the Range code to base its capabilities on - /// the user_typetraits of the iterator passed in - template - struct Bidir_Range - { - using container_type = Container; + constexpr Bidir_Range(Container &c) + : m_begin(c.begin()) + , m_end(c.end()) { + } - constexpr Bidir_Range(Container &c) - : m_begin(c.begin()), m_end(c.end()) - { - } + constexpr bool empty() const noexcept { return m_begin == m_end; } - constexpr bool empty() const noexcept - { - return m_begin == m_end; - } + constexpr void pop_front() { + if (empty()) { + throw std::range_error("Range empty"); + } + ++m_begin; + } - constexpr void pop_front() - { - if (empty()) - { - throw std::range_error("Range empty"); - } - ++m_begin; - } + constexpr void pop_back() { + if (empty()) { + throw std::range_error("Range empty"); + } + --m_end; + } - constexpr void pop_back() - { - if (empty()) - { - throw std::range_error("Range empty"); - } - --m_end; - } + constexpr decltype(auto) front() const { + if (empty()) { + throw std::range_error("Range empty"); + } + return (*m_begin); + } - constexpr decltype(auto) front() const - { - if (empty()) - { - throw std::range_error("Range empty"); - } - return (*m_begin); - } + constexpr decltype(auto) back() const { + if (empty()) { + throw std::range_error("Range empty"); + } + auto pos = m_end; + --pos; + return (*(pos)); + } - constexpr decltype(auto) back() const - { - if (empty()) - { - throw std::range_error("Range empty"); - } - auto pos = m_end; - --pos; - return (*(pos)); - } + IterType m_begin; + IterType m_end; + }; - IterType m_begin; - IterType m_end; - }; + namespace detail { + template + size_t count(const T &t_target, const typename T::key_type &t_key) { + return t_target.count(t_key); + } - namespace detail { + template + void insert(T &t_target, const T &t_other) { + t_target.insert(t_other.begin(), t_other.end()); + } - template - size_t count(const T &t_target, const typename T::key_type &t_key) - { - return t_target.count(t_key); - } + template + void insert_ref(T &t_target, const typename T::value_type &t_val) { + t_target.insert(t_val); + } - template - void insert(T &t_target, const T &t_other) - { - t_target.insert(t_other.begin(), t_other.end()); - } + /// Add Bidir_Range support for the given ContainerType + template + void input_range_type_impl(const std::string &type, Module &m) { + m.add(user_type(), type + "_Range"); - template - void insert_ref(T &t_target, const typename T::value_type &t_val) - { - t_target.insert(t_val); - } + copy_constructor(type + "_Range", m); + m.add(constructor(), "range_internal"); + m.add(fun(&Bidir_Type::empty), "empty"); + m.add(fun(&Bidir_Type::pop_front), "pop_front"); + m.add(fun(&Bidir_Type::front), "front"); + m.add(fun(&Bidir_Type::pop_back), "pop_back"); + m.add(fun(&Bidir_Type::back), "back"); + } - /// Add Bidir_Range support for the given ContainerType - template - void input_range_type_impl(const std::string &type, Module& m) - { - m.add(user_type(), type + "_Range"); + /// Algorithm for inserting at a specific position into a container + template + void insert_at(Type &container, int pos, const typename Type::value_type &v) { + auto itr = container.begin(); + auto end = container.end(); - copy_constructor(type + "_Range", m); - - m.add(constructor(), "range_internal"); - - m.add(fun(&Bidir_Type::empty), "empty"); - m.add(fun(&Bidir_Type::pop_front), "pop_front"); - m.add(fun(&Bidir_Type::front), "front"); - m.add(fun(&Bidir_Type::pop_back), "pop_back"); - m.add(fun(&Bidir_Type::back), "back"); - } - - - /// Algorithm for inserting at a specific position into a container - template - void insert_at(Type &container, int pos, const typename Type::value_type &v) - { - auto itr = container.begin(); - auto end = container.end(); - - if (pos < 0 || std::distance(itr, end) < pos) - { - throw std::range_error("Cannot insert past end of range"); - } - - std::advance(itr, pos); - container.insert(itr, v); - } - - - /// Algorithm for erasing a specific position from a container - template - void erase_at(Type &container, int pos) - { - auto itr = container.begin(); - auto end = container.end(); - - if (pos < 0 || std::distance(itr, end) < (pos-1)) - { - throw std::range_error("Cannot erase past end of range"); - } - - std::advance(itr, pos); - container.erase(itr); - } + if (pos < 0 || std::distance(itr, end) < pos) { + throw std::range_error("Cannot insert past end of range"); } - template - void input_range_type(const std::string &type, Module& m) - { - detail::input_range_type_impl >(type,m); - detail::input_range_type_impl >("Const_" + type,m); - } + std::advance(itr, pos); + container.insert(itr, v); + } + /// Algorithm for erasing a specific position from a container + template + void erase_at(Type &container, int pos) { + auto itr = container.begin(); + auto end = container.end(); - /// Add random_access_container concept to the given ContainerType - /// http://www.sgi.com/tech/stl/RandomAccessContainer.html - template - 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, - //to throw an exception in an out of bounds condition. - m.add( - fun( - [](ContainerType &c, int index) -> typename ContainerType::reference { - /// \todo we are preferring to keep the key as 'int' to avoid runtime conversions - /// during dispatch. reevaluate - return c.at(static_cast(index)); - }), "[]"); + if (pos < 0 || std::distance(itr, end) < (pos - 1)) { + throw std::range_error("Cannot erase past end of range"); + } - m.add( - fun( - [](const ContainerType &c, int index) -> typename ContainerType::const_reference { - /// \todo we are preferring to keep the key as 'int' to avoid runtime conversions - /// during dispatch. reevaluate - return c.at(static_cast(index)); - }), "[]"); - } + std::advance(itr, pos); + container.erase(itr); + } + } // namespace detail + template + void input_range_type(const std::string &type, Module &m) { + detail::input_range_type_impl>(type, m); + detail::input_range_type_impl>("Const_" + type, m); + } - /// Add assignable concept to the given ContainerType - /// http://www.sgi.com/tech/stl/Assignable.html - template - void assignable_type(const std::string &type, Module& m) - { - copy_constructor(type, m); - operators::assign(m); - } + /// Add random_access_container concept to the given ContainerType + /// http://www.sgi.com/tech/stl/RandomAccessContainer.html + template + 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, + // to throw an exception in an out of bounds condition. + m.add(fun([](ContainerType &c, int index) -> typename ContainerType::reference { + /// \todo we are preferring to keep the key as 'int' to avoid runtime conversions + /// during dispatch. reevaluate + return c.at(static_cast(index)); + }), + "[]"); - /// Add container resize concept to the given ContainerType - /// http://www.cplusplus.com/reference/stl/ - template - 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) { return a->resize(n, val); } ), "resize"); - m.add(fun([](ContainerType *a, typename ContainerType::size_type n) { return a->resize(n); } ), "resize"); - } + m.add(fun([](const ContainerType &c, int index) -> typename ContainerType::const_reference { + /// \todo we are preferring to keep the key as 'int' to avoid runtime conversions + /// during dispatch. reevaluate + return c.at(static_cast(index)); + }), + "[]"); + } - /// Add container reserve concept to the given ContainerType - /// http://www.cplusplus.com/reference/stl/ - template - 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([](const ContainerType *a) { return a->capacity(); } ), "capacity"); - } + /// Add assignable concept to the given ContainerType + /// http://www.sgi.com/tech/stl/Assignable.html + template + void assignable_type(const std::string &type, Module &m) { + copy_constructor(type, m); + operators::assign(m); + } - /// Add container concept to the given ContainerType - /// http://www.sgi.com/tech/stl/Container.html - template - 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->empty(); } ), "empty"); - m.add(fun([](ContainerType *a) { a->clear(); } ), "clear"); - } + /// Add container resize concept to the given ContainerType + /// http://www.cplusplus.com/reference/stl/ + template + 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) { + return a->resize(n, val); + }), + "resize"); + m.add(fun([](ContainerType *a, typename ContainerType::size_type n) { return a->resize(n); }), "resize"); + } - /// Add default constructable concept to the given Type - /// http://www.sgi.com/tech/stl/DefaultConstructible.html - template - void default_constructible_type(const std::string &type, Module& m) - { - m.add(constructor(), type); - } + /// Add container reserve concept to the given ContainerType + /// http://www.cplusplus.com/reference/stl/ + template + 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([](const ContainerType *a) { return a->capacity(); }), "capacity"); + } - /// Add sequence concept to the given ContainerType - /// http://www.sgi.com/tech/stl/Sequence.html - template - void sequence_type(const std::string &/*type*/, Module& m) - { - m.add(fun(&detail::insert_at), - []()->std::string{ - if (typeid(typename ContainerType::value_type) == typeid(Boxed_Value)) { - return "insert_ref_at"; - } else { - return "insert_at"; - } - }()); + /// Add container concept to the given ContainerType + /// http://www.sgi.com/tech/stl/Container.html + template + 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->empty(); }), "empty"); + m.add(fun([](ContainerType *a) { a->clear(); }), "clear"); + } - m.add(fun(&detail::erase_at), "erase_at"); - } + /// Add default constructable concept to the given Type + /// http://www.sgi.com/tech/stl/DefaultConstructible.html + template + void default_constructible_type(const std::string &type, Module &m) { + m.add(constructor(), type); + } - /// Add back insertion sequence concept to the given ContainerType - /// http://www.sgi.com/tech/stl/BackInsertionSequence.html - template - void back_insertion_sequence_type(const std::string &type, Module& m) - { - m.add(fun([](ContainerType &container)->decltype(auto){ - if (container.empty()) { - throw std::range_error("Container empty"); - } else { - return (container.back()); - } - } - ) - , "back"); - m.add(fun([](const ContainerType &container)->decltype(auto){ - if (container.empty()) { - throw std::range_error("Container empty"); - } else { - return (container.back()); - } - } - ) - , "back"); + /// Add sequence concept to the given ContainerType + /// http://www.sgi.com/tech/stl/Sequence.html + template + void sequence_type(const std::string & /*type*/, Module &m) { + m.add(fun(&detail::insert_at), []() -> std::string { + if (typeid(typename ContainerType::value_type) == typeid(Boxed_Value)) { + return "insert_ref_at"; + } else { + return "insert_at"; + } + }()); + m.add(fun(&detail::erase_at), "erase_at"); + } - using push_back = void (ContainerType::*)(const typename ContainerType::value_type &); - m.add(fun(static_cast(&ContainerType::push_back)), - [&]()->std::string{ - if (typeid(typename ContainerType::value_type) == typeid(Boxed_Value)) { - m.eval( - "# Pushes the second value onto the container while making a clone of the value\n" - "def push_back(" + type + " container, x)\n" - "{ \n" - " if (x.is_var_return_value()) {\n" - " x.reset_var_return_value() \n" - " container.push_back_ref(x) \n" - " } else { \n" - " container.push_back_ref(clone(x)); \n" - " }\n" - "} \n" - ); + /// Add back insertion sequence concept to the given ContainerType + /// http://www.sgi.com/tech/stl/BackInsertionSequence.html + template + void back_insertion_sequence_type(const std::string &type, Module &m) { + m.add(fun([](ContainerType &container) -> decltype(auto) { + if (container.empty()) { + throw std::range_error("Container empty"); + } else { + return (container.back()); + } + }), + "back"); + m.add(fun([](const ContainerType &container) -> decltype(auto) { + if (container.empty()) { + throw std::range_error("Container empty"); + } else { + return (container.back()); + } + }), + "back"); - return "push_back_ref"; - } else { - return "push_back"; - } - }()); + using push_back = void (ContainerType::*)(const typename ContainerType::value_type &); + m.add(fun(static_cast(&ContainerType::push_back)), [&]() -> std::string { + if (typeid(typename ContainerType::value_type) == typeid(Boxed_Value)) { + m.eval("# Pushes the second value onto the container while making a clone of the value\n" + "def push_back(" + + type + + " container, x)\n" + "{ \n" + " if (x.is_var_return_value()) {\n" + " x.reset_var_return_value() \n" + " container.push_back_ref(x) \n" + " } else { \n" + " container.push_back_ref(clone(x)); \n" + " }\n" + "} \n"); - m.add(fun(&ContainerType::pop_back), "pop_back"); - } + return "push_back_ref"; + } else { + return "push_back"; + } + }()); + m.add(fun(&ContainerType::pop_back), "pop_back"); + } - /// Front insertion sequence - /// http://www.sgi.com/tech/stl/FrontInsertionSequence.html - template - void front_insertion_sequence_type(const std::string &type, Module& m) - { - using push_ptr = void (ContainerType::*)(typename ContainerType::const_reference); - using pop_ptr = void (ContainerType::*)(); + /// Front insertion sequence + /// http://www.sgi.com/tech/stl/FrontInsertionSequence.html + template + void front_insertion_sequence_type(const std::string &type, Module &m) { + using push_ptr = void (ContainerType::*)(typename ContainerType::const_reference); + using pop_ptr = void (ContainerType::*)(); - m.add(fun([](ContainerType &container)->decltype(auto){ - if (container.empty()) { - throw std::range_error("Container empty"); - } else { - return (container.front()); - } - } - ) - , "front"); + m.add(fun([](ContainerType &container) -> decltype(auto) { + if (container.empty()) { + throw std::range_error("Container empty"); + } else { + return (container.front()); + } + }), + "front"); - m.add(fun([](const ContainerType &container)->decltype(auto){ - if (container.empty()) { - throw std::range_error("Container empty"); - } else { - return (container.front()); - } - } - ) - , "front"); + m.add(fun([](const ContainerType &container) -> decltype(auto) { + if (container.empty()) { + throw std::range_error("Container empty"); + } else { + return (container.front()); + } + }), + "front"); + m.add(fun(static_cast(&ContainerType::push_front)), [&]() -> std::string { + if (typeid(typename ContainerType::value_type) == typeid(Boxed_Value)) { + m.eval("# Pushes the second value onto the front of container while making a clone of the value\n" + "def push_front(" + + type + + " container, x)\n" + "{ \n" + " if (x.is_var_return_value()) {\n" + " x.reset_var_return_value() \n" + " container.push_front_ref(x) \n" + " } else { \n" + " container.push_front_ref(clone(x)); \n" + " }\n" + "} \n"); + return "push_front_ref"; + } else { + return "push_front"; + } + }()); - m.add(fun(static_cast(&ContainerType::push_front)), - [&]()->std::string{ - if (typeid(typename ContainerType::value_type) == typeid(Boxed_Value)) { - m.eval( - "# Pushes the second value onto the front of container while making a clone of the value\n" - "def push_front(" + type + " container, x)\n" - "{ \n" - " if (x.is_var_return_value()) {\n" - " x.reset_var_return_value() \n" - " container.push_front_ref(x) \n" - " } else { \n" - " container.push_front_ref(clone(x)); \n" - " }\n" - "} \n" - ); - return "push_front_ref"; - } else { - return "push_front"; - } - }()); + m.add(fun(static_cast(&ContainerType::pop_front)), "pop_front"); + } - m.add(fun(static_cast(&ContainerType::pop_front)), "pop_front"); - } + /// bootstrap a given PairType + /// http://www.sgi.com/tech/stl/pair.html + template + void pair_type(const std::string &type, Module &m) { + m.add(user_type(), type); - /// bootstrap a given PairType - /// http://www.sgi.com/tech/stl/pair.html - template - void pair_type(const std::string &type, Module& m) - { - m.add(user_type(), type); + m.add(fun(&PairType::first), "first"); + m.add(fun(&PairType::second), "second"); - m.add(fun(&PairType::first), "first"); - m.add(fun(&PairType::second), "second"); + basic_constructors(type, m); + m.add(constructor(), type); + } - basic_constructors(type, m); - m.add(constructor(), type); - } + /// Add pair associative container concept to the given ContainerType + /// http://www.sgi.com/tech/stl/PairAssociativeContainer.html + template + void pair_associative_container_type(const std::string &type, Module &m) { + pair_type(type + "_Pair", m); + } - /// Add pair associative container concept to the given ContainerType - /// http://www.sgi.com/tech/stl/PairAssociativeContainer.html + /// Add unique associative container concept to the given ContainerType + /// http://www.sgi.com/tech/stl/UniqueAssociativeContainer.html + template + void unique_associative_container_type(const std::string & /*type*/, Module &m) { + m.add(fun(detail::count), "count"); - template - void pair_associative_container_type(const std::string &type, Module& m) - { - pair_type(type + "_Pair", m); - } + using erase_ptr = size_t (ContainerType::*)(const typename ContainerType::key_type &); - /// Add unique associative container concept to the given ContainerType - /// http://www.sgi.com/tech/stl/UniqueAssociativeContainer.html - template - void unique_associative_container_type(const std::string &/*type*/, Module& m) - { - m.add(fun(detail::count), "count"); + m.add(fun(static_cast(&ContainerType::erase)), "erase"); - using erase_ptr = size_t (ContainerType::*)(const typename ContainerType::key_type &); + m.add(fun(&detail::insert), "insert"); - m.add(fun(static_cast(&ContainerType::erase)), "erase"); + m.add(fun(&detail::insert_ref), []() -> std::string { + if (typeid(typename ContainerType::mapped_type) == typeid(Boxed_Value)) { + return "insert_ref"; + } else { + return "insert"; + } + }()); + } - m.add(fun(&detail::insert), "insert"); + /// Add a MapType container + /// http://www.sgi.com/tech/stl/Map.html + template + void map_type(const std::string &type, Module &m) { + m.add(user_type(), type); - m.add(fun(&detail::insert_ref), - []()->std::string{ - if (typeid(typename ContainerType::mapped_type) == typeid(Boxed_Value)) { - return "insert_ref"; - } else { - return "insert"; - } - }()); - } + using elem_access = typename MapType::mapped_type &(MapType::*)(const typename MapType::key_type &); + using const_elem_access = const typename MapType::mapped_type &(MapType::*)(const typename MapType::key_type &) const; - /// Add a MapType container - /// http://www.sgi.com/tech/stl/Map.html - template - void map_type(const std::string &type, Module& m) - { - m.add(user_type(), type); + m.add(fun(static_cast(&MapType::operator[])), "[]"); - using elem_access = typename MapType::mapped_type &(MapType::*)(const typename MapType::key_type &); - using const_elem_access = const typename MapType::mapped_type &(MapType::*)(const typename MapType::key_type &) const; + m.add(fun(static_cast(&MapType::at)), "at"); + m.add(fun(static_cast(&MapType::at)), "at"); - m.add(fun(static_cast(&MapType::operator[])), "[]"); - - m.add(fun(static_cast(&MapType::at)), "at"); - m.add(fun(static_cast(&MapType::at)), "at"); - - if (typeid(MapType) == typeid(std::map)) - { - m.eval(R"( + if (typeid(MapType) == typeid(std::map)) { + m.eval(R"( def Map::`==`(Map rhs) { if ( rhs.size() != this.size() ) { return false; @@ -454,77 +393,68 @@ namespace chaiscript } true; } - } )" - ); - } + } )"); + } - container_type(type, m); - default_constructible_type(type, m); - assignable_type(type, m); - unique_associative_container_type(type, m); - pair_associative_container_type(type, m); - input_range_type(type, m); - } + container_type(type, m); + default_constructible_type(type, m); + assignable_type(type, m); + unique_associative_container_type(type, m); + pair_associative_container_type(type, m); + input_range_type(type, m); + } - /// http://www.sgi.com/tech/stl/List.html - template - void list_type(const std::string &type, Module& m) - { - m.add(user_type(), type); + /// http://www.sgi.com/tech/stl/List.html + template + void list_type(const std::string &type, Module &m) { + m.add(user_type(), type); - front_insertion_sequence_type(type, m); - back_insertion_sequence_type(type, m); - sequence_type(type, m); - resizable_type(type, m); - container_type(type, m); - default_constructible_type(type, m); - assignable_type(type, m); - input_range_type(type, m); - } + front_insertion_sequence_type(type, m); + back_insertion_sequence_type(type, m); + sequence_type(type, m); + resizable_type(type, m); + container_type(type, m); + default_constructible_type(type, m); + assignable_type(type, m); + input_range_type(type, m); + } - /// Create a vector type with associated concepts - /// http://www.sgi.com/tech/stl/Vector.html - template - void vector_type(const std::string &type, Module& m) - { - m.add(user_type(), type); + /// Create a vector type with associated concepts + /// http://www.sgi.com/tech/stl/Vector.html + template + void vector_type(const std::string &type, Module &m) { + m.add(user_type(), type); - m.add(fun([](VectorType &container)->decltype(auto){ - if (container.empty()) { - throw std::range_error("Container empty"); - } else { - return (container.front()); - } - } - ) - , "front"); + m.add(fun([](VectorType &container) -> decltype(auto) { + if (container.empty()) { + throw std::range_error("Container empty"); + } else { + return (container.front()); + } + }), + "front"); - m.add(fun([](const VectorType &container)->decltype(auto){ - if (container.empty()) { - throw std::range_error("Container empty"); - } else { - return (container.front()); - } - } - ) - , "front"); + m.add(fun([](const VectorType &container) -> decltype(auto) { + if (container.empty()) { + throw std::range_error("Container empty"); + } else { + return (container.front()); + } + }), + "front"); + back_insertion_sequence_type(type, m); + sequence_type(type, m); + random_access_container_type(type, m); + resizable_type(type, m); + reservable_type(type, m); + container_type(type, m); + default_constructible_type(type, m); + assignable_type(type, m); + input_range_type(type, m); - - - back_insertion_sequence_type(type, m); - sequence_type(type, m); - random_access_container_type(type, m); - resizable_type(type, m); - reservable_type(type, m); - container_type(type, m); - default_constructible_type(type, m); - assignable_type(type, m); - input_range_type(type, m); - - if (typeid(VectorType) == typeid(std::vector)) - { - m.eval(R"( + if (typeid(VectorType) == typeid(std::vector)) { + m.eval(R"( def Vector::`==`(Vector rhs) { if ( rhs.size() != this.size() ) { return false; @@ -542,73 +472,62 @@ namespace chaiscript } true; } - } )" - ); - } - } - - /// Add a String container - /// http://www.sgi.com/tech/stl/basic_string.html - template - void string_type(const std::string &type, Module& m) - { - m.add(user_type(), type); - operators::addition(m); - operators::assign_sum(m); - opers_comparison(m); - random_access_container_type(type, m); - sequence_type(type, m); - default_constructible_type(type, m); - // container_type(type, m); - assignable_type(type, m); - input_range_type(type, m); - - //Special case: add push_back to string (which doesn't support other back_insertion operations - m.add(fun(&String::push_back), - []()->std::string{ - if (typeid(typename String::value_type) == typeid(Boxed_Value)) { - return "push_back_ref"; - } else { - return "push_back"; - } - }()); - - - 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([](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([](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 - /// http://www.sgi.com/tech/stl/Map.html - template - void future_type(const std::string &type, Module& m) - { - m.add(user_type(), type); - - m.add(fun([](const FutureType &t) { return t.valid(); }), "valid"); - m.add(fun([](FutureType &t) { return t.get(); }), "get"); - m.add(fun(&FutureType::wait), "wait"); - } + } )"); } } -} + /// Add a String container + /// http://www.sgi.com/tech/stl/basic_string.html + template + void string_type(const std::string &type, Module &m) { + m.add(user_type(), type); + operators::addition(m); + operators::assign_sum(m); + opers_comparison(m); + random_access_container_type(type, m); + sequence_type(type, m); + default_constructible_type(type, m); + // container_type(type, m); + assignable_type(type, m); + input_range_type(type, m); + + // Special case: add push_back to string (which doesn't support other back_insertion operations + m.add(fun(&String::push_back), []() -> std::string { + if (typeid(typename String::value_type) == typeid(Boxed_Value)) { + return "push_back_ref"; + } else { + return "push_back"; + } + }()); + + 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([](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([](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 + /// http://www.sgi.com/tech/stl/Map.html + template + void future_type(const std::string &type, Module &m) { + m.add(user_type(), type); + + m.add(fun([](const FutureType &t) { return t.valid(); }), "valid"); + m.add(fun([](FutureType &t) { return t.get(); }), "get"); + m.add(fun(&FutureType::wait), "wait"); + } +} // namespace chaiscript::bootstrap::standard_library #endif - - diff --git a/include/chaiscript/dispatchkit/boxed_cast.hpp b/include/chaiscript/dispatchkit/boxed_cast.hpp index 4b6e4d79..d4dd5883 100644 --- a/include/chaiscript/dispatchkit/boxed_cast.hpp +++ b/include/chaiscript/dispatchkit/boxed_cast.hpp @@ -7,7 +7,6 @@ // This is an open source non-commercial project. Dear PVS-Studio, please check it. // PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com - #ifndef CHAISCRIPT_BOXED_CAST_HPP_ #define CHAISCRIPT_BOXED_CAST_HPP_ @@ -19,23 +18,19 @@ #include "type_info.hpp" namespace chaiscript { -class Type_Conversions; -namespace detail { -namespace exception { -class bad_any_cast; -} // namespace exception -} // namespace detail -} // namespace chaiscript + class Type_Conversions; +} +namespace chaiscript::detail::exception { + class bad_any_cast; +} // namespace chaiscript::detail::exception -namespace chaiscript -{ - +namespace chaiscript { /// \brief Function for extracting a value stored in a Boxed_Value object /// \tparam Type The type to extract from the Boxed_Value /// \param[in] bv The Boxed_Value to extract a typed value from - /// \returns Type equivalent to the requested type + /// \returns Type equivalent to the requested type /// \throws exception::bad_boxed_cast If the requested conversion is not possible - /// + /// /// boxed_cast will attempt to make conversions between value, &, *, std::shared_ptr, std::reference_wrapper, /// and std::function (const and non-const) where possible. boxed_cast is used internally during function /// dispatch. This means that all of these conversions will be attempted automatically for you during @@ -67,47 +62,41 @@ namespace chaiscript /// std::function conversion example /// \code /// chaiscript::ChaiScript chai; - /// Boxed_Value bv = chai.eval("`+`"); // Get the functor for the + operator which is built in + /// Boxed_Value bv = chai.eval("`+`"); // Get the functor for the + operator which is built in /// std::function f = chaiscript::boxed_cast >(bv); /// int i = f(2,3); /// assert(i == 5); /// \endcode template - 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()) || (t_conversions && !(*t_conversions)->convertable_type())) { try { - return(detail::Cast_Helper::cast(bv, t_conversions)); + return detail::Cast_Helper::cast(bv, t_conversions); } catch (const chaiscript::detail::exception::bad_any_cast &) { } } - - if (t_conversions && (*t_conversions)->convertable_type()) - { + if (t_conversions && (*t_conversions)->convertable_type()) { try { // We will not catch any bad_boxed_dynamic_cast that is thrown, let the user get it // either way, we are not responsible if it doesn't work - return(detail::Cast_Helper::cast((*t_conversions)->boxed_type_conversion(t_conversions->saves(), bv), t_conversions)); + return (detail::Cast_Helper::cast((*t_conversions)->boxed_type_conversion(t_conversions->saves(), bv), t_conversions)); } catch (...) { try { // try going the other way - return(detail::Cast_Helper::cast((*t_conversions)->boxed_type_down_conversion(t_conversions->saves(), bv), t_conversions)); + return (detail::Cast_Helper::cast((*t_conversions)->boxed_type_down_conversion(t_conversions->saves(), bv), + t_conversions)); } catch (const chaiscript::detail::exception::bad_any_cast &) { throw exception::bad_boxed_cast(bv.get_type_info(), typeid(Type)); } } } else { - // If it's not convertable, just throw the error, don't waste the time on the + // If it's not convertable, just throw the error, don't waste the time on the // attempted dynamic_cast throw exception::bad_boxed_cast(bv.get_type_info(), typeid(Type)); } - } -} - - +} // namespace chaiscript #endif - diff --git a/include/chaiscript/dispatchkit/boxed_cast_helper.hpp b/include/chaiscript/dispatchkit/boxed_cast_helper.hpp index ad26c296..fc547b18 100644 --- a/include/chaiscript/dispatchkit/boxed_cast_helper.hpp +++ b/include/chaiscript/dispatchkit/boxed_cast_helper.hpp @@ -7,7 +7,6 @@ // This is an open source non-commercial project. Dear PVS-Studio, please check it. // PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com - #ifndef CHAISCRIPT_BOXED_CAST_HELPER_HPP_ #define CHAISCRIPT_BOXED_CAST_HELPER_HPP_ @@ -17,21 +16,19 @@ #include "boxed_value.hpp" #include "type_info.hpp" - -namespace chaiscript -{ +namespace chaiscript { class Type_Conversions_State; - namespace detail - { + namespace detail { // Cast_Helper_Inner helper classes template - constexpr T* throw_if_null(T *t) - { - if (t) { return t; } - throw std::runtime_error("Attempted to dereference null Boxed_Value"); + constexpr T *throw_if_null(T *t) { + if (t) { + return t; } + throw std::runtime_error("Attempted to dereference null Boxed_Value"); + } template static const T *verify_type_no_throw(const Boxed_Value &ob, const std::type_info &ti, const T *ptr) { @@ -51,7 +48,6 @@ namespace chaiscript } } - template 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)) { @@ -72,252 +68,193 @@ namespace chaiscript /// Generic Cast_Helper_Inner, for casting to any type template - struct Cast_Helper_Inner - { - static Result cast(const Boxed_Value &ob, const Type_Conversions_State *) - { - return *static_cast(verify_type(ob, typeid(Result), ob.get_const_ptr())); - } - }; + struct Cast_Helper_Inner { + static Result cast(const Boxed_Value &ob, const Type_Conversions_State *) { + return *static_cast(verify_type(ob, typeid(Result), ob.get_const_ptr())); + } + }; template - struct Cast_Helper_Inner : Cast_Helper_Inner - { - }; - + struct Cast_Helper_Inner : Cast_Helper_Inner { + }; /// Cast_Helper_Inner for casting to a const * type template - struct Cast_Helper_Inner - { - static const Result * cast(const Boxed_Value &ob, const Type_Conversions_State *) - { - return static_cast(verify_type_no_throw(ob, typeid(Result), ob.get_const_ptr())); - } - }; + struct Cast_Helper_Inner { + static const Result *cast(const Boxed_Value &ob, const Type_Conversions_State *) { + return static_cast(verify_type_no_throw(ob, typeid(Result), ob.get_const_ptr())); + } + }; /// Cast_Helper_Inner for casting to a * type template - struct Cast_Helper_Inner - { - static Result * cast(const Boxed_Value &ob, const Type_Conversions_State *) - { - return static_cast(verify_type_no_throw(ob, typeid(Result), ob.get_ptr())); - } - }; - - template - struct Cast_Helper_Inner : public Cast_Helper_Inner - { + struct Cast_Helper_Inner { + static Result *cast(const Boxed_Value &ob, const Type_Conversions_State *) { + return static_cast(verify_type_no_throw(ob, typeid(Result), ob.get_ptr())); + } }; template - struct Cast_Helper_Inner : public Cast_Helper_Inner - { + struct Cast_Helper_Inner : public Cast_Helper_Inner { }; + template + struct Cast_Helper_Inner : public Cast_Helper_Inner { + }; /// Cast_Helper_Inner for casting to a & type template - struct Cast_Helper_Inner - { - static const Result & cast(const Boxed_Value &ob, const Type_Conversions_State *) - { - return *static_cast(verify_type(ob, typeid(Result), ob.get_const_ptr())); - } - }; - - + struct Cast_Helper_Inner { + static const Result &cast(const Boxed_Value &ob, const Type_Conversions_State *) { + return *static_cast(verify_type(ob, typeid(Result), ob.get_const_ptr())); + } + }; /// Cast_Helper_Inner for casting to a & type template - struct Cast_Helper_Inner - { - static Result& cast(const Boxed_Value &ob, const Type_Conversions_State *) - { - return *static_cast(verify_type(ob, typeid(Result), ob.get_ptr())); - } - }; + struct Cast_Helper_Inner { + static Result &cast(const Boxed_Value &ob, const Type_Conversions_State *) { + return *static_cast(verify_type(ob, typeid(Result), ob.get_ptr())); + } + }; /// Cast_Helper_Inner for casting to a && type template - struct Cast_Helper_Inner - { - static Result&& cast(const Boxed_Value &ob, const Type_Conversions_State *) - { - return std::move(*static_cast(verify_type(ob, typeid(Result), ob.get_ptr()))); - } - }; + struct Cast_Helper_Inner { + static Result &&cast(const Boxed_Value &ob, const Type_Conversions_State *) { + return std::move(*static_cast(verify_type(ob, typeid(Result), ob.get_ptr()))); + } + }; /// 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 template - struct Cast_Helper_Inner &&> - { - static std::unique_ptr &&cast(const Boxed_Value &ob, const Type_Conversions_State *) - { - return std::move(*(ob.get().cast>>())); - } - }; + struct Cast_Helper_Inner &&> { + static std::unique_ptr &&cast(const Boxed_Value &ob, const Type_Conversions_State *) { + return std::move(*(ob.get().cast>>())); + } + }; /// 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 template - struct Cast_Helper_Inner &> - { - static std::unique_ptr &cast(const Boxed_Value &ob, const Type_Conversions_State *) - { - return *(ob.get().cast>>()); - } - }; + struct Cast_Helper_Inner &> { + static std::unique_ptr &cast(const Boxed_Value &ob, const Type_Conversions_State *) { + return *(ob.get().cast>>()); + } + }; /// 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 template - struct Cast_Helper_Inner &> - { - static std::unique_ptr &cast(const Boxed_Value &ob, const Type_Conversions_State *) - { - return *(ob.get().cast>>()); - } - }; - + struct Cast_Helper_Inner &> { + static std::unique_ptr &cast(const Boxed_Value &ob, const Type_Conversions_State *) { + return *(ob.get().cast>>()); + } + }; /// Cast_Helper_Inner for casting to a std::shared_ptr<> type template - struct Cast_Helper_Inner > - { - static auto cast(const Boxed_Value &ob, const Type_Conversions_State *) - { - return ob.get().cast >(); - } - }; + struct Cast_Helper_Inner> { + static auto cast(const Boxed_Value &ob, const Type_Conversions_State *) { return ob.get().cast>(); } + }; /// Cast_Helper_Inner for casting to a std::shared_ptr type template - struct Cast_Helper_Inner > - { - static auto cast(const Boxed_Value &ob, const Type_Conversions_State *) - { - if (!ob.get_type_info().is_const()) - { - return std::const_pointer_cast(ob.get().cast >()); - } else { - return ob.get().cast >(); - } + struct Cast_Helper_Inner> { + static auto cast(const Boxed_Value &ob, const Type_Conversions_State *) { + if (!ob.get_type_info().is_const()) { + return std::const_pointer_cast(ob.get().cast>()); + } else { + return ob.get().cast>(); } - }; + } + }; /// Cast_Helper_Inner for casting to a const std::shared_ptr<> & type template - struct Cast_Helper_Inner > : Cast_Helper_Inner > - { - }; + struct Cast_Helper_Inner> : Cast_Helper_Inner> { + }; template - struct Cast_Helper_Inner &> : Cast_Helper_Inner > - { - }; + struct Cast_Helper_Inner &> : Cast_Helper_Inner> { + }; template - struct Cast_Helper_Inner &> - { - static_assert(!std::is_const::value, "Non-const reference to std::shared_ptr is not supported"); - static auto cast(const Boxed_Value &ob, const Type_Conversions_State *) - { - std::shared_ptr &res = ob.get().cast >(); - return ob.pointer_sentinel(res); - } - }; - + struct Cast_Helper_Inner &> { + static_assert(!std::is_const::value, "Non-const reference to std::shared_ptr is not supported"); + static auto cast(const Boxed_Value &ob, const Type_Conversions_State *) { + std::shared_ptr &res = ob.get().cast>(); + return ob.pointer_sentinel(res); + } + }; /// Cast_Helper_Inner for casting to a const std::shared_ptr & type template - struct Cast_Helper_Inner > : Cast_Helper_Inner > - { - }; + struct Cast_Helper_Inner> : Cast_Helper_Inner> { + }; template - struct Cast_Helper_Inner &> : Cast_Helper_Inner > - { - }; - + struct Cast_Helper_Inner &> : Cast_Helper_Inner> { + }; /// Cast_Helper_Inner for casting to a Boxed_Value type template<> - struct Cast_Helper_Inner - { - static Boxed_Value cast(const Boxed_Value &ob, const Type_Conversions_State *) - { - return ob; - } - }; + struct Cast_Helper_Inner { + static Boxed_Value cast(const Boxed_Value &ob, const Type_Conversions_State *) { return ob; } + }; /// Cast_Helper_Inner for casting to a Boxed_Value & type template<> - struct Cast_Helper_Inner - { - static std::reference_wrapper cast(const Boxed_Value &ob, const Type_Conversions_State *) - { - return std::ref(const_cast(ob)); - } - }; - + struct Cast_Helper_Inner { + static std::reference_wrapper cast(const Boxed_Value &ob, const Type_Conversions_State *) { + return std::ref(const_cast(ob)); + } + }; /// Cast_Helper_Inner for casting to a const Boxed_Value & type template<> - struct Cast_Helper_Inner : Cast_Helper_Inner - { - }; + struct Cast_Helper_Inner : Cast_Helper_Inner { + }; template<> - struct Cast_Helper_Inner : Cast_Helper_Inner - { - }; - + struct Cast_Helper_Inner : Cast_Helper_Inner { + }; /// Cast_Helper_Inner for casting to a std::reference_wrapper type template - struct Cast_Helper_Inner > : Cast_Helper_Inner - { - }; + struct Cast_Helper_Inner> : Cast_Helper_Inner { + }; template - struct Cast_Helper_Inner > : Cast_Helper_Inner - { - }; + struct Cast_Helper_Inner> : Cast_Helper_Inner { + }; template - struct Cast_Helper_Inner &> : Cast_Helper_Inner - { - }; + struct Cast_Helper_Inner &> : Cast_Helper_Inner { + }; template - struct Cast_Helper_Inner > : Cast_Helper_Inner - { - }; + struct Cast_Helper_Inner> : Cast_Helper_Inner { + }; template - struct Cast_Helper_Inner > : Cast_Helper_Inner - { - }; + struct Cast_Helper_Inner> : Cast_Helper_Inner { + }; template - struct Cast_Helper_Inner & > : Cast_Helper_Inner - { - }; + struct Cast_Helper_Inner &> : Cast_Helper_Inner { + }; /// The exposed Cast_Helper object that by default just calls the Cast_Helper_Inner template - struct Cast_Helper - { - static decltype(auto) cast(const Boxed_Value &ob, const Type_Conversions_State *t_conversions) - { - return(Cast_Helper_Inner::cast(ob, t_conversions)); - } - }; - } - -} + struct Cast_Helper { + static decltype(auto) cast(const Boxed_Value &ob, const Type_Conversions_State *t_conversions) { + return (Cast_Helper_Inner::cast(ob, t_conversions)); + } + }; + } // namespace detail + +} // namespace chaiscript #endif diff --git a/include/chaiscript/dispatchkit/boxed_number.hpp b/include/chaiscript/dispatchkit/boxed_number.hpp index 357f4cb0..816fe5a3 100644 --- a/include/chaiscript/dispatchkit/boxed_number.hpp +++ b/include/chaiscript/dispatchkit/boxed_number.hpp @@ -22,25 +22,20 @@ #include "type_info.hpp" namespace chaiscript { -class Type_Conversions; -} // namespace chaiscript + class Type_Conversions; +} // namespace chaiscript -namespace chaiscript -{ - namespace exception - { - 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() noexcept override = default; - }; - } -} - -namespace chaiscript -{ +namespace chaiscript::exception { + 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() noexcept override = default; + }; +} // namespace chaiscript::exception +namespace chaiscript { // Due to the nature of generating every possible arithmetic operation, there // 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 @@ -49,7 +44,6 @@ namespace chaiscript #pragma warning(disable : 4244 4018 4389 4146 4365 4267 4242) #endif - #ifdef __GNUC__ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunknown-pragmas" @@ -63,738 +57,648 @@ namespace chaiscript #endif /// \brief Represents any numeric type, generically. Used internally for generic operations between POD values - class Boxed_Number - { - private: - enum class Common_Types { - t_int32, - t_double, - t_uint8, - t_int8, - t_uint16, - t_int16, - t_uint32, - t_uint64, - t_int64, - t_float, - t_long_double - }; + class Boxed_Number { + private: + enum class Common_Types { + t_int32, + t_double, + t_uint8, + t_int8, + t_uint16, + t_int16, + t_uint32, + t_uint64, + t_int64, + t_float, + t_long_double + }; - template - constexpr static inline void check_divide_by_zero([[maybe_unused]] T t) - { + template + constexpr static inline void check_divide_by_zero([[maybe_unused]] T t) { #ifndef CHAISCRIPT_NO_PROTECT_DIVIDEBYZERO - if constexpr (!std::is_floating_point::value) { - if (t == 0) { - throw chaiscript::exception::arithmetic_error("divide by zero"); - } + if constexpr (!std::is_floating_point::value) { + if (t == 0) { + throw chaiscript::exception::arithmetic_error("divide by zero"); } + } #endif + } + + constexpr static Common_Types get_common_type(size_t t_size, bool t_signed) noexcept { + return (t_size == 1 && t_signed) ? (Common_Types::t_int8) + : (t_size == 1) ? (Common_Types::t_uint8) + : (t_size == 2 && t_signed) ? (Common_Types::t_int16) + : (t_size == 2) ? (Common_Types::t_uint16) + : (t_size == 4 && t_signed) ? (Common_Types::t_int32) + : (t_size == 4) ? (Common_Types::t_uint32) + : (t_size == 8 && t_signed) ? (Common_Types::t_int64) + : (Common_Types::t_uint64); + } + + static Common_Types get_common_type(const Boxed_Value &t_bv) { + const Type_Info &inp_ = t_bv.get_type_info(); + + if (inp_ == user_type()) { + return get_common_type(sizeof(int), true); + } else if (inp_ == user_type()) { + return Common_Types::t_double; + } else if (inp_ == user_type()) { + return Common_Types::t_long_double; + } else if (inp_ == user_type()) { + return Common_Types::t_float; + } else if (inp_ == user_type()) { + return get_common_type(sizeof(char), std::is_signed::value); + } else if (inp_ == user_type()) { + return get_common_type(sizeof(unsigned char), false); + } else if (inp_ == user_type()) { + return get_common_type(sizeof(unsigned int), false); + } else if (inp_ == user_type()) { + return get_common_type(sizeof(long), true); + } else if (inp_ == user_type()) { + return get_common_type(sizeof(long long), true); + } else if (inp_ == user_type()) { + return get_common_type(sizeof(unsigned long), false); + } else if (inp_ == user_type()) { + return get_common_type(sizeof(unsigned long long), false); + } else if (inp_ == user_type()) { + return Common_Types::t_int8; + } else if (inp_ == user_type()) { + return Common_Types::t_int16; + } else if (inp_ == user_type()) { + return Common_Types::t_int32; + } else if (inp_ == user_type()) { + return Common_Types::t_int64; + } else if (inp_ == user_type()) { + return Common_Types::t_uint8; + } else if (inp_ == user_type()) { + return Common_Types::t_uint16; + } else if (inp_ == user_type()) { + return Common_Types::t_uint32; + } else if (inp_ == user_type()) { + return Common_Types::t_uint64; + } else if (inp_ == user_type()) { + return get_common_type(sizeof(wchar_t), std::is_signed::value); + } else if (inp_ == user_type()) { + return get_common_type(sizeof(char16_t), std::is_signed::value); + } else if (inp_ == user_type()) { + return get_common_type(sizeof(char32_t), std::is_signed::value); + } else { + throw chaiscript::detail::exception::bad_any_cast(); + } + } + + template + 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) { + case Operators::Opers::equals: + return const_var(c_lhs == c_rhs); + case Operators::Opers::less_than: + return const_var(c_lhs < c_rhs); + case Operators::Opers::greater_than: + return const_var(c_lhs > c_rhs); + case Operators::Opers::less_than_equal: + return const_var(c_lhs <= c_rhs); + case Operators::Opers::greater_than_equal: + return const_var(c_lhs >= c_rhs); + case Operators::Opers::not_equal: + return const_var(c_lhs != c_rhs); + case Operators::Opers::sum: + return const_var(c_lhs + c_rhs); + case Operators::Opers::quotient: + check_divide_by_zero(c_rhs); + return const_var(c_lhs / c_rhs); + case Operators::Opers::product: + return const_var(c_lhs * c_rhs); + case Operators::Opers::difference: + return const_var(c_lhs - c_rhs); + default: + break; } - constexpr static Common_Types get_common_type(size_t t_size, bool t_signed) noexcept - { - return (t_size == 1 && t_signed)?(Common_Types::t_int8) - :(t_size == 1)?(Common_Types::t_uint8) - :(t_size == 2 && t_signed)?(Common_Types::t_int16) - :(t_size == 2)?(Common_Types::t_uint16) - :(t_size == 4 && t_signed)?(Common_Types::t_int32) - :(t_size == 4)?(Common_Types::t_uint32) - :(t_size == 8 && t_signed)?(Common_Types::t_int64) - :(Common_Types::t_uint64); - } - - - static Common_Types get_common_type(const Boxed_Value &t_bv) - { - const Type_Info &inp_ = t_bv.get_type_info(); - - if (inp_ == user_type()) { - return get_common_type(sizeof(int), true); - } else if (inp_ == user_type()) { - return Common_Types::t_double; - } else if (inp_ == user_type()) { - return Common_Types::t_long_double; - } else if (inp_ == user_type()) { - return Common_Types::t_float; - } else if (inp_ == user_type()) { - return get_common_type(sizeof(char), std::is_signed::value); - } else if (inp_ == user_type()) { - return get_common_type(sizeof(unsigned char), false); - } else if (inp_ == user_type()) { - return get_common_type(sizeof(unsigned int), false); - } else if (inp_ == user_type()) { - return get_common_type(sizeof(long), true); - } else if (inp_ == user_type()) { - return get_common_type(sizeof(long long), true); - } else if (inp_ == user_type()) { - return get_common_type(sizeof(unsigned long), false); - } else if (inp_ == user_type()) { - return get_common_type(sizeof(unsigned long long), false); - } else if (inp_ == user_type()) { - return Common_Types::t_int8; - } else if (inp_ == user_type()) { - return Common_Types::t_int16; - } else if (inp_ == user_type()) { - return Common_Types::t_int32; - } else if (inp_ == user_type()) { - return Common_Types::t_int64; - } else if (inp_ == user_type()) { - return Common_Types::t_uint8; - } else if (inp_ == user_type()) { - return Common_Types::t_uint16; - } else if (inp_ == user_type()) { - return Common_Types::t_uint32; - } else if (inp_ == user_type()) { - return Common_Types::t_uint64; - } else if (inp_ == user_type()) { - return get_common_type(sizeof(wchar_t), std::is_signed::value); - } else if (inp_ == user_type()) { - return get_common_type(sizeof(char16_t), std::is_signed::value); - } else if (inp_ == user_type()) { - return get_common_type(sizeof(char32_t), std::is_signed::value); - } else { - throw chaiscript::detail::exception::bad_any_cast(); - } - } - - - - template - static auto go(Operators::Opers t_oper, const Boxed_Value &t_bv, LHS *t_lhs, const LHS &c_lhs, const RHS &c_rhs) - { + if constexpr (!std::is_floating_point::value && !std::is_floating_point::value) { switch (t_oper) { - case Operators::Opers::equals: - return const_var(c_lhs == c_rhs); - case Operators::Opers::less_than: - return const_var(c_lhs < c_rhs); - case Operators::Opers::greater_than: - return const_var(c_lhs > c_rhs); - case Operators::Opers::less_than_equal: - return const_var(c_lhs <= c_rhs); - case Operators::Opers::greater_than_equal: - return const_var(c_lhs >= c_rhs); - case Operators::Opers::not_equal: - return const_var(c_lhs != c_rhs); - case Operators::Opers::sum: - return const_var(c_lhs + c_rhs); - case Operators::Opers::quotient: + case Operators::Opers::shift_left: + return const_var(c_lhs << c_rhs); + case Operators::Opers::shift_right: + return const_var(c_lhs >> c_rhs); + case Operators::Opers::remainder: check_divide_by_zero(c_rhs); - return const_var(c_lhs / c_rhs); - case Operators::Opers::product: - return const_var(c_lhs * c_rhs); - case Operators::Opers::difference: - return const_var(c_lhs - c_rhs); + return const_var(c_lhs % c_rhs); + case Operators::Opers::bitwise_and: + return const_var(c_lhs & c_rhs); + case Operators::Opers::bitwise_or: + return const_var(c_lhs | c_rhs); + case Operators::Opers::bitwise_xor: + return const_var(c_lhs ^ c_rhs); default: break; - } + } + } + if (t_lhs) { + switch (t_oper) { + case Operators::Opers::assign: + *t_lhs = c_rhs; + return t_bv; + case Operators::Opers::assign_product: + *t_lhs *= c_rhs; + return t_bv; + case Operators::Opers::assign_sum: + *t_lhs += c_rhs; + return t_bv; + case Operators::Opers::assign_quotient: + check_divide_by_zero(c_rhs); + *t_lhs /= c_rhs; + return t_bv; + case Operators::Opers::assign_difference: + *t_lhs -= c_rhs; + return t_bv; + default: + break; + } if constexpr (!std::is_floating_point::value && !std::is_floating_point::value) { switch (t_oper) { - case Operators::Opers::shift_left: - return const_var(c_lhs << c_rhs); - case Operators::Opers::shift_right: - return const_var(c_lhs >> c_rhs); - case Operators::Opers::remainder: + case Operators::Opers::assign_bitwise_and: check_divide_by_zero(c_rhs); - return const_var(c_lhs % c_rhs); - case Operators::Opers::bitwise_and: - return const_var(c_lhs & c_rhs); - case Operators::Opers::bitwise_or: - return const_var(c_lhs | c_rhs); - case Operators::Opers::bitwise_xor: - return const_var(c_lhs ^ c_rhs); + *t_lhs &= c_rhs; + return t_bv; + case Operators::Opers::assign_bitwise_or: + *t_lhs |= c_rhs; + return t_bv; + case Operators::Opers::assign_shift_left: + *t_lhs <<= c_rhs; + return t_bv; + case Operators::Opers::assign_shift_right: + *t_lhs >>= c_rhs; + return t_bv; + case Operators::Opers::assign_remainder: + *t_lhs %= c_rhs; + return t_bv; + case Operators::Opers::assign_bitwise_xor: + *t_lhs ^= c_rhs; + return t_bv; default: break; - } + } + } + } + + throw chaiscript::detail::exception::bad_any_cast(); + } + + template + inline static auto visit(const Boxed_Value &bv, Callable &&callable) { + switch (get_common_type(bv)) { + case Common_Types::t_int32: + return callable(*static_cast(bv.get_const_ptr())); + case Common_Types::t_uint8: + return callable(*static_cast(bv.get_const_ptr())); + case Common_Types::t_int8: + return callable(*static_cast(bv.get_const_ptr())); + case Common_Types::t_uint16: + return callable(*static_cast(bv.get_const_ptr())); + case Common_Types::t_int16: + return callable(*static_cast(bv.get_const_ptr())); + case Common_Types::t_uint32: + return callable(*static_cast(bv.get_const_ptr())); + case Common_Types::t_uint64: + return callable(*static_cast(bv.get_const_ptr())); + case Common_Types::t_int64: + return callable(*static_cast(bv.get_const_ptr())); + case Common_Types::t_double: + return callable(*static_cast(bv.get_const_ptr())); + case Common_Types::t_float: + return callable(*static_cast(bv.get_const_ptr())); + case Common_Types::t_long_double: + return callable(*static_cast(bv.get_const_ptr())); + } + throw chaiscript::detail::exception::bad_any_cast(); + } + + 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 *lhs = static_cast *>(t_lhs.get_ptr()); + + if (lhs) { + switch (t_oper) { + case Operators::Opers::pre_increment: + ++(*lhs); + return t_lhs; + case Operators::Opers::pre_decrement: + --(*lhs); + return t_lhs; + default: + break; + } } - if (t_lhs) { + switch (t_oper) { + case Operators::Opers::unary_minus: + return const_var(-c_lhs); + case Operators::Opers::unary_plus: + return const_var(+c_lhs); + default: + break; + } + + if constexpr (!std::is_floating_point_v>) { switch (t_oper) { - case Operators::Opers::assign: - *t_lhs = c_rhs; - return t_bv; - case Operators::Opers::assign_product: - *t_lhs *= c_rhs; - return t_bv; - case Operators::Opers::assign_sum: - *t_lhs += c_rhs; - return t_bv; - case Operators::Opers::assign_quotient: - check_divide_by_zero(c_rhs); - *t_lhs /= c_rhs; - return t_bv; - case Operators::Opers::assign_difference: - *t_lhs -= c_rhs; - return t_bv; + case Operators::Opers::bitwise_complement: + return const_var(~c_lhs); default: break; - } - - if constexpr (!std::is_floating_point::value && !std::is_floating_point::value) { - switch (t_oper) { - case Operators::Opers::assign_bitwise_and: - check_divide_by_zero(c_rhs); - *t_lhs &= c_rhs; - return t_bv; - case Operators::Opers::assign_bitwise_or: - *t_lhs |= c_rhs; - return t_bv; - case Operators::Opers::assign_shift_left: - *t_lhs <<= c_rhs; - return t_bv; - case Operators::Opers::assign_shift_right: - *t_lhs >>= c_rhs; - return t_bv; - case Operators::Opers::assign_remainder: - *t_lhs %= c_rhs; - return t_bv; - case Operators::Opers::assign_bitwise_xor: - *t_lhs ^= c_rhs; - return t_bv; - default: - break; - } } } throw chaiscript::detail::exception::bad_any_cast(); + }; + + return visit(t_lhs, unary_operator); + } + + inline static Boxed_Value oper(Operators::Opers t_oper, const Boxed_Value &t_lhs, const Boxed_Value &t_rhs) { + auto lhs_visit = [t_oper, &t_lhs, &t_rhs](const auto &c_lhs) { + auto *lhs = t_lhs.is_return_value() ? nullptr : static_cast *>(t_lhs.get_ptr()); + + auto rhs_visit = [t_oper, &t_lhs, lhs, &c_lhs](const auto &c_rhs) { return go(t_oper, t_lhs, lhs, c_lhs, c_rhs); }; + + return visit(t_rhs, rhs_visit); + }; + + return visit(t_lhs, lhs_visit); + } + + template + static inline Target get_as_aux(const Boxed_Value &t_bv) { + return static_cast(*static_cast(t_bv.get_const_ptr())); + } + + template + static std::string to_string_aux(const Boxed_Value &v) { + std::ostringstream oss; + oss << *static_cast(v.get_const_ptr()); + return oss.str(); + } + + public: + Boxed_Number() + : bv(Boxed_Value(0)) { + } + + explicit Boxed_Number(Boxed_Value v) + : bv(std::move(v)) { + validate_boxed_number(bv); + } + + Boxed_Number(const Boxed_Number &) = default; + Boxed_Number(Boxed_Number &&) = default; + Boxed_Number &operator=(Boxed_Number &&) = default; + + template + explicit Boxed_Number(T t) + : bv(Boxed_Value(t)) { + validate_boxed_number(bv); + } + + static Boxed_Value clone(const Boxed_Value &t_bv) { return Boxed_Number(t_bv).get_as(t_bv.get_type_info()).bv; } + + static bool is_floating_point(const Boxed_Value &t_bv) { + const Type_Info &inp_ = t_bv.get_type_info(); + + if (inp_ == user_type()) { + return true; + } else if (inp_ == user_type()) { + return true; + } else if (inp_ == user_type()) { + return true; + } else { + return false; } + } - template - inline static auto visit(const Boxed_Value &bv, Callable &&callable) - { - switch (get_common_type(bv)) { - case Common_Types::t_int32: - return callable(*static_cast(bv.get_const_ptr())); - case Common_Types::t_uint8: - return callable(*static_cast(bv.get_const_ptr())); - case Common_Types::t_int8: - return callable(*static_cast(bv.get_const_ptr())); - case Common_Types::t_uint16: - return callable(*static_cast(bv.get_const_ptr())); - case Common_Types::t_int16: - return callable(*static_cast(bv.get_const_ptr())); - case Common_Types::t_uint32: - return callable(*static_cast(bv.get_const_ptr())); - case Common_Types::t_uint64: - return callable(*static_cast(bv.get_const_ptr())); - case Common_Types::t_int64: - return callable(*static_cast(bv.get_const_ptr())); - case Common_Types::t_double: - return callable(*static_cast(bv.get_const_ptr())); - case Common_Types::t_float: - return callable(*static_cast(bv.get_const_ptr())); - case Common_Types::t_long_double: - return callable(*static_cast(bv.get_const_ptr())); - } - throw chaiscript::detail::exception::bad_any_cast(); - } - - 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 *lhs = static_cast *>(t_lhs.get_ptr()); - - if (lhs) { - switch (t_oper) { - case Operators::Opers::pre_increment: - ++(*lhs); - return t_lhs; - case Operators::Opers::pre_decrement: - --(*lhs); - return t_lhs; - default: - break; - } - } - - switch (t_oper) { - case Operators::Opers::unary_minus: - return const_var(-c_lhs); - case Operators::Opers::unary_plus: - return const_var(+c_lhs); - default: - break; - } - - if constexpr (!std::is_floating_point_v>) { - switch (t_oper) { - case Operators::Opers::bitwise_complement: - return const_var(~c_lhs); - default: - break; - } - } - - throw chaiscript::detail::exception::bad_any_cast(); - }; - - return visit(t_lhs, unary_operator); - } - - - inline static Boxed_Value oper(Operators::Opers t_oper, const Boxed_Value &t_lhs, const Boxed_Value &t_rhs) - { - - auto lhs_visit = [t_oper, &t_lhs, &t_rhs](const auto &c_lhs){ - auto *lhs = t_lhs.is_return_value()?nullptr:static_cast *>(t_lhs.get_ptr()); - - auto rhs_visit = [t_oper, &t_lhs, lhs, &c_lhs](const auto &c_rhs) { - return go(t_oper, t_lhs, lhs, c_lhs, c_rhs); - }; - - return visit(t_rhs, rhs_visit); - }; - - return visit(t_lhs, lhs_visit); - } - - template - static inline Target get_as_aux(const Boxed_Value &t_bv) - { - return static_cast(*static_cast(t_bv.get_const_ptr())); - } - - template - static std::string to_string_aux(const Boxed_Value &v) - { - std::ostringstream oss; - oss << *static_cast(v.get_const_ptr()); - return oss.str(); - } - - public: - Boxed_Number() - : bv(Boxed_Value(0)) - { + Boxed_Number get_as(const Type_Info &inp_) const { + if (inp_.bare_equal(user_type())) { + return Boxed_Number(get_as()); + } else if (inp_.bare_equal(user_type())) { + return Boxed_Number(get_as()); + } else if (inp_.bare_equal(user_type())) { + return Boxed_Number(get_as()); + } else if (inp_.bare_equal(user_type())) { + return Boxed_Number(get_as()); + } else if (inp_.bare_equal(user_type())) { + return Boxed_Number(get_as()); + } else if (inp_.bare_equal(user_type())) { + return Boxed_Number(get_as()); + } else if (inp_.bare_equal(user_type())) { + return Boxed_Number(get_as()); + } else if (inp_.bare_equal(user_type())) { + return Boxed_Number(get_as()); + } else if (inp_.bare_equal(user_type())) { + return Boxed_Number(get_as()); + } else if (inp_.bare_equal(user_type())) { + return Boxed_Number(get_as()); + } else if (inp_.bare_equal(user_type())) { + return Boxed_Number(get_as()); + } else if (inp_.bare_equal(user_type())) { + return Boxed_Number(get_as()); + } else if (inp_.bare_equal(user_type())) { + return Boxed_Number(get_as()); + } else if (inp_.bare_equal(user_type())) { + return Boxed_Number(get_as()); + } else if (inp_.bare_equal(user_type())) { + return Boxed_Number(get_as()); + } else if (inp_.bare_equal(user_type())) { + return Boxed_Number(get_as()); + } else if (inp_.bare_equal(user_type())) { + return Boxed_Number(get_as()); + } else if (inp_.bare_equal(user_type())) { + return Boxed_Number(get_as()); + } else if (inp_.bare_equal(user_type())) { + return Boxed_Number(get_as()); + } else if (inp_.bare_equal(user_type())) { + return Boxed_Number(get_as()); + } else if (inp_.bare_equal(user_type())) { + return Boxed_Number(get_as()); + } else if (inp_.bare_equal(user_type())) { + return Boxed_Number(get_as()); + } else { + throw chaiscript::detail::exception::bad_any_cast(); } + } - explicit Boxed_Number(Boxed_Value v) - : bv(std::move(v)) - { - validate_boxed_number(bv); - } - - Boxed_Number(const Boxed_Number &) = default; - Boxed_Number(Boxed_Number &&) = default; - Boxed_Number& operator=(Boxed_Number &&) = default; - - template explicit Boxed_Number(T t) - : bv(Boxed_Value(t)) - { - validate_boxed_number(bv); - } - - static Boxed_Value clone(const Boxed_Value &t_bv) { - return Boxed_Number(t_bv).get_as(t_bv.get_type_info()).bv; - } - - static bool is_floating_point(const Boxed_Value &t_bv) - { - const Type_Info &inp_ = t_bv.get_type_info(); - - if (inp_ == user_type()) { - return true; - } else if (inp_ == user_type()) { - return true; - } else if (inp_ == user_type()) { - return true; - } else { - return false; - } - } - - Boxed_Number get_as(const Type_Info &inp_) const - { - if (inp_.bare_equal(user_type())) { - return Boxed_Number(get_as()); - } else if (inp_.bare_equal(user_type())) { - return Boxed_Number(get_as()); - } else if (inp_.bare_equal(user_type())) { - return Boxed_Number(get_as()); - } else if (inp_.bare_equal(user_type())) { - return Boxed_Number(get_as()); - } else if (inp_.bare_equal(user_type())) { - return Boxed_Number(get_as()); - } else if (inp_.bare_equal(user_type())) { - return Boxed_Number(get_as()); - } else if (inp_.bare_equal(user_type())) { - return Boxed_Number(get_as()); - } else if (inp_.bare_equal(user_type())) { - return Boxed_Number(get_as()); - } else if (inp_.bare_equal(user_type())) { - return Boxed_Number(get_as()); - } else if (inp_.bare_equal(user_type())) { - return Boxed_Number(get_as()); - } else if (inp_.bare_equal(user_type())) { - return Boxed_Number(get_as()); - } else if (inp_.bare_equal(user_type())) { - return Boxed_Number(get_as()); - } else if (inp_.bare_equal(user_type())) { - return Boxed_Number(get_as()); - } else if (inp_.bare_equal(user_type())) { - return Boxed_Number(get_as()); - } else if (inp_.bare_equal(user_type())) { - return Boxed_Number(get_as()); - } else if (inp_.bare_equal(user_type())) { - return Boxed_Number(get_as()); - } else if (inp_.bare_equal(user_type())) { - return Boxed_Number(get_as()); - } else if (inp_.bare_equal(user_type())) { - return Boxed_Number(get_as()); - } else if (inp_.bare_equal(user_type())) { - return Boxed_Number(get_as()); - } else if (inp_.bare_equal(user_type())) { - return Boxed_Number(get_as()); - } else if (inp_.bare_equal(user_type())) { - return Boxed_Number(get_as()); - } else if (inp_.bare_equal(user_type())) { - return Boxed_Number(get_as()); - } else { - throw chaiscript::detail::exception::bad_any_cast(); - } - - } - - template - static void check_type() - { + template + static void check_type() { #ifdef CHAISCRIPT_MSVC // MSVC complains about this being redundant / tautologica l #pragma warning(push) #pragma warning(disable : 4127 6287) #endif - if (sizeof(Source) != sizeof(Target) - || std::is_signed() != std::is_signed() - || std::is_floating_point() != std::is_floating_point()) - { - throw chaiscript::detail::exception::bad_any_cast(); - } + if (sizeof(Source) != sizeof(Target) || std::is_signed() != std::is_signed() + || std::is_floating_point() != std::is_floating_point()) { + throw chaiscript::detail::exception::bad_any_cast(); + } #ifdef CHAISCRIPT_MSVC #pragma warning(pop) #endif + } + + template + Target get_as_checked() const { + switch (get_common_type(bv)) { + case Common_Types::t_int32: + check_type(); + return get_as_aux(bv); + case Common_Types::t_uint8: + check_type(); + return get_as_aux(bv); + case Common_Types::t_int8: + check_type(); + return get_as_aux(bv); + case Common_Types::t_uint16: + check_type(); + return get_as_aux(bv); + case Common_Types::t_int16: + check_type(); + return get_as_aux(bv); + case Common_Types::t_uint32: + check_type(); + return get_as_aux(bv); + case Common_Types::t_uint64: + check_type(); + return get_as_aux(bv); + case Common_Types::t_int64: + check_type(); + return get_as_aux(bv); + case Common_Types::t_double: + check_type(); + return get_as_aux(bv); + case Common_Types::t_float: + check_type(); + return get_as_aux(bv); + case Common_Types::t_long_double: + check_type(); + return get_as_aux(bv); } - template Target get_as_checked() const - { - switch (get_common_type(bv)) { - case Common_Types::t_int32: - check_type(); - return get_as_aux(bv); - case Common_Types::t_uint8: - check_type(); - return get_as_aux(bv); - case Common_Types::t_int8: - check_type(); - return get_as_aux(bv); - case Common_Types::t_uint16: - check_type(); - return get_as_aux(bv); - case Common_Types::t_int16: - check_type(); - return get_as_aux(bv); - case Common_Types::t_uint32: - check_type(); - return get_as_aux(bv); - case Common_Types::t_uint64: - check_type(); - return get_as_aux(bv); - case Common_Types::t_int64: - check_type(); - return get_as_aux(bv); - case Common_Types::t_double: - check_type(); - return get_as_aux(bv); - case Common_Types::t_float: - check_type(); - return get_as_aux(bv); - case Common_Types::t_long_double: - check_type(); - return get_as_aux(bv); - } + throw chaiscript::detail::exception::bad_any_cast(); + } + template + Target get_as() const { + switch (get_common_type(bv)) { + case Common_Types::t_int32: + return get_as_aux(bv); + case Common_Types::t_uint8: + return get_as_aux(bv); + case Common_Types::t_int8: + return get_as_aux(bv); + case Common_Types::t_uint16: + return get_as_aux(bv); + case Common_Types::t_int16: + return get_as_aux(bv); + case Common_Types::t_uint32: + return get_as_aux(bv); + case Common_Types::t_uint64: + return get_as_aux(bv); + case Common_Types::t_int64: + return get_as_aux(bv); + case Common_Types::t_double: + return get_as_aux(bv); + case Common_Types::t_float: + return get_as_aux(bv); + case Common_Types::t_long_double: + return get_as_aux(bv); + } + + throw chaiscript::detail::exception::bad_any_cast(); + } + + std::string to_string() const { + switch (get_common_type(bv)) { + case Common_Types::t_int32: + return std::to_string(get_as()); + case Common_Types::t_uint8: + return std::to_string(get_as()); + case Common_Types::t_int8: + return std::to_string(get_as()); + case Common_Types::t_uint16: + return std::to_string(get_as()); + case Common_Types::t_int16: + return std::to_string(get_as()); + case Common_Types::t_uint32: + return std::to_string(get_as()); + case Common_Types::t_uint64: + return std::to_string(get_as()); + case Common_Types::t_int64: + return std::to_string(get_as()); + case Common_Types::t_double: + return to_string_aux(bv); + case Common_Types::t_float: + return to_string_aux(bv); + case Common_Types::t_long_double: + return to_string_aux(bv); + } + + throw chaiscript::detail::exception::bad_any_cast(); + } + + static void validate_boxed_number(const Boxed_Value &v) { + const Type_Info &inp_ = v.get_type_info(); + if (inp_ == user_type()) { throw chaiscript::detail::exception::bad_any_cast(); } - - template Target get_as() const - { - switch (get_common_type(bv)) { - case Common_Types::t_int32: - return get_as_aux(bv); - case Common_Types::t_uint8: - return get_as_aux(bv); - case Common_Types::t_int8: - return get_as_aux(bv); - case Common_Types::t_uint16: - return get_as_aux(bv); - case Common_Types::t_int16: - return get_as_aux(bv); - case Common_Types::t_uint32: - return get_as_aux(bv); - case Common_Types::t_uint64: - return get_as_aux(bv); - case Common_Types::t_int64: - return get_as_aux(bv); - case Common_Types::t_double: - return get_as_aux(bv); - case Common_Types::t_float: - return get_as_aux(bv); - case Common_Types::t_long_double: - return get_as_aux(bv); - } - + if (!inp_.is_arithmetic()) { throw chaiscript::detail::exception::bad_any_cast(); } + } - std::string to_string() const - { - switch (get_common_type(bv)) { - case Common_Types::t_int32: - return std::to_string(get_as()); - case Common_Types::t_uint8: - return std::to_string(get_as()); - case Common_Types::t_int8: - return std::to_string(get_as()); - case Common_Types::t_uint16: - return std::to_string(get_as()); - case Common_Types::t_int16: - return std::to_string(get_as()); - case Common_Types::t_uint32: - return std::to_string(get_as()); - case Common_Types::t_uint64: - return std::to_string(get_as()); - case Common_Types::t_int64: - return std::to_string(get_as()); - case Common_Types::t_double: - return to_string_aux(bv); - case Common_Types::t_float: - return to_string_aux(bv); - case Common_Types::t_long_double: - return to_string_aux(bv); - } + static bool equals(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs) { + return boxed_cast(oper(Operators::Opers::equals, t_lhs.bv, t_rhs.bv)); + } - throw chaiscript::detail::exception::bad_any_cast(); - } + static bool less_than(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs) { + return boxed_cast(oper(Operators::Opers::less_than, t_lhs.bv, t_rhs.bv)); + } - static void validate_boxed_number(const Boxed_Value &v) - { - const Type_Info &inp_ = v.get_type_info(); - if (inp_ == user_type()) - { - throw chaiscript::detail::exception::bad_any_cast(); - } + static bool greater_than(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs) { + return boxed_cast(oper(Operators::Opers::greater_than, t_lhs.bv, t_rhs.bv)); + } - if (!inp_.is_arithmetic()) - { - throw chaiscript::detail::exception::bad_any_cast(); - } - } + static bool greater_than_equal(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs) { + return boxed_cast(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) { + return boxed_cast(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) { + return boxed_cast(oper(Operators::Opers::not_equal, t_lhs.bv, t_rhs.bv)); + } - static bool equals(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs) - { - return boxed_cast(oper(Operators::Opers::equals, t_lhs.bv, t_rhs.bv)); - } + static Boxed_Number pre_decrement(Boxed_Number t_lhs) { return Boxed_Number(oper(Operators::Opers::pre_decrement, t_lhs.bv)); } - static bool less_than(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs) - { - return boxed_cast(oper(Operators::Opers::less_than, t_lhs.bv, t_rhs.bv)); - } + static Boxed_Number pre_increment(Boxed_Number t_lhs) { return Boxed_Number(oper(Operators::Opers::pre_increment, t_lhs.bv)); } - static bool greater_than(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs) - { - return boxed_cast(oper(Operators::Opers::greater_than, t_lhs.bv, t_rhs.bv)); - } + 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)); + } - static bool greater_than_equal(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs) - { - return boxed_cast(oper(Operators::Opers::greater_than_equal, t_lhs.bv, t_rhs.bv)); - } + static const Boxed_Number unary_plus(const Boxed_Number &t_lhs) { return Boxed_Number(oper(Operators::Opers::unary_plus, t_lhs.bv)); } - static bool less_than_equal(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs) - { - return boxed_cast(oper(Operators::Opers::less_than_equal, t_lhs.bv, t_rhs.bv)); - } + static const Boxed_Number unary_minus(const Boxed_Number &t_lhs) { return Boxed_Number(oper(Operators::Opers::unary_minus, t_lhs.bv)); } - static bool not_equal(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs) - { - return boxed_cast(oper(Operators::Opers::not_equal, t_lhs.bv, t_rhs.bv)); - } + 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)); + } - static Boxed_Number pre_decrement(Boxed_Number t_lhs) - { - return Boxed_Number(oper(Operators::Opers::pre_decrement, t_lhs.bv)); - } + 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)); + } - static Boxed_Number pre_increment(Boxed_Number t_lhs) - { - return Boxed_Number(oper(Operators::Opers::pre_increment, t_lhs.bv)); - } + 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)); + } - 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)); - } + 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)); + } - static const Boxed_Number unary_plus(const Boxed_Number &t_lhs) - { - return Boxed_Number(oper(Operators::Opers::unary_plus, t_lhs.bv)); - } + 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)); + } - static const Boxed_Number unary_minus(const Boxed_Number &t_lhs) - { - return Boxed_Number(oper(Operators::Opers::unary_minus, t_lhs.bv)); - } + 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)); + } - 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)); - } + 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)); + } - 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)); - } + 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)); + } - 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)); - } + 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)); + } - 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)); - } + 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))); + } - 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)); - } + 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)); + } - 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)); - } + 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)); + } - 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)); - } + 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)); + } - 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)); - } + 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)); + } - 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)); - } + 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)); + } + 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)); + } - 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))); - } + 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)); + } - 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)); - } + 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)); + } - 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)); - } + 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)); + } - 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)); - } + 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)); + } - 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)); - } + 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)); + } - 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)); - } - 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)); - } + 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); + } - 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)); - } + static Boxed_Value do_oper(Operators::Opers t_oper, const Boxed_Value &t_lhs) { return oper(t_oper, t_lhs); } - 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)); - } - - 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)); - } - - 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)); - } - - 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)); - } - - - - 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); - } - - static Boxed_Value do_oper(Operators::Opers t_oper, const Boxed_Value &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 template<> - struct Cast_Helper - { - static Boxed_Number cast(const Boxed_Value &ob, const Type_Conversions_State *) - { - return Boxed_Number(ob); - } - }; + struct Cast_Helper { + 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 template<> - struct Cast_Helper : Cast_Helper - { - }; + struct Cast_Helper : Cast_Helper { + }; /// Cast_Helper for converting from Boxed_Value to Boxed_Number template<> - struct Cast_Helper : Cast_Helper - { - }; - } + struct Cast_Helper : Cast_Helper { + }; + } // namespace detail #ifdef __GNUC__ #pragma GCC diagnostic pop @@ -804,9 +708,6 @@ namespace chaiscript #pragma warning(pop) #endif -} - - +} // namespace chaiscript #endif - diff --git a/include/chaiscript/dispatchkit/boxed_value.hpp b/include/chaiscript/dispatchkit/boxed_value.hpp index b979733d..06941b2f 100644 --- a/include/chaiscript/dispatchkit/boxed_value.hpp +++ b/include/chaiscript/dispatchkit/boxed_value.hpp @@ -7,7 +7,6 @@ // This is an open source non-commercial project. Dear PVS-Studio, please check it. // PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com - #ifndef CHAISCRIPT_BOXED_VALUE_HPP_ #define CHAISCRIPT_BOXED_VALUE_HPP_ @@ -19,357 +18,238 @@ #include "any.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 /// \sa chaiscript::boxed_cast - class Boxed_Value - { - public: - /// used for explicitly creating a "void" object - struct Void_Type - { - }; + class Boxed_Value { + public: + /// used for explicitly creating a "void" object + struct Void_Type { + }; - private: - /// 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 - struct Data - { - Data(const Type_Info &ti, - chaiscript::detail::Any to, - bool is_ref, - const void *t_void_ptr, - bool t_return_value) - : m_type_info(ti), m_obj(std::move(to)), m_data_ptr(ti.is_const()?nullptr:const_cast(t_void_ptr)), m_const_data_ptr(t_void_ptr), - m_is_ref(is_ref), m_return_value(t_return_value) - { - } - - Data &operator=(const Data &rhs) - { - m_type_info = rhs.m_type_info; - m_obj = rhs.m_obj; - m_is_ref = rhs.m_is_ref; - m_data_ptr = rhs.m_data_ptr; - m_const_data_ptr = rhs.m_const_data_ptr; - m_return_value = rhs.m_return_value; - - if (rhs.m_attrs) - { - m_attrs = std::make_unique>>(*rhs.m_attrs); - } - - return *this; - } - - Data(const Data &) = delete; - - Data(Data &&) = default; - Data &operator=(Data &&rhs) = default; - - - Type_Info m_type_info; - chaiscript::detail::Any m_obj; - void *m_data_ptr; - const void *m_const_data_ptr; - std::unique_ptr>> m_attrs; - bool m_is_ref; - bool m_return_value; - }; - - struct Object_Data - { - static auto get(Boxed_Value::Void_Type, bool t_return_value) - { - return std::make_shared( - detail::Get_Type_Info::get(), - chaiscript::detail::Any(), - false, - nullptr, - t_return_value) - ; - } - - template - static auto get(const std::shared_ptr *obj, bool t_return_value) - { - return get(*obj, t_return_value); - } - - template - static auto get(const std::shared_ptr &obj, bool t_return_value) - { - return std::make_shared( - detail::Get_Type_Info::get(), - chaiscript::detail::Any(obj), - false, - obj.get(), - t_return_value - ); - } - - template - static auto get(std::shared_ptr &&obj, bool t_return_value) - { - auto ptr = obj.get(); - return std::make_shared( - detail::Get_Type_Info::get(), - chaiscript::detail::Any(std::move(obj)), - false, - ptr, - t_return_value - ); - } - - - - template - static auto get(T *t, bool t_return_value) - { - return get(std::ref(*t), t_return_value); - } - - template - static auto get(const T *t, bool t_return_value) - { - return get(std::cref(*t), t_return_value); - } - - - template - static auto get(std::reference_wrapper obj, bool t_return_value) - { - auto p = &obj.get(); - return std::make_shared( - detail::Get_Type_Info::get(), - chaiscript::detail::Any(std::move(obj)), - true, - p, - t_return_value - ); - } - - template - static auto get(std::unique_ptr &&obj, bool t_return_value) - { - auto ptr = obj.get(); - return std::make_shared( - detail::Get_Type_Info::get(), - chaiscript::detail::Any(std::make_shared>(std::move(obj))), - true, - ptr, - t_return_value - ); - } - - template - static auto get(T t, bool t_return_value) - { - auto p = std::make_shared(std::move(t)); - auto ptr = p.get(); - return std::make_shared( - detail::Get_Type_Info::get(), - chaiscript::detail::Any(std::move(p)), - false, - ptr, - t_return_value - ); - } - - static std::shared_ptr get() - { - return std::make_shared( - Type_Info(), - chaiscript::detail::Any(), - false, - nullptr, - false - ); - } - - }; - - public: - /// Basic Boxed_Value constructor - template>>> - explicit Boxed_Value(T &&t, bool t_return_value = false) - : m_data(Object_Data::get(std::forward(t), t_return_value)) - { - } - - /// Unknown-type constructor - Boxed_Value() = default; - - Boxed_Value(Boxed_Value&&) = default; - Boxed_Value& operator=(Boxed_Value&&) = default; - Boxed_Value(const Boxed_Value&) = default; - Boxed_Value& operator=(const Boxed_Value&) = default; - - void swap(Boxed_Value &rhs) noexcept - { - std::swap(m_data, rhs.m_data); + private: + /// 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 + struct Data { + Data(const Type_Info &ti, chaiscript::detail::Any to, bool is_ref, const void *t_void_ptr, bool t_return_value) + : m_type_info(ti) + , m_obj(std::move(to)) + , m_data_ptr(ti.is_const() ? nullptr : const_cast(t_void_ptr)) + , m_const_data_ptr(t_void_ptr) + , m_is_ref(is_ref) + , m_return_value(t_return_value) { } - /// Copy the values stored in rhs.m_data to m_data. - /// m_data pointers are not shared in this case - Boxed_Value assign(const Boxed_Value &rhs) noexcept - { - (*m_data) = (*rhs.m_data); + Data &operator=(const Data &rhs) { + m_type_info = rhs.m_type_info; + m_obj = rhs.m_obj; + m_is_ref = rhs.m_is_ref; + m_data_ptr = rhs.m_data_ptr; + m_const_data_ptr = rhs.m_const_data_ptr; + m_return_value = rhs.m_return_value; + + if (rhs.m_attrs) { + m_attrs = std::make_unique>>(*rhs.m_attrs); + } + return *this; } - const Type_Info &get_type_info() const noexcept - { - return m_data->m_type_info; - } + Data(const Data &) = delete; - /// return true if the object is uninitialized - bool is_undef() const noexcept - { - return m_data->m_type_info.is_undef(); - } + Data(Data &&) = default; + Data &operator=(Data &&rhs) = default; - bool is_const() const noexcept - { - return m_data->m_type_info.is_const(); - } + Type_Info m_type_info; + chaiscript::detail::Any m_obj; + void *m_data_ptr; + const void *m_const_data_ptr; + std::unique_ptr>> m_attrs; + bool m_is_ref; + bool m_return_value; + }; - bool is_type(const Type_Info &ti) const noexcept - { - return m_data->m_type_info.bare_equal(ti); + struct Object_Data { + static auto get(Boxed_Value::Void_Type, bool t_return_value) { + return std::make_shared(detail::Get_Type_Info::get(), chaiscript::detail::Any(), false, nullptr, t_return_value); } - template - auto pointer_sentinel(std::shared_ptr &ptr) const noexcept - { - struct Sentinel { - Sentinel(std::shared_ptr &t_ptr, Data &data) - : m_ptr(t_ptr), m_data(data) - { - } - - ~Sentinel() - { - // save new pointer data - const auto ptr_ = m_ptr.get().get(); - m_data.get().m_data_ptr = ptr_; - m_data.get().m_const_data_ptr = ptr_; - } - - Sentinel& operator=(Sentinel&&s) = default; - Sentinel(Sentinel &&s) = default; - - operator std::shared_ptr&() const noexcept - { - return m_ptr.get(); - } - - Sentinel &operator=(const Sentinel &) = delete; - Sentinel(Sentinel&) = delete; - - std::reference_wrapper> m_ptr; - std::reference_wrapper m_data; - }; - - return Sentinel(ptr, *(m_data.get())); + static auto get(const std::shared_ptr *obj, bool t_return_value) { + return get(*obj, t_return_value); } - bool is_null() const noexcept - { - return (m_data->m_data_ptr == nullptr && m_data->m_const_data_ptr == nullptr); + template + static auto get(const std::shared_ptr &obj, bool t_return_value) { + return std::make_shared(detail::Get_Type_Info::get(), chaiscript::detail::Any(obj), false, obj.get(), t_return_value); } - const chaiscript::detail::Any & get() const noexcept - { - return m_data->m_obj; + template + static auto get(std::shared_ptr &&obj, bool t_return_value) { + auto ptr = obj.get(); + return std::make_shared(detail::Get_Type_Info::get(), chaiscript::detail::Any(std::move(obj)), false, ptr, t_return_value); } - bool is_ref() const noexcept - { - return m_data->m_is_ref; + template + static auto get(T *t, bool t_return_value) { + return get(std::ref(*t), t_return_value); } - bool is_return_value() const noexcept - { - return m_data->m_return_value; + template + static auto get(const T *t, bool t_return_value) { + return get(std::cref(*t), t_return_value); } - void reset_return_value() const noexcept - { - m_data->m_return_value = false; + template + static auto get(std::reference_wrapper obj, bool t_return_value) { + auto p = &obj.get(); + return std::make_shared(detail::Get_Type_Info::get(), chaiscript::detail::Any(std::move(obj)), true, p, t_return_value); } - bool is_pointer() const noexcept - { - return !is_ref(); + template + static auto get(std::unique_ptr &&obj, bool t_return_value) { + auto ptr = obj.get(); + return std::make_shared(detail::Get_Type_Info::get(), + chaiscript::detail::Any(std::make_shared>(std::move(obj))), + true, + ptr, + t_return_value); } - void *get_ptr() const noexcept - { - return m_data->m_data_ptr; + template + static auto get(T t, bool t_return_value) { + auto p = std::make_shared(std::move(t)); + auto ptr = p.get(); + return std::make_shared(detail::Get_Type_Info::get(), chaiscript::detail::Any(std::move(p)), false, ptr, t_return_value); } - const void *get_const_ptr() const noexcept - { - return m_data->m_const_data_ptr; - } + static std::shared_ptr get() { return std::make_shared(Type_Info(), chaiscript::detail::Any(), false, nullptr, false); } + }; - Boxed_Value get_attr(const std::string &t_name) - { - if (!m_data->m_attrs) - { - m_data->m_attrs = std::make_unique>>(); + public: + /// Basic Boxed_Value constructor + template>>> + explicit Boxed_Value(T &&t, bool t_return_value = false) + : m_data(Object_Data::get(std::forward(t), t_return_value)) { + } + + /// Unknown-type constructor + Boxed_Value() = default; + + Boxed_Value(Boxed_Value &&) = default; + Boxed_Value &operator=(Boxed_Value &&) = default; + Boxed_Value(const Boxed_Value &) = default; + Boxed_Value &operator=(const Boxed_Value &) = default; + + void swap(Boxed_Value &rhs) noexcept { std::swap(m_data, rhs.m_data); } + + /// Copy the values stored in rhs.m_data to m_data. + /// m_data pointers are not shared in this case + Boxed_Value assign(const Boxed_Value &rhs) noexcept { + (*m_data) = (*rhs.m_data); + return *this; + } + + const Type_Info &get_type_info() const noexcept { return m_data->m_type_info; } + + /// return true if the object is uninitialized + bool is_undef() const noexcept { return m_data->m_type_info.is_undef(); } + + bool is_const() const noexcept { 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); } + + template + auto pointer_sentinel(std::shared_ptr &ptr) const noexcept { + struct Sentinel { + Sentinel(std::shared_ptr &t_ptr, Data &data) + : m_ptr(t_ptr) + , m_data(data) { } - auto &attr = (*m_data->m_attrs)[t_name]; - if (attr) { - return Boxed_Value(attr, Internal_Construction()); - } else { - Boxed_Value bv; //default construct a new one - attr = bv.m_data; - return bv; + ~Sentinel() { + // save new pointer data + const auto ptr_ = m_ptr.get().get(); + m_data.get().m_data_ptr = ptr_; + m_data.get().m_const_data_ptr = ptr_; } + + Sentinel &operator=(Sentinel &&s) = default; + Sentinel(Sentinel &&s) = default; + + operator std::shared_ptr &() const noexcept { return m_ptr.get(); } + + Sentinel &operator=(const Sentinel &) = delete; + Sentinel(Sentinel &) = delete; + + std::reference_wrapper> m_ptr; + std::reference_wrapper m_data; + }; + + return Sentinel(ptr, *(m_data.get())); + } + + bool is_null() const noexcept { return (m_data->m_data_ptr == nullptr && m_data->m_const_data_ptr == nullptr); } + + const chaiscript::detail::Any &get() const noexcept { return m_data->m_obj; } + + bool is_ref() const noexcept { return m_data->m_is_ref; } + + bool is_return_value() const noexcept { return m_data->m_return_value; } + + void reset_return_value() const noexcept { m_data->m_return_value = false; } + + bool is_pointer() const noexcept { return !is_ref(); } + + void *get_ptr() const noexcept { return m_data->m_data_ptr; } + + const void *get_const_ptr() const noexcept { return m_data->m_const_data_ptr; } + + Boxed_Value get_attr(const std::string &t_name) { + if (!m_data->m_attrs) { + m_data->m_attrs = std::make_unique>>(); } - Boxed_Value ©_attrs(const Boxed_Value &t_obj) - { - if (t_obj.m_data->m_attrs) - { - m_data->m_attrs = std::make_unique>>(*t_obj.m_data->m_attrs); - } - return *this; + auto &attr = (*m_data->m_attrs)[t_name]; + if (attr) { + return Boxed_Value(attr, Internal_Construction()); + } else { + Boxed_Value bv; // default construct a new one + attr = bv.m_data; + return bv; } + } - Boxed_Value &clone_attrs(const Boxed_Value &t_obj) - { - copy_attrs(t_obj); - reset_return_value(); - return *this; + Boxed_Value ©_attrs(const Boxed_Value &t_obj) { + if (t_obj.m_data->m_attrs) { + m_data->m_attrs = std::make_unique>>(*t_obj.m_data->m_attrs); } + return *this; + } + Boxed_Value &clone_attrs(const Boxed_Value &t_obj) { + copy_attrs(t_obj); + reset_return_value(); + return *this; + } - /// \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 - { - return l.get_type_info() == r.get_type_info(); - } + /// \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 { return l.get_type_info() == r.get_type_info(); } - private: - // necessary to avoid hitting the templated && constructor of Boxed_Value - struct Internal_Construction{}; + private: + // necessary to avoid hitting the templated && constructor of Boxed_Value + struct Internal_Construction { + }; - Boxed_Value(std::shared_ptr t_data, Internal_Construction) + Boxed_Value(std::shared_ptr t_data, Internal_Construction) : m_data(std::move(t_data)) { - } + } - std::shared_ptr m_data = Object_Data::get(); + std::shared_ptr 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. /// @param t The value to box /// @@ -384,21 +264,19 @@ namespace chaiscript /// /// @sa @ref adding_objects template - Boxed_Value var(T &&t) - { - return Boxed_Value(std::forward(t)); - } + Boxed_Value var(T &&t) { + return Boxed_Value(std::forward(t)); + } namespace detail { /// \brief Takes a value, copies it and returns a Boxed_Value object that is immutable /// \param[in] t Value to copy and make const - /// \returns Immutable Boxed_Value + /// \returns Immutable Boxed_Value /// \sa Boxed_Value::is_const template - Boxed_Value const_var_impl(const T &t) - { - return Boxed_Value(std::make_shared::type >(t)); - } + Boxed_Value const_var_impl(const T &t) { + return Boxed_Value(std::make_shared::type>(t)); + } /// \brief Takes a pointer to a value, adds const to the pointed to type and returns an immutable Boxed_Value. /// Does not copy the pointed to value. @@ -406,10 +284,9 @@ namespace chaiscript /// \returns Immutable Boxed_Value /// \sa Boxed_Value::is_const template - Boxed_Value const_var_impl(T *t) - { - return Boxed_Value( const_cast::type *>(t) ); - } + Boxed_Value const_var_impl(T *t) { + return Boxed_Value(const_cast::type *>(t)); + } /// \brief Takes a std::shared_ptr to a value, adds const to the pointed to type and returns an immutable Boxed_Value. /// Does not copy the pointed to value. @@ -417,10 +294,9 @@ namespace chaiscript /// \returns Immutable Boxed_Value /// \sa Boxed_Value::is_const template - Boxed_Value const_var_impl(const std::shared_ptr &t) - { - return Boxed_Value( std::const_pointer_cast::type>(t) ); - } + Boxed_Value const_var_impl(const std::shared_ptr &t) { + return Boxed_Value(std::const_pointer_cast::type>(t)); + } /// \brief Takes a std::reference_wrapper value, adds const to the referenced type and returns an immutable Boxed_Value. /// Does not copy the referenced value. @@ -428,11 +304,10 @@ namespace chaiscript /// \returns Immutable Boxed_Value /// \sa Boxed_Value::is_const template - Boxed_Value const_var_impl(const std::reference_wrapper &t) - { - return Boxed_Value( std::cref(t.get()) ); - } - } + Boxed_Value const_var_impl(const std::reference_wrapper &t) { + 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 /// the value is not copied. If it is an object type, it is copied. @@ -454,14 +329,13 @@ namespace chaiscript /// chai.add(chaiscript::const_var(Red), "Red"); /// chai.add(chaiscript::const_var(Green), "Green"); /// \endcode - /// + /// /// \todo support C++11 strongly typed enums /// \sa \ref adding_objects template - Boxed_Value const_var(const T &t) - { - return detail::const_var_impl(t); - } + Boxed_Value const_var(const T &t) { + return detail::const_var_impl(t); + } inline Boxed_Value void_var() { static const auto v = Boxed_Value(Boxed_Value::Void_Type()); @@ -479,7 +353,6 @@ namespace chaiscript } } -} +} // namespace chaiscript #endif - diff --git a/include/chaiscript/dispatchkit/callable_traits.hpp b/include/chaiscript/dispatchkit/callable_traits.hpp index 442dabd6..3f8fa15c 100644 --- a/include/chaiscript/dispatchkit/callable_traits.hpp +++ b/include/chaiscript/dispatchkit/callable_traits.hpp @@ -12,49 +12,50 @@ namespace chaiscript { namespace dispatch { namespace detail { - - template - struct Constructor - { - template - std::shared_ptr operator()(Inner&& ... inner) const { + template + struct Constructor { + template + std::shared_ptr operator()(Inner &&...inner) const { return std::make_shared(std::forward(inner)...); } }; - template - struct Const_Caller - { - explicit Const_Caller(Ret (Class::*t_func)(Param...) const) : m_func(t_func) {} + template + struct Const_Caller { + explicit Const_Caller(Ret (Class::*t_func)(Param...) const) + : m_func(t_func) { + } - template - Ret operator()(const Class &o, Inner&& ... inner) const { + template + Ret operator()(const Class &o, Inner &&...inner) const { return (o.*m_func)(std::forward(inner)...); } Ret (Class::*m_func)(Param...) const; }; - template - struct Fun_Caller - { - explicit Fun_Caller(Ret( * t_func)(Param...) ) : m_func(t_func) {} + template + struct Fun_Caller { + explicit Fun_Caller(Ret (*t_func)(Param...)) + : m_func(t_func) { + } - template - Ret operator()(Inner&& ... inner) const { + template + Ret operator()(Inner &&...inner) const { return (m_func)(std::forward(inner)...); } - Ret(*m_func)(Param...); + Ret (*m_func)(Param...); }; - template - struct Caller - { - explicit Caller(Ret (Class::*t_func)(Param...)) : m_func(t_func) {} + template + struct Caller { + explicit Caller(Ret (Class::*t_func)(Param...)) + : m_func(t_func) { + } - template - Ret operator()(Class &o, Inner&& ... inner) const { + template + Ret operator()(Class &o, Inner &&...inner) const { return (o.*m_func)(std::forward(inner)...); } @@ -62,46 +63,37 @@ namespace chaiscript { }; template - struct Arity - { - }; - - template - struct Arity - { - static const size_t arity = sizeof...(Params); - }; + struct Arity { + }; + template + struct Arity { + static const size_t arity = sizeof...(Params); + }; template - struct Function_Signature - { - }; + struct Function_Signature { + }; - template - struct Function_Signature - { - using Return_Type = Ret; - using Signature = Ret ()(Params...); - }; - - template - struct Function_Signature - { - using Return_Type = Ret; - using Signature = Ret ()(Params...); - }; + template + struct Function_Signature { + using Return_Type = Ret; + using Signature = Ret()(Params...); + }; + template + struct Function_Signature { + using Return_Type = Ret; + using Signature = Ret()(Params...); + }; template - struct Callable_Traits - { - using Signature = typename Function_Signature::Signature; - using Return_Type = typename Function_Signature::Return_Type; - }; - } - } -} + struct Callable_Traits { + using Signature = typename Function_Signature::Signature; + using Return_Type = typename Function_Signature::Return_Type; + }; + } // namespace detail + } // namespace dispatch +} // namespace chaiscript #endif - diff --git a/include/chaiscript/dispatchkit/dispatchkit.hpp b/include/chaiscript/dispatchkit/dispatchkit.hpp index 701a240a..06e8992a 100644 --- a/include/chaiscript/dispatchkit/dispatchkit.hpp +++ b/include/chaiscript/dispatchkit/dispatchkit.hpp @@ -7,7 +7,6 @@ // This is an open source non-commercial project. Dear PVS-Studio, please check it. // PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com - #ifndef CHAISCRIPT_DISPATCHKIT_HPP_ #define CHAISCRIPT_DISPATCHKIT_HPP_ @@ -26,368 +25,303 @@ #include "../chaiscript_defines.hpp" #include "../chaiscript_threading.hpp" +#include "../utility/quick_flat_map.hpp" #include "bad_boxed_cast.hpp" #include "boxed_cast.hpp" #include "boxed_cast_helper.hpp" #include "boxed_value.hpp" -#include "type_conversions.hpp" #include "dynamic_object.hpp" #include "proxy_constructors.hpp" #include "proxy_functions.hpp" -#include "type_info.hpp" #include "short_alloc.hpp" -#include "../utility/quick_flat_map.hpp" +#include "type_conversions.hpp" +#include "type_info.hpp" namespace chaiscript { -class Boxed_Number; -} // namespace chaiscript + class Boxed_Number; +} // namespace chaiscript namespace chaiscript { namespace parser { class ChaiScript_Parser_Base; } -namespace dispatch { -class Dynamic_Proxy_Function; -class Proxy_Function_Base; -struct Placeholder_Object; -} // namespace dispatch -} // namespace chaiscript - - + namespace dispatch { + class Dynamic_Proxy_Function; + class Proxy_Function_Base; + struct Placeholder_Object; + } // namespace dispatch +} // namespace chaiscript /// \namespace chaiscript::dispatch /// \brief Classes and functions specific to the runtime dispatch side of ChaiScript. Some items may be of use to the end user. -namespace chaiscript -{ - namespace exception - { +namespace chaiscript { + namespace exception { /// Exception thrown in the case that an object name is invalid because it is a reserved word - class reserved_word_error : public std::runtime_error - { - public: - explicit reserved_word_error(const std::string &t_word) noexcept - : std::runtime_error("Reserved word not allowed in object name: " + t_word), m_word(t_word) - { - } + class reserved_word_error : public std::runtime_error { + public: + explicit reserved_word_error(const std::string &t_word) noexcept + : std::runtime_error("Reserved word not allowed in object name: " + t_word) + , m_word(t_word) { + } - reserved_word_error(const reserved_word_error &) = default; + reserved_word_error(const reserved_word_error &) = default; - ~reserved_word_error() noexcept override = default; + ~reserved_word_error() noexcept override = default; - std::string word() const - { - return m_word; - } + std::string word() const { return m_word; } - private: - std::string m_word; + private: + std::string m_word; }; /// Exception thrown in the case that an object name is invalid because it contains illegal characters - class illegal_name_error : public std::runtime_error - { - public: - explicit illegal_name_error(const std::string &t_name) noexcept - : std::runtime_error("Reserved name not allowed in object name: " + t_name), m_name(t_name) - { - } + class illegal_name_error : public std::runtime_error { + public: + explicit illegal_name_error(const std::string &t_name) noexcept + : std::runtime_error("Reserved name not allowed in object name: " + t_name) + , m_name(t_name) { + } - illegal_name_error(const illegal_name_error &) = default; + illegal_name_error(const illegal_name_error &) = default; - ~illegal_name_error() noexcept override = default; + ~illegal_name_error() noexcept override = default; - std::string name() const - { - return m_name; - } + std::string name() const { return m_name; } - private: - std::string m_name; + private: + std::string m_name; }; - /// Exception thrown in the case that an object name is invalid because it already exists in current context - class name_conflict_error : public std::runtime_error - { - public: - explicit name_conflict_error(const std::string &t_name) noexcept - : std::runtime_error("Name already exists in current context " + t_name), m_name(t_name) - { - } + class name_conflict_error : public std::runtime_error { + public: + explicit name_conflict_error(const std::string &t_name) noexcept + : std::runtime_error("Name already exists in current context " + t_name) + , m_name(t_name) { + } - name_conflict_error(const name_conflict_error &) = default; + name_conflict_error(const name_conflict_error &) = default; - ~name_conflict_error() noexcept override = default; + ~name_conflict_error() noexcept override = default; - std::string name() const - { - return m_name; - } - - private: - std::string m_name; + std::string name() const { return m_name; } + private: + std::string m_name; }; - /// Exception thrown in the case that a non-const object was added as a shared object - class global_non_const : public std::runtime_error - { - public: - global_non_const() noexcept - : std::runtime_error("a global object must be const") - { - } + class global_non_const : public std::runtime_error { + public: + global_non_const() noexcept + : std::runtime_error("a global object must be const") { + } - global_non_const(const global_non_const &) = default; - ~global_non_const() noexcept override = default; + global_non_const(const global_non_const &) = default; + ~global_non_const() noexcept override = default; }; - } - + } // namespace exception /// \brief Holds a collection of ChaiScript settings which can be applied to the ChaiScript runtime. /// Used to implement loadable module support. - class Module - { - public: - Module &add(Type_Info ti, std::string name) - { - m_typeinfos.emplace_back(ti, std::move(name)); - return *this; + class Module { + public: + Module &add(Type_Info ti, std::string name) { + m_typeinfos.emplace_back(ti, std::move(name)); + return *this; + } + + Module &add(Type_Conversion d) { + m_conversions.push_back(std::move(d)); + return *this; + } + + Module &add(Proxy_Function f, std::string name) { + m_funcs.emplace_back(std::move(f), std::move(name)); + return *this; + } + + Module &add_global_const(Boxed_Value t_bv, std::string t_name) { + if (!t_bv.is_const()) { + throw chaiscript::exception::global_non_const(); } - Module &add(Type_Conversion d) - { - m_conversions.push_back(std::move(d)); - return *this; + m_globals.emplace_back(std::move(t_bv), std::move(t_name)); + return *this; + } + + // Add a bit of ChaiScript to eval during module implementation + Module &eval(std::string str) { + m_evals.push_back(std::move(str)); + return *this; + } + + template + void apply(Eval &t_eval, Engine &t_engine) const { + apply(m_typeinfos.begin(), m_typeinfos.end(), t_engine); + apply(m_funcs.begin(), m_funcs.end(), t_engine); + apply_eval(m_evals.begin(), m_evals.end(), t_eval); + apply_single(m_conversions.begin(), m_conversions.end(), t_engine); + apply_globals(m_globals.begin(), m_globals.end(), t_engine); + } + + bool has_function(const Proxy_Function &new_f, std::string_view name) noexcept { + return std::any_of(m_funcs.begin(), m_funcs.end(), [&](const std::pair &existing_f) { + return existing_f.second == name && *(existing_f.first) == *(new_f); + }); + } + + private: + std::vector> m_typeinfos; + std::vector> m_funcs; + std::vector> m_globals; + std::vector m_evals; + std::vector m_conversions; + + template + static void apply(InItr begin, const InItr end, T &t) { + for_each(begin, end, [&t](const auto &obj) { + try { + t.add(obj.first, obj.second); + } catch (const chaiscript::exception::name_conflict_error &) { + /// \todo Should we throw an error if there's a name conflict + /// while applying a module? + } + }); + } + + template + static void apply_globals(InItr begin, InItr end, T &t) { + while (begin != end) { + t.add_global_const(begin->first, begin->second); + ++begin; } + } - Module &add(Proxy_Function f, std::string name) - { - m_funcs.emplace_back(std::move(f), std::move(name)); - return *this; + template + static void apply_single(InItr begin, InItr end, T &t) { + while (begin != end) { + t.add(*begin); + ++begin; } + } - Module &add_global_const(Boxed_Value t_bv, std::string t_name) - { - if (!t_bv.is_const()) - { - throw chaiscript::exception::global_non_const(); - } - - m_globals.emplace_back(std::move(t_bv), std::move(t_name)); - return *this; + template + static void apply_eval(InItr begin, InItr end, T &t) { + while (begin != end) { + t.eval(*begin); + ++begin; } - - - //Add a bit of ChaiScript to eval during module implementation - Module &eval(std::string str) - { - m_evals.push_back(std::move(str)); - return *this; - } - - template - void apply(Eval &t_eval, Engine &t_engine) const - { - apply(m_typeinfos.begin(), m_typeinfos.end(), t_engine); - apply(m_funcs.begin(), m_funcs.end(), t_engine); - apply_eval(m_evals.begin(), m_evals.end(), t_eval); - apply_single(m_conversions.begin(), m_conversions.end(), t_engine); - apply_globals(m_globals.begin(), m_globals.end(), t_engine); - } - - bool has_function(const Proxy_Function &new_f, std::string_view name) noexcept - { - return std::any_of(m_funcs.begin(), m_funcs.end(), - [&](const std::pair &existing_f) { - return existing_f.second == name && *(existing_f.first) == *(new_f); - } - ); - } - - - private: - std::vector> m_typeinfos; - std::vector> m_funcs; - std::vector> m_globals; - std::vector m_evals; - std::vector m_conversions; - - template - static void apply(InItr begin, const InItr end, T &t) - { - for_each(begin, end, - [&t](const auto &obj) { - try { - t.add(obj.first, obj.second); - } catch (const chaiscript::exception::name_conflict_error &) { - /// \todo Should we throw an error if there's a name conflict - /// while applying a module? - } - } - ); - } - - template - static void apply_globals(InItr begin, InItr end, T &t) - { - while (begin != end) - { - t.add_global_const(begin->first, begin->second); - ++begin; - } - } - - template - static void apply_single(InItr begin, InItr end, T &t) - { - while (begin != end) - { - t.add(*begin); - ++begin; - } - } - - template - static void apply_eval(InItr begin, InItr end, T &t) - { - while (begin != end) - { - t.eval(*begin); - ++begin; - } - } + } }; /// Convenience typedef for Module objects to be added to the ChaiScript runtime using ModulePtr = std::shared_ptr; - namespace detail - { + namespace detail { /// A Proxy_Function implementation that is able to take /// a vector of Proxy_Functions and perform a dispatch on them. It is /// used specifically in the case of dealing with Function object variables - class Dispatch_Function final : public dispatch::Proxy_Function_Base - { - public: - explicit Dispatch_Function(std::vector t_funcs) - : Proxy_Function_Base(build_type_infos(t_funcs), calculate_arity(t_funcs)), - m_funcs(std::move(t_funcs)) - { + class Dispatch_Function final : public dispatch::Proxy_Function_Base { + public: + explicit Dispatch_Function(std::vector t_funcs) + : Proxy_Function_Base(build_type_infos(t_funcs), calculate_arity(t_funcs)) + , m_funcs(std::move(t_funcs)) { + } + + bool operator==(const dispatch::Proxy_Function_Base &rhs) const noexcept override { + try { + const auto &dispatch_fun = dynamic_cast(rhs); + return m_funcs == dispatch_fun.m_funcs; + } catch (const std::bad_cast &) { + return false; + } + } + + std::vector get_contained_functions() const override { + return std::vector(m_funcs.begin(), m_funcs.end()); + } + + static int calculate_arity(const std::vector &t_funcs) noexcept { + if (t_funcs.empty()) { + return -1; } - bool operator==(const dispatch::Proxy_Function_Base &rhs) const noexcept override - { - try { - const auto &dispatch_fun = dynamic_cast(rhs); - return m_funcs == dispatch_fun.m_funcs; - } catch (const std::bad_cast &) { - return false; - } - } + const auto arity = t_funcs.front()->get_arity(); - std::vector get_contained_functions() const override - { - return std::vector(m_funcs.begin(), m_funcs.end()); - } - - - static int calculate_arity(const std::vector &t_funcs) noexcept - { - if (t_funcs.empty()) { + for (const auto &func : t_funcs) { + if (arity != func->get_arity()) { + // The arities in the list do not match, so it's unspecified return -1; } + } - const auto arity = t_funcs.front()->get_arity(); + return arity; + } - for (const auto &func : t_funcs) - { - if (arity != func->get_arity()) - { - // The arities in the list do not match, so it's unspecified - return -1; + bool call_match(const Function_Params &vals, const Type_Conversions_State &t_conversions) const noexcept override { + return std::any_of(std::begin(m_funcs), std::end(m_funcs), [&vals, &t_conversions](const Proxy_Function &f) { + return f->call_match(vals, t_conversions); + }); + } + + protected: + Boxed_Value do_call(const Function_Params ¶ms, const Type_Conversions_State &t_conversions) const override { + return dispatch::dispatch(m_funcs, params, t_conversions); + } + + private: + std::vector m_funcs; + + static std::vector build_type_infos(const std::vector &t_funcs) { + auto begin = t_funcs.cbegin(); + const auto &end = t_funcs.cend(); + + if (begin != end) { + std::vector type_infos = (*begin)->get_param_types(); + + ++begin; + + bool size_mismatch = false; + + while (begin != end) { + std::vector param_types = (*begin)->get_param_types(); + + if (param_types.size() != type_infos.size()) { + size_mismatch = true; } - } - return arity; - } - - bool call_match(const Function_Params &vals, const Type_Conversions_State &t_conversions) const noexcept override - { - return std::any_of(std::begin(m_funcs), std::end(m_funcs), - [&vals, &t_conversions](const Proxy_Function &f){ return f->call_match(vals, t_conversions); }); - } - - protected: - Boxed_Value do_call(const Function_Params ¶ms, const Type_Conversions_State &t_conversions) const override - { - return dispatch::dispatch(m_funcs, params, t_conversions); - } - - private: - std::vector m_funcs; - - static std::vector build_type_infos(const std::vector &t_funcs) - { - auto begin = t_funcs.cbegin(); - const auto &end = t_funcs.cend(); - - if (begin != end) - { - std::vector type_infos = (*begin)->get_param_types(); + for (size_t i = 0; i < type_infos.size() && i < param_types.size(); ++i) { + if (!(type_infos[i] == param_types[i])) { + type_infos[i] = detail::Get_Type_Info::get(); + } + } ++begin; - - bool size_mismatch = false; - - while (begin != end) - { - std::vector param_types = (*begin)->get_param_types(); - - if (param_types.size() != type_infos.size()) - { - size_mismatch = true; - } - - for (size_t i = 0; i < type_infos.size() && i < param_types.size(); ++i) - { - if (!(type_infos[i] == param_types[i])) - { - type_infos[i] = detail::Get_Type_Info::get(); - } - } - - ++begin; - } - - assert(!type_infos.empty() && " type_info vector size is < 0, this is only possible if something else is broken"); - - if (size_mismatch) - { - type_infos.resize(1); - } - - return type_infos; } - return std::vector(); + assert(!type_infos.empty() && " type_info vector size is < 0, this is only possible if something else is broken"); + + if (size_mismatch) { + type_infos.resize(1); + } + + return type_infos; } + + return std::vector(); + } }; - } + } // namespace detail - - namespace detail - { - struct Stack_Holder - { - //template + namespace detail { + struct Stack_Holder { + // template // using SmallVector = std::vector>; - template - using SmallVector = std::vector; - + template + using SmallVector = std::vector; using Scope = utility::QuickFlatMap; using StackData = SmallVector; @@ -395,27 +329,19 @@ namespace chaiscript using Call_Param_List = SmallVector; using Call_Params = SmallVector; - Stack_Holder() - { + Stack_Holder() { push_stack(); push_call_params(); } - void push_stack_data() - { + void push_stack_data() { stacks.back().emplace_back(); -// stacks.back().emplace_back(Scope(scope_allocator)); + // stacks.back().emplace_back(Scope(scope_allocator)); } - void push_stack() - { - stacks.emplace_back(1); - } + void push_stack() { stacks.emplace_back(1); } - void push_call_params() - { - call_params.emplace_back(); - } + void push_call_params() { call_params.emplace_back(); } Stacks stacks; Call_Params call_params; @@ -425,488 +351,404 @@ namespace chaiscript /// Main class for the dispatchkit. Handles management /// of the object stack, functions and registered types. - class Dispatch_Engine - { + class Dispatch_Engine { + public: + using Type_Name_Map = std::map; + using Scope = utility::QuickFlatMap; + using StackData = Stack_Holder::StackData; - public: - using Type_Name_Map = std::map; - using Scope = utility::QuickFlatMap; - using StackData = Stack_Holder::StackData; + struct State { + utility::QuickFlatMap>, str_equal> m_functions; + utility::QuickFlatMap m_function_objects; + utility::QuickFlatMap m_boxed_functions; + std::map m_global_objects; + Type_Name_Map m_types; + }; - struct State - { - utility::QuickFlatMap>, str_equal> m_functions; - utility::QuickFlatMap m_function_objects; - utility::QuickFlatMap m_boxed_functions; - std::map m_global_objects; - Type_Name_Map m_types; + explicit Dispatch_Engine(chaiscript::parser::ChaiScript_Parser_Base &parser) + : m_stack_holder() + , m_parser(parser) { + } + + /// \brief casts an object while applying any Dynamic_Conversion available + template + decltype(auto) boxed_cast(const Boxed_Value &bv) const { + Type_Conversions_State state(m_conversions, m_conversions.conversion_saves()); + return (chaiscript::boxed_cast(bv, &state)); + } + + /// Add a new conversion for upcasting to a base class + void add(const Type_Conversion &d) { m_conversions.add_conversion(d); } + + /// Add a new named Proxy_Function to the system + void add(const Proxy_Function &f, const std::string &name) { add_function(f, name); } + + /// Set the value of an object, by name. If the object + /// is not available in the current scope it is created + void add(Boxed_Value obj, const std::string &name) { + auto &stack = get_stack_data(); + + for (auto stack_elem = stack.rbegin(); stack_elem != stack.rend(); ++stack_elem) { + if (auto itr = stack_elem->find(name); itr != stack_elem->end()) { + itr->second = std::move(obj); + return; + } + } + + add_object(name, std::move(obj)); + } + + /// Adds a named object to the current scope + /// \warning This version does not check the validity of the name + /// it is meant for internal use only + Boxed_Value &add_get_object(std::string t_name, Boxed_Value obj, Stack_Holder &t_holder) { + auto &stack_elem = get_stack_data(t_holder).back(); + + if (auto result = stack_elem.insert(std::pair{std::move(t_name), std::move(obj)}); result.second) { + return result.first->second; + } else { + // insert failed + throw chaiscript::exception::name_conflict_error(result.first->first); + } + } + + /// Adds a named object to the current scope + /// \warning This version does not check the validity of the name + /// it is meant for internal use only + void add_object(std::string t_name, Boxed_Value obj, Stack_Holder &t_holder) { + auto &stack_elem = get_stack_data(t_holder).back(); + + if (auto result = stack_elem.insert(std::pair{std::move(t_name), std::move(obj)}); !result.second) { + // insert failed + throw chaiscript::exception::name_conflict_error(result.first->first); + } + } + + /// Adds a named object to the current scope + /// \warning This version does not check the validity of the name + /// it is meant for internal use only + void add_object(const std::string &name, Boxed_Value obj) { add_object(name, std::move(obj), get_stack_holder()); } + + /// Adds a new global shared object, between all the threads + void add_global_const(const Boxed_Value &obj, const std::string &name) { + if (!obj.is_const()) { + throw chaiscript::exception::global_non_const(); + } + + chaiscript::detail::threading::unique_lock l(m_mutex); + + if (m_state.m_global_objects.find(name) != m_state.m_global_objects.end()) { + throw chaiscript::exception::name_conflict_error(name); + } else { + m_state.m_global_objects.insert(std::make_pair(name, obj)); + } + } + + /// Adds a new global (non-const) shared object, between all the threads + Boxed_Value add_global_no_throw(Boxed_Value obj, std::string name) { + chaiscript::detail::threading::unique_lock l(m_mutex); + + return m_state.m_global_objects.insert(std::pair{std::move(name), std::move(obj)}).first->second; + } + + /// Adds a new global (non-const) shared object, between all the threads + void add_global(Boxed_Value obj, std::string name) { + chaiscript::detail::threading::unique_lock l(m_mutex); + + if (auto result = m_state.m_global_objects.insert(std::pair{std::move(name), std::move(obj)}); !result.second) { + // insert failed + throw chaiscript::exception::name_conflict_error(result.first->first); + } + } + + /// Updates an existing global shared object or adds a new global shared object if not found + void set_global(Boxed_Value obj, std::string name) { + chaiscript::detail::threading::unique_lock l(m_mutex); + m_state.m_global_objects.insert_or_assign(std::move(name), std::move(obj)); + } + + /// Adds a new scope to the stack + void new_scope() { new_scope(*m_stack_holder); } + + /// Pops the current scope from the stack + void pop_scope() { pop_scope(*m_stack_holder); } + + /// Adds a new scope to the stack + static void new_scope(Stack_Holder &t_holder) { + t_holder.push_stack_data(); + t_holder.push_call_params(); + } + + /// Pops the current scope from the stack + static void pop_scope(Stack_Holder &t_holder) { + t_holder.call_params.pop_back(); + StackData &stack = get_stack_data(t_holder); + + assert(!stack.empty()); + + stack.pop_back(); + } + + /// Pushes a new stack on to the list of stacks + static void new_stack(Stack_Holder &t_holder) { + // add a new Stack with 1 element + t_holder.push_stack(); + } + + static void pop_stack(Stack_Holder &t_holder) { t_holder.stacks.pop_back(); } + + /// Searches the current stack for an object of the given name + /// includes a special overload for the _ place holder object to + /// ensure that it is always in scope. + Boxed_Value get_object(std::string_view name, std::atomic_uint_fast32_t &t_loc, Stack_Holder &t_holder) const { + enum class Loc : uint_fast32_t { + located = 0x80000000, + is_local = 0x40000000, + stack_mask = 0x0FFF0000, + loc_mask = 0x0000FFFF }; - explicit Dispatch_Engine(chaiscript::parser::ChaiScript_Parser_Base &parser) - : m_stack_holder(), - m_parser(parser) - { - } + uint_fast32_t loc = t_loc; - /// \brief casts an object while applying any Dynamic_Conversion available - template - decltype(auto) boxed_cast(const Boxed_Value &bv) const - { - Type_Conversions_State state(m_conversions, m_conversions.conversion_saves()); - return(chaiscript::boxed_cast(bv, &state)); - } + if (loc == 0) { + auto &stack = get_stack_data(t_holder); - /// Add a new conversion for upcasting to a base class - void add(const Type_Conversion &d) - { - m_conversions.add_conversion(d); - } - - /// Add a new named Proxy_Function to the system - void add(const Proxy_Function &f, const std::string &name) - { - add_function(f, name); - } - - /// Set the value of an object, by name. If the object - /// is not available in the current scope it is created - void add(Boxed_Value obj, const std::string &name) - { - auto &stack = get_stack_data(); - - for (auto stack_elem = stack.rbegin(); stack_elem != stack.rend(); ++stack_elem) - { - if (auto itr = stack_elem->find(name); itr != stack_elem->end()) - { - itr->second = std::move(obj); - return; - } - } - - add_object(name, std::move(obj)); - } - - /// Adds a named object to the current scope - /// \warning This version does not check the validity of the name - /// it is meant for internal use only - Boxed_Value &add_get_object(std::string t_name, Boxed_Value obj, Stack_Holder &t_holder) - { - auto &stack_elem = get_stack_data(t_holder).back(); - - if (auto result = stack_elem.insert(std::pair{std::move(t_name), std::move(obj)}); result.second) - { - return result.first->second; - } else { - //insert failed - throw chaiscript::exception::name_conflict_error(result.first->first); - } - } - - - /// Adds a named object to the current scope - /// \warning This version does not check the validity of the name - /// it is meant for internal use only - void add_object(std::string t_name, Boxed_Value obj, Stack_Holder &t_holder) - { - auto &stack_elem = get_stack_data(t_holder).back(); - - if (auto result = stack_elem.insert(std::pair{std::move(t_name), std::move(obj)}); !result.second) - { - //insert failed - throw chaiscript::exception::name_conflict_error(result.first->first); - } - } - - - /// Adds a named object to the current scope - /// \warning This version does not check the validity of the name - /// it is meant for internal use only - void add_object(const std::string &name, Boxed_Value obj) - { - add_object(name, std::move(obj), get_stack_holder()); - } - - /// Adds a new global shared object, between all the threads - void add_global_const(const Boxed_Value &obj, const std::string &name) - { - if (!obj.is_const()) - { - throw chaiscript::exception::global_non_const(); - } - - chaiscript::detail::threading::unique_lock l(m_mutex); - - if (m_state.m_global_objects.find(name) != m_state.m_global_objects.end()) - { - throw chaiscript::exception::name_conflict_error(name); - } else { - m_state.m_global_objects.insert(std::make_pair(name, obj)); - } - } - - /// Adds a new global (non-const) shared object, between all the threads - Boxed_Value add_global_no_throw(Boxed_Value obj, std::string name) - { - chaiscript::detail::threading::unique_lock l(m_mutex); - - return m_state.m_global_objects.insert(std::pair{std::move(name), std::move(obj)}).first->second; - } - - - /// Adds a new global (non-const) shared object, between all the threads - void add_global(Boxed_Value obj, std::string name) - { - chaiscript::detail::threading::unique_lock l(m_mutex); - - if (auto result = m_state.m_global_objects.insert(std::pair{std::move(name), std::move(obj)}); !result.second) { - // insert failed - throw chaiscript::exception::name_conflict_error(result.first->first); - } - } - - /// Updates an existing global shared object or adds a new global shared object if not found - void set_global(Boxed_Value obj, std::string name) - { - chaiscript::detail::threading::unique_lock l(m_mutex); - m_state.m_global_objects.insert_or_assign(std::move(name), std::move(obj)); - } - - /// Adds a new scope to the stack - void new_scope() - { - new_scope(*m_stack_holder); - } - - /// Pops the current scope from the stack - void pop_scope() - { - pop_scope(*m_stack_holder); - } - - /// Adds a new scope to the stack - static void new_scope(Stack_Holder &t_holder) - { - t_holder.push_stack_data(); - t_holder.push_call_params(); - } - - /// Pops the current scope from the stack - static void pop_scope(Stack_Holder &t_holder) - { - t_holder.call_params.pop_back(); - StackData &stack = get_stack_data(t_holder); - - assert(!stack.empty()); - - stack.pop_back(); - } - - - /// Pushes a new stack on to the list of stacks - static void new_stack(Stack_Holder &t_holder) - { - // add a new Stack with 1 element - t_holder.push_stack(); - } - - static void pop_stack(Stack_Holder &t_holder) - { - t_holder.stacks.pop_back(); - } - - /// Searches the current stack for an object of the given name - /// includes a special overload for the _ place holder object to - /// ensure that it is always in scope. - Boxed_Value get_object(std::string_view name, std::atomic_uint_fast32_t &t_loc, Stack_Holder &t_holder) const - { - enum class Loc : uint_fast32_t { - located = 0x80000000, - is_local = 0x40000000, - stack_mask = 0x0FFF0000, - loc_mask = 0x0000FFFF - }; - - uint_fast32_t loc = t_loc; - - if (loc == 0) - { - auto &stack = get_stack_data(t_holder); - - // Is it in the stack? - for (auto stack_elem = stack.rbegin(); stack_elem != stack.rend(); ++stack_elem) - { - for (auto s = stack_elem->begin(); s != stack_elem->end(); ++s ) - { - if (s->first == name) { - t_loc = static_cast(std::distance(stack.rbegin(), stack_elem) << 16) - | static_cast(std::distance(stack_elem->begin(), s)) - | static_cast(Loc::located) - | static_cast(Loc::is_local); - return s->second; - } + // Is it in the stack? + for (auto stack_elem = stack.rbegin(); stack_elem != stack.rend(); ++stack_elem) { + for (auto s = stack_elem->begin(); s != stack_elem->end(); ++s) { + if (s->first == name) { + t_loc = static_cast(std::distance(stack.rbegin(), stack_elem) << 16) + | static_cast(std::distance(stack_elem->begin(), s)) | static_cast(Loc::located) + | static_cast(Loc::is_local); + return s->second; } } - - t_loc = static_cast(Loc::located); - } else if ((loc & static_cast(Loc::is_local)) != 0u) { - auto &stack = get_stack_data(t_holder); - - return stack[stack.size() - 1 - ((loc & static_cast(Loc::stack_mask)) >> 16)].at_index(loc & static_cast(Loc::loc_mask)); } - // Is the value we are looking for a global or function? - chaiscript::detail::threading::shared_lock l(m_mutex); - - const auto itr = m_state.m_global_objects.find(name); - if (itr != m_state.m_global_objects.end()) - { - return itr->second; - } - - // no? is it a function object? - auto obj = get_function_object_int(name, loc); - if (obj.first != loc) { t_loc = uint_fast32_t(obj.first); } - - return obj.second; + t_loc = static_cast(Loc::located); + } else if ((loc & static_cast(Loc::is_local)) != 0u) { + auto &stack = get_stack_data(t_holder); + return stack[stack.size() - 1 - ((loc & static_cast(Loc::stack_mask)) >> 16)].at_index( + loc & static_cast(Loc::loc_mask)); } - /// Registers a new named type - void add(const Type_Info &ti, const std::string &name) - { - add_global_const(const_var(ti), name + "_type"); + // Is the value we are looking for a global or function? + chaiscript::detail::threading::shared_lock l(m_mutex); - chaiscript::detail::threading::unique_lock l(m_mutex); - - m_state.m_types.insert(std::make_pair(name, ti)); + const auto itr = m_state.m_global_objects.find(name); + if (itr != m_state.m_global_objects.end()) { + return itr->second; } - /// Returns the type info for a named type - Type_Info get_type(std::string_view name, bool t_throw = true) const - { - chaiscript::detail::threading::shared_lock l(m_mutex); + // no? is it a function object? + auto obj = get_function_object_int(name, loc); + if (obj.first != loc) { + t_loc = uint_fast32_t(obj.first); + } - const auto itr = m_state.m_types.find(name); + return obj.second; + } - if (itr != m_state.m_types.end()) - { - return itr->second; - } + /// Registers a new named type + void add(const Type_Info &ti, const std::string &name) { + add_global_const(const_var(ti), name + "_type"); - if (t_throw) { - throw std::range_error("Type Not Known: " + std::string(name)); - } else { - return Type_Info(); + chaiscript::detail::threading::unique_lock l(m_mutex); + + m_state.m_types.insert(std::make_pair(name, ti)); + } + + /// Returns the type info for a named type + Type_Info get_type(std::string_view name, bool t_throw = true) const { + chaiscript::detail::threading::shared_lock l(m_mutex); + + const auto itr = m_state.m_types.find(name); + + if (itr != m_state.m_types.end()) { + return itr->second; + } + + if (t_throw) { + throw std::range_error("Type Not Known: " + std::string(name)); + } else { + return Type_Info(); + } + } + + /// Returns the registered name of a known type_info object + /// compares the "bare_type_info" for the broadest possible + /// match + std::string get_type_name(const Type_Info &ti) const { + chaiscript::detail::threading::shared_lock l(m_mutex); + + for (const auto &elem : m_state.m_types) { + if (elem.second.bare_equal(ti)) { + return elem.first; } } - /// Returns the registered name of a known type_info object - /// compares the "bare_type_info" for the broadest possible - /// match - std::string get_type_name(const Type_Info &ti) const - { - chaiscript::detail::threading::shared_lock l(m_mutex); + return ti.bare_name(); + } - for (const auto & elem : m_state.m_types) - { - if (elem.second.bare_equal(ti)) - { - return elem.first; - } - } + /// Return all registered types + std::vector> get_types() const { + chaiscript::detail::threading::shared_lock l(m_mutex); - return ti.bare_name(); + return std::vector>(m_state.m_types.begin(), m_state.m_types.end()); + } + + std::shared_ptr> get_method_missing_functions() const { + uint_fast32_t method_missing_loc = m_method_missing_loc; + auto method_missing_funs = get_function("method_missing", method_missing_loc); + if (method_missing_funs.first != method_missing_loc) { + m_method_missing_loc = uint_fast32_t(method_missing_funs.first); } - /// Return all registered types - std::vector > get_types() const - { - chaiscript::detail::threading::shared_lock l(m_mutex); + return std::move(method_missing_funs.second); + } - return std::vector >(m_state.m_types.begin(), m_state.m_types.end()); + /// Return a function by name + std::pair>> get_function(std::string_view t_name, const size_t t_hint) const { + chaiscript::detail::threading::shared_lock l(m_mutex); + + const auto &funs = get_functions_int(); + + if (const auto itr = funs.find(t_name, t_hint); itr != funs.end()) { + return std::make_pair(std::distance(funs.begin(), itr), itr->second); + } else { + return std::make_pair(size_t(0), std::make_shared>()); + } + } + + /// \returns a function object (Boxed_Value wrapper) if it exists + /// \throws std::range_error if it does not + Boxed_Value get_function_object(const std::string &t_name) const { + chaiscript::detail::threading::shared_lock l(m_mutex); + + return get_function_object_int(t_name, 0).second; + } + + /// \returns a function object (Boxed_Value wrapper) if it exists + /// \throws std::range_error if it does not + /// \warn does not obtain a mutex lock. \sa get_function_object for public version + std::pair get_function_object_int(std::string_view t_name, const size_t t_hint) const { + const auto &funs = get_boxed_functions_int(); + + if (const auto itr = funs.find(t_name, t_hint); itr != funs.end()) { + return std::make_pair(std::distance(funs.begin(), itr), itr->second); + } else { + throw std::range_error("Object not found: " + std::string(t_name)); + } + } + + /// Return true if a function exists + bool function_exists(std::string_view name) const { + chaiscript::detail::threading::shared_lock l(m_mutex); + + return get_functions_int().count(name) > 0; + } + + /// \returns All values in the local thread state in the parent scope, or if it doesn't exist, + /// the current scope. + std::map get_parent_locals() const { + auto &stack = get_stack_data(); + if (stack.size() > 1) { + return std::map(stack[1].begin(), stack[1].end()); + } else { + return std::map(stack[0].begin(), stack[0].end()); + } + } + + /// \returns All values in the local thread state, added through the add() function + std::map get_locals() const { + auto &stack = get_stack_data(); + auto &scope = stack.front(); + return std::map(scope.begin(), scope.end()); + } + + /// \brief Sets all of the locals for the current thread state. + /// + /// \param[in] t_locals The map set of variables to replace the current state with + /// + /// Any existing locals are removed and the given set of variables is added + void set_locals(const std::map &t_locals) { + auto &stack = get_stack_data(); + auto &scope = stack.front(); + scope.assign(t_locals.begin(), t_locals.end()); + } + + /// + /// Get a map of all objects that can be seen from the current scope in a scripting context + /// + std::map get_scripting_objects() const { + const Stack_Holder &s = *m_stack_holder; + + // We don't want the current context, but one up if it exists + const StackData &stack = (s.stacks.size() == 1) ? (s.stacks.back()) : (s.stacks[s.stacks.size() - 2]); + + std::map retval; + + // note: map insert doesn't overwrite existing values, which is why this works + for (auto itr = stack.rbegin(); itr != stack.rend(); ++itr) { + retval.insert(itr->begin(), itr->end()); } - std::shared_ptr> get_method_missing_functions() const - { - uint_fast32_t method_missing_loc = m_method_missing_loc; - auto method_missing_funs = get_function("method_missing", method_missing_loc); - if (method_missing_funs.first != method_missing_loc) { - m_method_missing_loc = uint_fast32_t(method_missing_funs.first); - } + // add the global values + chaiscript::detail::threading::shared_lock l(m_mutex); + retval.insert(m_state.m_global_objects.begin(), m_state.m_global_objects.end()); - return std::move(method_missing_funs.second); + return retval; + } + + /// + /// Get a map of all functions that can be seen from a scripting context + /// + std::map get_function_objects() const { + chaiscript::detail::threading::shared_lock l(m_mutex); + + const auto &funs = get_function_objects_int(); + + std::map objs; + + for (const auto &fun : funs) { + objs.insert(std::make_pair(fun.first, const_var(fun.second))); } + return objs; + } - /// Return a function by name - std::pair>> get_function(std::string_view t_name, const size_t t_hint) const - { - chaiscript::detail::threading::shared_lock l(m_mutex); + /// Get a vector of all registered functions + std::vector> get_functions() const { + chaiscript::detail::threading::shared_lock l(m_mutex); - const auto &funs = get_functions_int(); + std::vector> rets; - if (const auto itr = funs.find(t_name, t_hint); itr != funs.end()) - { - return std::make_pair(std::distance(funs.begin(), itr), itr->second); - } else { - return std::make_pair(size_t(0), std::make_shared>()); + const auto &functions = get_functions_int(); + + for (const auto &function : functions) { + for (const auto &internal_func : *function.second) { + rets.emplace_back(function.first, internal_func); } } - /// \returns a function object (Boxed_Value wrapper) if it exists - /// \throws std::range_error if it does not - Boxed_Value get_function_object(const std::string &t_name) const - { - chaiscript::detail::threading::shared_lock l(m_mutex); + return rets; + } - return get_function_object_int(t_name, 0).second; + const Type_Conversions &conversions() const noexcept { return m_conversions; } + + static bool is_attribute_call(const std::vector &t_funs, + const Function_Params &t_params, + bool t_has_params, + const Type_Conversions_State &t_conversions) noexcept { + if (!t_has_params || t_params.empty()) { + return false; } - /// \returns a function object (Boxed_Value wrapper) if it exists - /// \throws std::range_error if it does not - /// \warn does not obtain a mutex lock. \sa get_function_object for public version - std::pair get_function_object_int(std::string_view t_name, const size_t t_hint) const - { - const auto &funs = get_boxed_functions_int(); - - if (const auto itr = funs.find(t_name, t_hint); itr != funs.end()) - { - return std::make_pair(std::distance(funs.begin(), itr), itr->second); - } else { - throw std::range_error("Object not found: " + std::string(t_name)); - } - } - - - /// Return true if a function exists - bool function_exists(std::string_view name) const - { - chaiscript::detail::threading::shared_lock l(m_mutex); - - return get_functions_int().count(name) > 0; - } - - /// \returns All values in the local thread state in the parent scope, or if it doesn't exist, - /// the current scope. - std::map get_parent_locals() const - { - auto &stack = get_stack_data(); - if (stack.size() > 1) - { - return std::map(stack[1].begin(), stack[1].end()); - } else { - return std::map(stack[0].begin(), stack[0].end()); - } - } - - /// \returns All values in the local thread state, added through the add() function - std::map get_locals() const - { - auto &stack = get_stack_data(); - auto &scope = stack.front(); - return std::map(scope.begin(), scope.end()); - } - - /// \brief Sets all of the locals for the current thread state. - /// - /// \param[in] t_locals The map set of variables to replace the current state with - /// - /// Any existing locals are removed and the given set of variables is added - void set_locals(const std::map &t_locals) - { - auto &stack = get_stack_data(); - auto &scope = stack.front(); - scope.assign(t_locals.begin(), t_locals.end()); - } - - - - /// - /// Get a map of all objects that can be seen from the current scope in a scripting context - /// - std::map get_scripting_objects() const - { - const Stack_Holder &s = *m_stack_holder; - - // We don't want the current context, but one up if it exists - const StackData &stack = (s.stacks.size()==1)?(s.stacks.back()):(s.stacks[s.stacks.size()-2]); - - std::map retval; - - // note: map insert doesn't overwrite existing values, which is why this works - for (auto itr = stack.rbegin(); itr != stack.rend(); ++itr) - { - retval.insert(itr->begin(), itr->end()); - } - - // add the global values - chaiscript::detail::threading::shared_lock l(m_mutex); - retval.insert(m_state.m_global_objects.begin(), m_state.m_global_objects.end()); - - return retval; - } - - - /// - /// Get a map of all functions that can be seen from a scripting context - /// - std::map get_function_objects() const - { - chaiscript::detail::threading::shared_lock l(m_mutex); - - const auto &funs = get_function_objects_int(); - - std::map objs; - - for (const auto & fun : funs) - { - objs.insert(std::make_pair(fun.first, const_var(fun.second))); - } - - return objs; - } - - - /// Get a vector of all registered functions - std::vector > get_functions() const - { - chaiscript::detail::threading::shared_lock l(m_mutex); - - std::vector > rets; - - const auto &functions = get_functions_int(); - - for (const auto & function : functions) - { - for (const auto & internal_func : *function.second) - { - rets.emplace_back(function.first, internal_func); - } - } - - return rets; - } - - - const Type_Conversions &conversions() const noexcept - { - return m_conversions; - } - - static bool is_attribute_call(const std::vector &t_funs, const Function_Params &t_params, - bool t_has_params, const Type_Conversions_State &t_conversions) noexcept - { - if (!t_has_params || t_params.empty()) { - return false; - } - - return std::any_of(std::begin(t_funs), std::end(t_funs), - [&](const auto &fun) { - return fun->is_attribute_function() && fun->compare_first_type(t_params[0], t_conversions); - } - ); - - } + return std::any_of(std::begin(t_funs), std::end(t_funs), [&](const auto &fun) { + return fun->is_attribute_function() && fun->compare_first_type(t_params[0], t_conversions); + }); + } #ifdef CHAISCRIPT_MSVC // MSVC is unable to recognize that "rethrow_exception" causes the function to return @@ -914,557 +756,449 @@ namespace chaiscript #pragma warning(push) #pragma warning(disable : 4715) #endif - Boxed_Value call_member(const std::string &t_name, std::atomic_uint_fast32_t &t_loc, const Function_Params ¶ms, bool t_has_params, - const Type_Conversions_State &t_conversions) - { - uint_fast32_t loc = t_loc; - const auto funs = get_function(t_name, loc); - if (funs.first != loc) { t_loc = uint_fast32_t(funs.first); } + Boxed_Value call_member(const std::string &t_name, + std::atomic_uint_fast32_t &t_loc, + const Function_Params ¶ms, + bool t_has_params, + const Type_Conversions_State &t_conversions) { + uint_fast32_t loc = t_loc; + const auto funs = get_function(t_name, loc); + if (funs.first != loc) { + t_loc = uint_fast32_t(funs.first); + } - const auto do_attribute_call = - [this](int l_num_params, Function_Params l_params, const std::vector &l_funs, const Type_Conversions_State &l_conversions)->Boxed_Value - { - Function_Params attr_params(l_params.begin(), l_params.begin() + l_num_params); - Boxed_Value bv = dispatch::dispatch(l_funs, attr_params, l_conversions); - if (l_num_params < int(l_params.size()) || bv.get_type_info().bare_equal(user_type())) { - struct This_Foist { - This_Foist(Dispatch_Engine &e, const Boxed_Value &t_bv) : m_e(e) { - m_e.get().new_scope(); - m_e.get().add_object("__this", t_bv); - } - - ~This_Foist() { - m_e.get().pop_scope(); - } - - std::reference_wrapper m_e; - }; - - This_Foist fi(*this, l_params.front()); - - try { - auto func = boxed_cast(bv); - try { - return (*func)({l_params.begin() + l_num_params, l_params.end()}, l_conversions); - } catch (const chaiscript::exception::bad_boxed_cast &) { - } catch (const chaiscript::exception::arity_error &) { - } catch (const chaiscript::exception::guard_error &) { - } - throw chaiscript::exception::dispatch_error({l_params.begin() + l_num_params, l_params.end()}, - std::vector{boxed_cast(bv)}); - } catch (const chaiscript::exception::bad_boxed_cast &) { - // unable to convert bv into a Proxy_Function_Base - throw chaiscript::exception::dispatch_error({l_params.begin() + l_num_params, l_params.end()}, - std::vector(l_funs.begin(), l_funs.end())); - } - } else { - return bv; + const auto do_attribute_call = [this](int l_num_params, + Function_Params l_params, + const std::vector &l_funs, + const Type_Conversions_State &l_conversions) -> Boxed_Value { + Function_Params attr_params(l_params.begin(), l_params.begin() + l_num_params); + Boxed_Value bv = dispatch::dispatch(l_funs, attr_params, l_conversions); + if (l_num_params < int(l_params.size()) || bv.get_type_info().bare_equal(user_type())) { + struct This_Foist { + This_Foist(Dispatch_Engine &e, const Boxed_Value &t_bv) + : m_e(e) { + m_e.get().new_scope(); + m_e.get().add_object("__this", t_bv); } + + ~This_Foist() { m_e.get().pop_scope(); } + + std::reference_wrapper m_e; }; - if (is_attribute_call(*funs.second, params, t_has_params, t_conversions)) { - return do_attribute_call(1, params, *funs.second, t_conversions); + This_Foist fi(*this, l_params.front()); + + try { + auto func = boxed_cast(bv); + try { + return (*func)({l_params.begin() + l_num_params, l_params.end()}, l_conversions); + } catch (const chaiscript::exception::bad_boxed_cast &) { + } catch (const chaiscript::exception::arity_error &) { + } catch (const chaiscript::exception::guard_error &) { + } + throw chaiscript::exception::dispatch_error({l_params.begin() + l_num_params, l_params.end()}, + std::vector{boxed_cast(bv)}); + } catch (const chaiscript::exception::bad_boxed_cast &) { + // unable to convert bv into a Proxy_Function_Base + throw chaiscript::exception::dispatch_error({l_params.begin() + l_num_params, l_params.end()}, + std::vector(l_funs.begin(), l_funs.end())); + } } else { - std::exception_ptr except; + return bv; + } + }; - if (!funs.second->empty()) { - try { - return dispatch::dispatch(*funs.second, params, t_conversions); - } catch(chaiscript::exception::dispatch_error&) { - except = std::current_exception(); - } - } + if (is_attribute_call(*funs.second, params, t_has_params, t_conversions)) { + return do_attribute_call(1, params, *funs.second, t_conversions); + } else { + std::exception_ptr except; - // If we get here we know that either there was no method with that name, - // or there was no matching method - - const auto functions = [&]()->std::vector { - std::vector fs; - - const auto method_missing_funs = get_method_missing_functions(); - - for (const auto &f : *method_missing_funs) - { - if(f->compare_first_type(params[0], t_conversions)) { - fs.push_back(f); - } - } - - return fs; - }(); - - - - const bool is_no_param = [&]()->bool{ - for (const auto &f : functions) { - if (f->get_arity() != 2) { - return false; - } - } - return true; - }(); - - if (!functions.empty()) { - try { - if (is_no_param) { - auto tmp_params = params.to_vector(); - tmp_params.insert(tmp_params.begin() + 1, var(t_name)); - return do_attribute_call(2, Function_Params(tmp_params), functions, t_conversions); - } else { - std::array p{params[0], var(t_name), var(std::vector(params.begin()+1, params.end()))}; - return dispatch::dispatch(functions, Function_Params{p}, t_conversions); - } - } catch (const dispatch::option_explicit_set &e) { - throw chaiscript::exception::dispatch_error(params, std::vector(funs.second->begin(), funs.second->end()), - e.what()); - } - } - - // If we get all the way down here we know there was no "method_missing" - // method at all. - if (except) { - std::rethrow_exception(except); - } else { - throw chaiscript::exception::dispatch_error(params, std::vector(funs.second->begin(), funs.second->end())); + if (!funs.second->empty()) { + try { + return dispatch::dispatch(*funs.second, params, t_conversions); + } catch (chaiscript::exception::dispatch_error &) { + except = std::current_exception(); } } + + // If we get here we know that either there was no method with that name, + // or there was no matching method + + const auto functions = [&]() -> std::vector { + std::vector fs; + + const auto method_missing_funs = get_method_missing_functions(); + + for (const auto &f : *method_missing_funs) { + if (f->compare_first_type(params[0], t_conversions)) { + fs.push_back(f); + } + } + + return fs; + }(); + + const bool is_no_param = [&]() -> bool { + for (const auto &f : functions) { + if (f->get_arity() != 2) { + return false; + } + } + return true; + }(); + + if (!functions.empty()) { + try { + if (is_no_param) { + auto tmp_params = params.to_vector(); + tmp_params.insert(tmp_params.begin() + 1, var(t_name)); + return do_attribute_call(2, Function_Params(tmp_params), functions, t_conversions); + } else { + std::array p{params[0], var(t_name), var(std::vector(params.begin() + 1, params.end()))}; + return dispatch::dispatch(functions, Function_Params{p}, t_conversions); + } + } catch (const dispatch::option_explicit_set &e) { + throw chaiscript::exception::dispatch_error(params, + std::vector(funs.second->begin(), funs.second->end()), + e.what()); + } + } + + // If we get all the way down here we know there was no "method_missing" + // method at all. + if (except) { + std::rethrow_exception(except); + } else { + throw chaiscript::exception::dispatch_error(params, + std::vector(funs.second->begin(), funs.second->end())); + } } + } #ifdef CHAISCRIPT_MSVC #pragma warning(pop) #endif + Boxed_Value call_function(std::string_view t_name, + std::atomic_uint_fast32_t &t_loc, + const Function_Params ¶ms, + const Type_Conversions_State &t_conversions) const { + uint_fast32_t loc = t_loc; + const auto [func_loc, func] = get_function(t_name, loc); + if (func_loc != loc) { + t_loc = uint_fast32_t(func_loc); + } + return dispatch::dispatch(*func, params, t_conversions); + } + /// Dump object info to stdout + void dump_object(const Boxed_Value &o) const { std::cout << (o.is_const() ? "const " : "") << type_name(o) << '\n'; } - Boxed_Value call_function(std::string_view t_name, std::atomic_uint_fast32_t &t_loc, const Function_Params ¶ms, - const Type_Conversions_State &t_conversions) const - { - uint_fast32_t loc = t_loc; - const auto [func_loc, func] = get_function(t_name, loc); - if (func_loc != loc) { t_loc = uint_fast32_t(func_loc); } - return dispatch::dispatch(*func, params, t_conversions); + /// Dump type info to stdout + void dump_type(const Type_Info &type) const { std::cout << (type.is_const() ? "const " : "") << get_type_name(type); } + + /// Dump function to stdout + void dump_function(const std::pair &f) const { + const auto params = f.second->get_param_types(); + + dump_type(params.front()); + std::cout << " " << f.first << "("; + + for (auto itr = params.begin() + 1; itr != params.end();) { + dump_type(*itr); + ++itr; + + if (itr != params.end()) { + std::cout << ", "; + } } + std::cout << ") \n"; + } - /// Dump object info to stdout - void dump_object(const Boxed_Value &o) const - { - std::cout << (o.is_const()?"const ":"") << type_name(o) << '\n'; + /// Returns true if a call can be made that consists of the first parameter + /// (the function) with the remaining parameters as its arguments. + Boxed_Value call_exists(const Function_Params ¶ms) const { + if (params.empty()) { + throw chaiscript::exception::arity_error(static_cast(params.size()), 1); } - /// Dump type info to stdout - void dump_type(const Type_Info &type) const - { - std::cout << (type.is_const()?"const ":"") << get_type_name(type); + const auto &f = this->boxed_cast(params[0]); + const Type_Conversions_State convs(m_conversions, m_conversions.conversion_saves()); + + return const_var(f->call_match(Function_Params(params.begin() + 1, params.end()), convs)); + } + + /// Dump all system info to stdout + void dump_system() const { + std::cout << "Registered Types: \n"; + for (const auto &[type_name, type] : get_types()) { + std::cout << type_name << ": " << type.bare_name() << '\n'; } - /// Dump function to stdout - void dump_function(const std::pair &f) const - { - const auto params = f.second->get_param_types(); + std::cout << '\n'; - dump_type(params.front()); - std::cout << " " << f.first << "("; + std::cout << "Functions: \n"; + for (const auto &func : get_functions()) { + dump_function(func); + } + std::cout << '\n'; + } - for (auto itr = params.begin() + 1; - itr != params.end(); - ) - { - dump_type(*itr); - ++itr; - - if (itr != params.end()) - { - std::cout << ", "; - } + /// return true if the Boxed_Value matches the registered type by name + bool is_type(const Boxed_Value &r, std::string_view user_typename) const noexcept { + try { + if (get_type(user_typename).bare_equal(r.get_type_info())) { + return true; } - - std::cout << ") \n"; + } catch (const std::range_error &) { } - /// Returns true if a call can be made that consists of the first parameter - /// (the function) with the remaining parameters as its arguments. - Boxed_Value call_exists(const Function_Params ¶ms) const - { - if (params.empty()) - { - throw chaiscript::exception::arity_error(static_cast(params.size()), 1); - } - - const auto &f = this->boxed_cast(params[0]); - const Type_Conversions_State convs(m_conversions, m_conversions.conversion_saves()); - - return const_var(f->call_match(Function_Params(params.begin() + 1, params.end()), convs)); + try { + const dispatch::Dynamic_Object &d = boxed_cast(r); + return d.get_type_name() == user_typename; + } catch (const std::bad_cast &) { } - /// Dump all system info to stdout - void dump_system() const - { - std::cout << "Registered Types: \n"; - for (const auto &[type_name, type] : get_types() ) - { - std::cout << type_name << ": " << type.bare_name() << '\n'; - } + return false; + } - std::cout << '\n'; + std::string type_name(const Boxed_Value &obj) const { return get_type_name(obj.get_type_info()); } - std::cout << "Functions: \n"; - for (const auto &func : get_functions()) - { - dump_function(func); - } - std::cout << '\n'; + State get_state() const { + chaiscript::detail::threading::shared_lock l(m_mutex); + + return m_state; + } + + void set_state(const State &t_state) { + chaiscript::detail::threading::unique_lock l(m_mutex); + + m_state = t_state; + } + + static void save_function_params(Stack_Holder &t_s, std::vector &&t_params) { + for (auto &¶m : t_params) { + t_s.call_params.back().insert(t_s.call_params.back().begin(), std::move(param)); + } + } + + static void save_function_params(Stack_Holder &t_s, const Function_Params &t_params) { + t_s.call_params.back().insert(t_s.call_params.back().begin(), t_params.begin(), t_params.end()); + } + + void save_function_params(std::vector &&t_params) { save_function_params(*m_stack_holder, std::move(t_params)); } + + void save_function_params(const Function_Params &t_params) { save_function_params(*m_stack_holder, t_params); } + + void new_function_call(Stack_Holder &t_s, Type_Conversions::Conversion_Saves &t_saves) { + if (t_s.call_depth == 0) { + m_conversions.enable_conversion_saves(t_saves, true); } - /// return true if the Boxed_Value matches the registered type by name - bool is_type(const Boxed_Value &r, std::string_view user_typename) const noexcept - { - try { - if (get_type(user_typename).bare_equal(r.get_type_info())) - { - return true; - } - } catch (const std::range_error &) { - } + ++t_s.call_depth; - try { - const dispatch::Dynamic_Object &d = boxed_cast(r); - return d.get_type_name() == user_typename; - } catch (const std::bad_cast &) { - } + save_function_params(m_conversions.take_saves(t_saves)); + } + void pop_function_call(Stack_Holder &t_s, Type_Conversions::Conversion_Saves &t_saves) { + --t_s.call_depth; + + assert(t_s.call_depth >= 0); + + if (t_s.call_depth == 0) { + t_s.call_params.back().clear(); + m_conversions.enable_conversion_saves(t_saves, false); + } + } + + void new_function_call() { new_function_call(*m_stack_holder, m_conversions.conversion_saves()); } + + void pop_function_call() { pop_function_call(*m_stack_holder, m_conversions.conversion_saves()); } + + Stack_Holder &get_stack_holder() noexcept { return *m_stack_holder; } + + /// Returns the current stack + /// make const/non const versions + const StackData &get_stack_data() const noexcept { return m_stack_holder->stacks.back(); } + + static StackData &get_stack_data(Stack_Holder &t_holder) noexcept { return t_holder.stacks.back(); } + + StackData &get_stack_data() noexcept { return m_stack_holder->stacks.back(); } + + parser::ChaiScript_Parser_Base &get_parser() noexcept { return m_parser.get(); } + + private: + const decltype(State::m_boxed_functions) &get_boxed_functions_int() const noexcept { return m_state.m_boxed_functions; } + + decltype(State::m_boxed_functions) &get_boxed_functions_int() noexcept { return m_state.m_boxed_functions; } + + const decltype(State::m_function_objects) &get_function_objects_int() const noexcept { return m_state.m_function_objects; } + + decltype(State::m_function_objects) &get_function_objects_int() noexcept { return m_state.m_function_objects; } + + const decltype(State::m_functions) &get_functions_int() const noexcept { return m_state.m_functions; } + + decltype(State::m_functions) &get_functions_int() noexcept { return m_state.m_functions; } + + static bool function_less_than(const Proxy_Function &lhs, const Proxy_Function &rhs) noexcept { + auto dynamic_lhs(std::dynamic_pointer_cast(lhs)); + auto dynamic_rhs(std::dynamic_pointer_cast(rhs)); + + if (dynamic_lhs && dynamic_rhs) { + if (dynamic_lhs->get_guard()) { + return dynamic_rhs->get_guard() ? false : true; + } else { + return false; + } + } + + if (dynamic_lhs && !dynamic_rhs) { return false; } - std::string type_name(const Boxed_Value &obj) const - { - return get_type_name(obj.get_type_info()); + if (!dynamic_lhs && dynamic_rhs) { + return true; } - State get_state() const - { - chaiscript::detail::threading::shared_lock l(m_mutex); + const auto &lhsparamtypes = lhs->get_param_types(); + const auto &rhsparamtypes = rhs->get_param_types(); - return m_state; - } + const auto lhssize = lhsparamtypes.size(); + const auto rhssize = rhsparamtypes.size(); - void set_state(const State &t_state) - { - chaiscript::detail::threading::unique_lock l(m_mutex); + const auto boxed_type = user_type(); + const auto boxed_pod_type = user_type(); - m_state = t_state; - } + for (size_t i = 1; i < lhssize && i < rhssize; ++i) { + const Type_Info < = lhsparamtypes[i]; + const Type_Info &rt = rhsparamtypes[i]; - static void save_function_params(Stack_Holder &t_s, std::vector &&t_params) - { - for (auto &¶m : t_params) - { - t_s.call_params.back().insert(t_s.call_params.back().begin(), std::move(param)); - } - } - - static void save_function_params(Stack_Holder &t_s, const Function_Params &t_params) - { - t_s.call_params.back().insert(t_s.call_params.back().begin(), t_params.begin(), t_params.end()); - } - - void save_function_params(std::vector &&t_params) - { - save_function_params(*m_stack_holder, std::move(t_params)); - } - - void save_function_params(const Function_Params &t_params) - { - save_function_params(*m_stack_holder, t_params); - } - - void new_function_call(Stack_Holder &t_s, Type_Conversions::Conversion_Saves &t_saves) - { - if (t_s.call_depth == 0) - { - m_conversions.enable_conversion_saves(t_saves, true); + if (lt.bare_equal(rt) && lt.is_const() == rt.is_const()) { + continue; // The first two types are essentially the same, next iteration } - ++t_s.call_depth; - - save_function_params(m_conversions.take_saves(t_saves)); - } - - void pop_function_call(Stack_Holder &t_s, Type_Conversions::Conversion_Saves &t_saves) - { - --t_s.call_depth; - - assert(t_s.call_depth >= 0); - - if (t_s.call_depth == 0) - { - t_s.call_params.back().clear(); - m_conversions.enable_conversion_saves(t_saves, false); - } - } - - void new_function_call() - { - new_function_call(*m_stack_holder, m_conversions.conversion_saves()); - } - - void pop_function_call() - { - pop_function_call(*m_stack_holder, m_conversions.conversion_saves()); - } - - Stack_Holder &get_stack_holder() noexcept - { - return *m_stack_holder; - } - - /// Returns the current stack - /// make const/non const versions - const StackData &get_stack_data() const noexcept - { - return m_stack_holder->stacks.back(); - } - - static StackData &get_stack_data(Stack_Holder &t_holder) noexcept - { - return t_holder.stacks.back(); - } - - StackData &get_stack_data() noexcept - { - return m_stack_holder->stacks.back(); - } - - parser::ChaiScript_Parser_Base &get_parser() noexcept - { - return m_parser.get(); - } - - private: - - const decltype(State::m_boxed_functions) &get_boxed_functions_int() const noexcept - { - return m_state.m_boxed_functions; - } - - decltype(State::m_boxed_functions) &get_boxed_functions_int() noexcept - { - return m_state.m_boxed_functions; - } - - const decltype(State::m_function_objects) &get_function_objects_int() const noexcept - { - return m_state.m_function_objects; - } - - decltype(State::m_function_objects) &get_function_objects_int() noexcept - { - return m_state.m_function_objects; - } - - const decltype(State::m_functions) &get_functions_int() const noexcept - { - return m_state.m_functions; - } - - decltype(State::m_functions) &get_functions_int() noexcept - { - return m_state.m_functions; - } - - static bool function_less_than(const Proxy_Function &lhs, const Proxy_Function &rhs) noexcept - { - - auto dynamic_lhs(std::dynamic_pointer_cast(lhs)); - auto dynamic_rhs(std::dynamic_pointer_cast(rhs)); - - if (dynamic_lhs && dynamic_rhs) - { - if (dynamic_lhs->get_guard()) - { - return dynamic_rhs->get_guard() ? false : true; - } else { - return false; - } - } - - if (dynamic_lhs && !dynamic_rhs) - { + // const is after non-const for the same type + if (lt.bare_equal(rt) && lt.is_const() && !rt.is_const()) { return false; } - if (!dynamic_lhs && dynamic_rhs) - { + if (lt.bare_equal(rt) && !lt.is_const()) { return true; } - const auto &lhsparamtypes = lhs->get_param_types(); - const auto &rhsparamtypes = rhs->get_param_types(); - - const auto lhssize = lhsparamtypes.size(); - const auto rhssize = rhsparamtypes.size(); - - const auto boxed_type = user_type(); - const auto boxed_pod_type = user_type(); - - for (size_t i = 1; i < lhssize && i < rhssize; ++i) - { - const Type_Info < = lhsparamtypes[i]; - const Type_Info &rt = rhsparamtypes[i]; - - if (lt.bare_equal(rt) && lt.is_const() == rt.is_const()) - { - continue; // The first two types are essentially the same, next iteration - } - - // const is after non-const for the same type - if (lt.bare_equal(rt) && lt.is_const() && !rt.is_const()) - { - return false; - } - - if (lt.bare_equal(rt) && !lt.is_const()) - { - return true; - } - - // boxed_values are sorted last - if (lt.bare_equal(boxed_type)) - { - return false; - } - - if (rt.bare_equal(boxed_type)) - { - return true; - } - - if (lt.bare_equal(boxed_pod_type)) - { - return false; - } - - if (rt.bare_equal(boxed_pod_type)) - { - return true; - } - - // otherwise, we want to sort by typeid - return lt < rt; + // boxed_values are sorted last + if (lt.bare_equal(boxed_type)) { + return false; } - return false; + if (rt.bare_equal(boxed_type)) { + return true; + } + + if (lt.bare_equal(boxed_pod_type)) { + return false; + } + + if (rt.bare_equal(boxed_pod_type)) { + return true; + } + + // otherwise, we want to sort by typeid + return lt < rt; } - /// Implementation detail for adding a function. - /// \throws exception::name_conflict_error if there's a function matching the given one being added - void add_function(const Proxy_Function &t_f, const std::string &t_name) - { - chaiscript::detail::threading::unique_lock l(m_mutex); + return false; + } - Proxy_Function new_func = - [&]() -> Proxy_Function { - auto &funcs = get_functions_int(); - auto itr = funcs.find(t_name); + /// Implementation detail for adding a function. + /// \throws exception::name_conflict_error if there's a function matching the given one being added + void add_function(const Proxy_Function &t_f, const std::string &t_name) { + chaiscript::detail::threading::unique_lock l(m_mutex); - if (itr != funcs.end()) - { - auto vec = *itr->second; - for (const auto &func : vec) - { - if ((*t_f) == *(func)) - { - throw chaiscript::exception::name_conflict_error(t_name); - } - } + Proxy_Function new_func = [&]() -> Proxy_Function { + auto &funcs = get_functions_int(); + auto itr = funcs.find(t_name); - vec.reserve(vec.size() + 1); // tightly control vec growth - vec.push_back(t_f); - std::stable_sort(vec.begin(), vec.end(), &function_less_than); - itr->second = std::make_shared>(vec); - return std::make_shared(std::move(vec)); - } else if (t_f->has_arithmetic_param()) { - // if the function is the only function but it also contains - // arithmetic operators, we must wrap it in a dispatch function - // to allow for automatic arithmetic type conversions - std::vector vec; - vec.push_back(t_f); - funcs.insert(std::pair{t_name, std::make_shared>(vec)}); - return std::make_shared(std::move(vec)); - } else { - auto vec = std::make_shared>(); - vec->push_back(t_f); - funcs.insert(std::pair{t_name, vec}); - return t_f; + if (itr != funcs.end()) { + auto vec = *itr->second; + for (const auto &func : vec) { + if ((*t_f) == *(func)) { + throw chaiscript::exception::name_conflict_error(t_name); } - }(); + } + vec.reserve(vec.size() + 1); // tightly control vec growth + vec.push_back(t_f); + std::stable_sort(vec.begin(), vec.end(), &function_less_than); + itr->second = std::make_shared>(vec); + return std::make_shared(std::move(vec)); + } else if (t_f->has_arithmetic_param()) { + // if the function is the only function but it also contains + // arithmetic operators, we must wrap it in a dispatch function + // to allow for automatic arithmetic type conversions + std::vector vec; + vec.push_back(t_f); + funcs.insert(std::pair{t_name, std::make_shared>(vec)}); + return std::make_shared(std::move(vec)); + } else { + auto vec = std::make_shared>(); + vec->push_back(t_f); + funcs.insert(std::pair{t_name, vec}); + return t_f; + } + }(); - get_boxed_functions_int().insert_or_assign(t_name, const_var(new_func)); - get_function_objects_int().insert_or_assign(t_name, std::move(new_func)); - } + get_boxed_functions_int().insert_or_assign(t_name, const_var(new_func)); + get_function_objects_int().insert_or_assign(t_name, std::move(new_func)); + } - mutable chaiscript::detail::threading::shared_mutex m_mutex; + mutable chaiscript::detail::threading::shared_mutex m_mutex; + Type_Conversions m_conversions; + chaiscript::detail::threading::Thread_Storage m_stack_holder; + std::reference_wrapper m_parser; - Type_Conversions m_conversions; - chaiscript::detail::threading::Thread_Storage m_stack_holder; - std::reference_wrapper m_parser; + mutable std::atomic_uint_fast32_t m_method_missing_loc = {0}; - mutable std::atomic_uint_fast32_t m_method_missing_loc = {0}; - - State m_state; + State m_state; }; - class Dispatch_State - { - public: - explicit Dispatch_State(Dispatch_Engine &t_engine) - : m_engine(t_engine), - m_stack_holder(t_engine.get_stack_holder()), - m_conversions(t_engine.conversions(), t_engine.conversions().conversion_saves()) - { - } + class Dispatch_State { + public: + explicit Dispatch_State(Dispatch_Engine &t_engine) + : m_engine(t_engine) + , m_stack_holder(t_engine.get_stack_holder()) + , m_conversions(t_engine.conversions(), t_engine.conversions().conversion_saves()) { + } - Dispatch_Engine *operator->() const noexcept { - return &m_engine.get(); - } + Dispatch_Engine *operator->() const noexcept { return &m_engine.get(); } - Dispatch_Engine &operator*() const noexcept { - return m_engine.get(); - } + Dispatch_Engine &operator*() const noexcept { return m_engine.get(); } - Stack_Holder &stack_holder() const noexcept { - return m_stack_holder.get(); - } + Stack_Holder &stack_holder() const noexcept { return m_stack_holder.get(); } - const Type_Conversions_State &conversions() const noexcept { - return m_conversions; - } + const Type_Conversions_State &conversions() const noexcept { return m_conversions; } - Type_Conversions::Conversion_Saves &conversion_saves() const noexcept { - return m_conversions.saves(); - } + Type_Conversions::Conversion_Saves &conversion_saves() const noexcept { return m_conversions.saves(); } - Boxed_Value &add_get_object(const std::string &t_name, Boxed_Value obj) const { - return m_engine.get().add_get_object(t_name, std::move(obj), m_stack_holder.get()); - } + Boxed_Value &add_get_object(const std::string &t_name, Boxed_Value obj) const { + return m_engine.get().add_get_object(t_name, std::move(obj), m_stack_holder.get()); + } - void add_object(const std::string &t_name, Boxed_Value obj) const { - m_engine.get().add_object(t_name, std::move(obj), m_stack_holder.get()); - } + void add_object(const std::string &t_name, Boxed_Value obj) const { + m_engine.get().add_object(t_name, std::move(obj), m_stack_holder.get()); + } - Boxed_Value get_object(std::string_view t_name, std::atomic_uint_fast32_t &t_loc) const { - return m_engine.get().get_object(t_name, t_loc, m_stack_holder.get()); - } + Boxed_Value get_object(std::string_view t_name, std::atomic_uint_fast32_t &t_loc) const { + return m_engine.get().get_object(t_name, t_loc, m_stack_holder.get()); + } - private: - std::reference_wrapper m_engine; - std::reference_wrapper m_stack_holder; - Type_Conversions_State m_conversions; + private: + std::reference_wrapper m_engine; + std::reference_wrapper m_stack_holder; + Type_Conversions_State m_conversions; }; - } -} + } // namespace detail +} // namespace chaiscript #endif - - diff --git a/include/chaiscript/dispatchkit/dynamic_object.hpp b/include/chaiscript/dispatchkit/dynamic_object.hpp index cd41b4b4..b242a207 100644 --- a/include/chaiscript/dispatchkit/dynamic_object.hpp +++ b/include/chaiscript/dispatchkit/dynamic_object.hpp @@ -7,7 +7,6 @@ // This is an open source non-commercial project. Dear PVS-Studio, please check it. // PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com - #ifndef CHAISCRIPT_DYNAMIC_OBJECT_HPP_ #define CHAISCRIPT_DYNAMIC_OBJECT_HPP_ @@ -18,21 +17,17 @@ #include "boxed_value.hpp" namespace chaiscript { -class Type_Conversions; -namespace dispatch { -class Proxy_Function_Base; -} // namespace dispatch -} // namespace chaiscript + class Type_Conversions; + namespace dispatch { + class Proxy_Function_Base; + } // namespace dispatch +} // namespace chaiscript -namespace chaiscript -{ - namespace dispatch - { +namespace chaiscript { + namespace dispatch { struct option_explicit_set : std::runtime_error { 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; @@ -40,92 +35,64 @@ namespace chaiscript ~option_explicit_set() noexcept override = default; }; - class Dynamic_Object - { - public: - explicit Dynamic_Object(std::string t_type_name) - : m_type_name(std::move(t_type_name)), m_option_explicit(false) - { + class Dynamic_Object { + public: + explicit Dynamic_Object(std::string t_type_name) + : m_type_name(std::move(t_type_name)) + , m_option_explicit(false) { + } + + Dynamic_Object() = default; + + bool is_explicit() const noexcept { return m_option_explicit; } + + void set_explicit(const bool t_explicit) noexcept { m_option_explicit = t_explicit; } + + const std::string &get_type_name() const noexcept { return m_type_name; } + + const Boxed_Value &operator[](const std::string &t_attr_name) const { return get_attr(t_attr_name); } + + Boxed_Value &operator[](const std::string &t_attr_name) { return get_attr(t_attr_name); } + + const Boxed_Value &get_attr(const std::string &t_attr_name) const { + auto a = m_attrs.find(t_attr_name); + + if (a != m_attrs.end()) { + return a->second; + } else { + throw std::range_error("Attr not found '" + t_attr_name + "' and cannot be added to const obj"); + } + } + + bool has_attr(const std::string &t_attr_name) const { return m_attrs.find(t_attr_name) != m_attrs.end(); } + + Boxed_Value &get_attr(const std::string &t_attr_name) { return m_attrs[t_attr_name]; } + + Boxed_Value &method_missing(const std::string &t_method_name) { + if (m_option_explicit && m_attrs.find(t_method_name) == m_attrs.end()) { + throw option_explicit_set(t_method_name); } - Dynamic_Object() = default; + return get_attr(t_method_name); + } - bool is_explicit() const noexcept - { - return m_option_explicit; + 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()) { + throw option_explicit_set(t_method_name); } - void set_explicit(const bool t_explicit) noexcept - { - m_option_explicit = t_explicit; - } + return get_attr(t_method_name); + } - const std::string &get_type_name() const noexcept - { - return m_type_name; - } + std::map get_attrs() const { return m_attrs; } - const Boxed_Value &operator[](const std::string &t_attr_name) const - { - return get_attr(t_attr_name); - } + private: + const std::string m_type_name = ""; + bool m_option_explicit = false; - Boxed_Value &operator[](const std::string &t_attr_name) - { - return get_attr(t_attr_name); - } - - const Boxed_Value &get_attr(const std::string &t_attr_name) const - { - auto a = m_attrs.find(t_attr_name); - - if (a != m_attrs.end()) { - return a->second; - } else { - throw std::range_error("Attr not found '" + t_attr_name + "' and cannot be added to const obj"); - } - } - - bool has_attr(const std::string &t_attr_name) const { - return m_attrs.find(t_attr_name) != m_attrs.end(); - } - - Boxed_Value &get_attr(const std::string &t_attr_name) - { - return m_attrs[t_attr_name]; - } - - Boxed_Value &method_missing(const std::string &t_method_name) - { - if (m_option_explicit && m_attrs.find(t_method_name) == m_attrs.end()) { - throw option_explicit_set(t_method_name); - } - - return get_attr(t_method_name); - } - - 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()) { - throw option_explicit_set(t_method_name); - } - - return get_attr(t_method_name); - } - - std::map get_attrs() const - { - return m_attrs; - } - - private: - const std::string m_type_name = ""; - bool m_option_explicit = false; - - std::map m_attrs; + std::map m_attrs; }; - } -} + } // namespace dispatch +} // namespace chaiscript #endif - diff --git a/include/chaiscript/dispatchkit/dynamic_object_detail.hpp b/include/chaiscript/dispatchkit/dynamic_object_detail.hpp index 2b285963..07477c1e 100644 --- a/include/chaiscript/dispatchkit/dynamic_object_detail.hpp +++ b/include/chaiscript/dispatchkit/dynamic_object_detail.hpp @@ -19,219 +19,185 @@ #include "boxed_cast.hpp" #include "boxed_cast_helper.hpp" #include "boxed_value.hpp" +#include "dynamic_object.hpp" #include "proxy_functions.hpp" #include "type_info.hpp" -#include "dynamic_object.hpp" namespace chaiscript { -class Type_Conversions; -namespace dispatch { -class Proxy_Function_Base; -} // namespace dispatch -} // namespace chaiscript + class Type_Conversions; + namespace dispatch { + class Proxy_Function_Base; + } // namespace dispatch +} // namespace chaiscript -namespace chaiscript -{ - namespace dispatch - { - namespace detail - { +namespace chaiscript { + namespace dispatch { + namespace detail { /// A Proxy_Function implementation designed for calling a function /// that is automatically guarded based on the first param based on the /// param's type name - class Dynamic_Object_Function final : public Proxy_Function_Base - { - public: - Dynamic_Object_Function( - std::string t_type_name, - const Proxy_Function &t_func, - bool t_is_attribute = false) - : Proxy_Function_Base(t_func->get_param_types(), t_func->get_arity()), - m_type_name(std::move(t_type_name)), m_func(t_func), m_doti(user_type()), - m_is_attribute(t_is_attribute) - { - assert( (t_func->get_arity() > 0 || t_func->get_arity() < 0) - && "Programming error, Dynamic_Object_Function must have at least one parameter (this)"); + class Dynamic_Object_Function final : public Proxy_Function_Base { + public: + Dynamic_Object_Function(std::string t_type_name, const Proxy_Function &t_func, bool t_is_attribute = false) + : Proxy_Function_Base(t_func->get_param_types(), t_func->get_arity()) + , m_type_name(std::move(t_type_name)) + , m_func(t_func) + , m_doti(user_type()) + , m_is_attribute(t_is_attribute) { + assert((t_func->get_arity() > 0 || t_func->get_arity() < 0) + && "Programming error, Dynamic_Object_Function must have at least one parameter (this)"); + } + + Dynamic_Object_Function(std::string t_type_name, const Proxy_Function &t_func, const Type_Info &t_ti, bool t_is_attribute = false) + : Proxy_Function_Base(build_param_types(t_func->get_param_types(), t_ti), t_func->get_arity()) + , m_type_name(std::move(t_type_name)) + , m_func(t_func) + , m_ti(t_ti.is_undef() ? nullptr : new Type_Info(t_ti)) + , m_doti(user_type()) + , m_is_attribute(t_is_attribute) { + assert((t_func->get_arity() > 0 || t_func->get_arity() < 0) + && "Programming error, Dynamic_Object_Function must have at least one parameter (this)"); + } + + Dynamic_Object_Function &operator=(const Dynamic_Object_Function) = delete; + Dynamic_Object_Function(Dynamic_Object_Function &) = delete; + + bool operator==(const Proxy_Function_Base &f) const noexcept override { + if (const auto *df = dynamic_cast(&f)) { + return df->m_type_name == m_type_name && (*df->m_func) == (*m_func); + } else { + return false; } + } - Dynamic_Object_Function( - std::string t_type_name, - const Proxy_Function &t_func, - const Type_Info &t_ti, - bool t_is_attribute = false) - : Proxy_Function_Base(build_param_types(t_func->get_param_types(), t_ti), t_func->get_arity()), - m_type_name(std::move(t_type_name)), m_func(t_func), m_ti(t_ti.is_undef()?nullptr:new Type_Info(t_ti)), m_doti(user_type()), - m_is_attribute(t_is_attribute) - { - assert( (t_func->get_arity() > 0 || t_func->get_arity() < 0) - && "Programming error, Dynamic_Object_Function must have at least one parameter (this)"); + 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 { + if (dynamic_object_typename_match(vals, m_type_name, m_ti, t_conversions)) { + return m_func->call_match(vals, t_conversions); + } else { + return false; } + } + std::vector get_contained_functions() const override { return {m_func}; } - Dynamic_Object_Function &operator=(const Dynamic_Object_Function) = delete; - Dynamic_Object_Function(Dynamic_Object_Function &) = delete; + protected: + Boxed_Value do_call(const chaiscript::Function_Params ¶ms, const Type_Conversions_State &t_conversions) const override { + if (dynamic_object_typename_match(params, m_type_name, m_ti, t_conversions)) { + return (*m_func)(params, t_conversions); + } else { + throw exception::guard_error(); + } + } - bool operator==(const Proxy_Function_Base &f) const noexcept override - { - if (const auto *df = dynamic_cast(&f)) - { - return df->m_type_name == m_type_name && (*df->m_func) == (*m_func); + 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); + } + + private: + static std::vector build_param_types(const std::vector &t_inner_types, const Type_Info &t_objectti) { + std::vector types(t_inner_types); + + assert(types.size() > 1); + // assert(types[1].bare_equal(user_type())); + types[1] = t_objectti; + return types; + } + + bool dynamic_object_typename_match(const Boxed_Value &bv, + const std::string &name, + const std::unique_ptr &ti, + const Type_Conversions_State &t_conversions) const noexcept { + if (bv.get_type_info().bare_equal(m_doti)) { + try { + const Dynamic_Object &d = boxed_cast(bv, &t_conversions); + return name == "Dynamic_Object" || d.get_type_name() == name; + } catch (const std::bad_cast &) { + return false; + } + } else { + if (ti) { + return bv.get_type_info().bare_equal(*ti); } else { return false; } } + } - bool 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 - { - if (dynamic_object_typename_match(vals, m_type_name, m_ti, t_conversions)) - { - return m_func->call_match(vals, t_conversions); - } else { - return false; - } + bool dynamic_object_typename_match(const chaiscript::Function_Params &bvs, + const std::string &name, + const std::unique_ptr &ti, + const Type_Conversions_State &t_conversions) const noexcept { + if (!bvs.empty()) { + return dynamic_object_typename_match(bvs[0], name, ti, t_conversions); + } else { + return false; } + } - std::vector get_contained_functions() const override - { - return {m_func}; - } - - protected: - Boxed_Value do_call(const chaiscript::Function_Params ¶ms, const Type_Conversions_State &t_conversions) const override - { - if (dynamic_object_typename_match(params, m_type_name, m_ti, t_conversions)) - { - return (*m_func)(params, t_conversions); - } else { - throw exception::guard_error(); - } - } - - 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); - } - - private: - static std::vector build_param_types( - const std::vector &t_inner_types, const Type_Info& t_objectti) - { - std::vector types(t_inner_types); - - assert(types.size() > 1); - //assert(types[1].bare_equal(user_type())); - types[1] = t_objectti; - return types; - } - - bool dynamic_object_typename_match(const Boxed_Value &bv, const std::string &name, - const std::unique_ptr &ti, const Type_Conversions_State &t_conversions) const noexcept - { - if (bv.get_type_info().bare_equal(m_doti)) - { - try { - const Dynamic_Object &d = boxed_cast(bv, &t_conversions); - return name == "Dynamic_Object" || d.get_type_name() == name; - } catch (const std::bad_cast &) { - return false; - } - } else { - if (ti) - { - return bv.get_type_info().bare_equal(*ti); - } else { - return false; - } - } - - } - - bool dynamic_object_typename_match(const chaiscript::Function_Params &bvs, const std::string &name, - const std::unique_ptr &ti, const Type_Conversions_State &t_conversions) const noexcept - { - if (!bvs.empty()) - { - return dynamic_object_typename_match(bvs[0], name, ti, t_conversions); - } else { - return false; - } - } - - std::string m_type_name; - Proxy_Function m_func; - std::unique_ptr m_ti; - const Type_Info m_doti; - const bool m_is_attribute; + std::string m_type_name; + Proxy_Function m_func; + std::unique_ptr m_ti; + const Type_Info m_doti; + const bool m_is_attribute; }; - /** - * A Proxy_Function implementation designed for creating a new - * Dynamic_Object - * that is automatically guarded based on the first param based on the - * param's type name - */ - class Dynamic_Object_Constructor final : public Proxy_Function_Base - { - public: - Dynamic_Object_Constructor( - std::string t_type_name, - const Proxy_Function &t_func) - : Proxy_Function_Base(build_type_list(t_func->get_param_types()), t_func->get_arity() - 1), - m_type_name(std::move(t_type_name)), m_func(t_func) - { - assert( (t_func->get_arity() > 0 || t_func->get_arity() < 0) - && "Programming error, Dynamic_Object_Function must have at least one parameter (this)"); + * A Proxy_Function implementation designed for creating a new + * Dynamic_Object + * that is automatically guarded based on the first param based on the + * param's type name + */ + class Dynamic_Object_Constructor final : public Proxy_Function_Base { + public: + Dynamic_Object_Constructor(std::string t_type_name, const Proxy_Function &t_func) + : Proxy_Function_Base(build_type_list(t_func->get_param_types()), t_func->get_arity() - 1) + , m_type_name(std::move(t_type_name)) + , m_func(t_func) { + assert((t_func->get_arity() > 0 || t_func->get_arity() < 0) + && "Programming error, Dynamic_Object_Function must have at least one parameter (this)"); + } + + static std::vector build_type_list(const std::vector &tl) { + auto begin = tl.begin(); + auto end = tl.end(); + + if (begin != end) { + ++begin; } - static std::vector build_type_list(const std::vector &tl) - { - auto begin = tl.begin(); - auto end = tl.end(); + return std::vector(begin, end); + } - if (begin != end) - { - ++begin; - } + bool operator==(const Proxy_Function_Base &f) const noexcept override { + const Dynamic_Object_Constructor *dc = dynamic_cast(&f); + return (dc != nullptr) && dc->m_type_name == m_type_name && (*dc->m_func) == (*m_func); + } - return std::vector(begin, end); - } + bool call_match(const chaiscript::Function_Params &vals, const Type_Conversions_State &t_conversions) const override { + std::vector new_vals{Boxed_Value(Dynamic_Object(m_type_name))}; + new_vals.insert(new_vals.end(), vals.begin(), vals.end()); - bool operator==(const Proxy_Function_Base &f) const noexcept override - { - const Dynamic_Object_Constructor *dc = dynamic_cast(&f); - return (dc != nullptr) && dc->m_type_name == m_type_name && (*dc->m_func) == (*m_func); - } + return m_func->call_match(chaiscript::Function_Params{new_vals}, t_conversions); + } - bool call_match(const chaiscript::Function_Params &vals, const Type_Conversions_State &t_conversions) const override - { - std::vector new_vals{Boxed_Value(Dynamic_Object(m_type_name))}; - new_vals.insert(new_vals.end(), vals.begin(), vals.end()); + protected: + Boxed_Value do_call(const chaiscript::Function_Params ¶ms, const Type_Conversions_State &t_conversions) const override { + auto bv = Boxed_Value(Dynamic_Object(m_type_name), true); + std::vector new_params{bv}; + new_params.insert(new_params.end(), params.begin(), params.end()); - return m_func->call_match(chaiscript::Function_Params{new_vals}, t_conversions); - } + (*m_func)(chaiscript::Function_Params{new_params}, t_conversions); - protected: - Boxed_Value do_call(const chaiscript::Function_Params ¶ms, const Type_Conversions_State &t_conversions) const override - { - auto bv = Boxed_Value(Dynamic_Object(m_type_name), true); - std::vector new_params{bv}; - new_params.insert(new_params.end(), params.begin(), params.end()); - - (*m_func)(chaiscript::Function_Params{new_params}, t_conversions); - - return bv; - } - - private: - const std::string m_type_name; - const Proxy_Function m_func; + return bv; + } + private: + const std::string m_type_name; + const Proxy_Function m_func; }; - } - } -} + } // namespace detail + } // namespace dispatch +} // namespace chaiscript #endif - diff --git a/include/chaiscript/dispatchkit/exception_specification.hpp b/include/chaiscript/dispatchkit/exception_specification.hpp index 9b107cc3..3ee32a83 100644 --- a/include/chaiscript/dispatchkit/exception_specification.hpp +++ b/include/chaiscript/dispatchkit/exception_specification.hpp @@ -7,7 +7,6 @@ // This is an open source non-commercial project. Dear PVS-Studio, please check it. // PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com - #ifndef CHAISCRIPT_EXCEPTION_SPECIFICATION_HPP_ #define CHAISCRIPT_EXCEPTION_SPECIFICATION_HPP_ @@ -17,39 +16,28 @@ #include "boxed_cast.hpp" namespace chaiscript { -class Boxed_Value; -namespace exception { -class bad_boxed_cast; -} // namespace exception -} // namespace chaiscript - -namespace chaiscript -{ - namespace detail - { - struct Exception_Handler_Base - { + namespace detail { + struct Exception_Handler_Base { virtual void handle(const Boxed_Value &bv, const Dispatch_Engine &t_engine) = 0; virtual ~Exception_Handler_Base() = default; - protected: - template - static void throw_type(const Boxed_Value &bv, const Dispatch_Engine &t_engine) - { - try { T t = t_engine.boxed_cast(bv); throw t; } catch (const chaiscript::exception::bad_boxed_cast &) {} + protected: + template + static void throw_type(const Boxed_Value &bv, const Dispatch_Engine &t_engine) { + try { + T t = t_engine.boxed_cast(bv); + throw t; + } catch (const chaiscript::exception::bad_boxed_cast &) { } + } }; - template - struct Exception_Handler_Impl : Exception_Handler_Base - { - void handle(const Boxed_Value &bv, const Dispatch_Engine &t_engine) override - { - (throw_type(bv, t_engine), ...); - } - }; - } + template + struct Exception_Handler_Impl : Exception_Handler_Base { + void handle(const Boxed_Value &bv, const Dispatch_Engine &t_engine) override { (throw_type(bv, t_engine), ...); } + }; + } // namespace detail /// \brief Used in the automatic unboxing of exceptions thrown during script evaluation /// @@ -61,7 +49,8 @@ namespace chaiscript /// chaiscript::ChaiScript chai; /// /// try { - /// chai.eval("throw(runtime_error(\"error\"))", chaiscript::exception_specification()); + /// chai.eval("throw(runtime_error(\"error\"))", chaiscript::exception_specification()); /// } catch (const double e) { /// } catch (int) { /// } catch (float) { @@ -86,7 +75,7 @@ namespace chaiscript /// /// Similarly, if you are using the ChaiScript::eval form that unboxes the return value, then chaiscript::exception::bad_boxed_cast /// should be handled as well. - /// + /// /// \code /// try { /// chai.eval("1.0", chaiscript::exception_specification()); @@ -105,13 +94,10 @@ namespace chaiscript /// \brief creates a chaiscript::Exception_Handler which handles one type of exception unboxing /// \sa \ref exceptions - template - Exception_Handler exception_specification() - { + template + Exception_Handler exception_specification() { return std::make_shared>(); } -} - +} // namespace chaiscript #endif - diff --git a/include/chaiscript/dispatchkit/function_call.hpp b/include/chaiscript/dispatchkit/function_call.hpp index 067158dd..f7589b33 100644 --- a/include/chaiscript/dispatchkit/function_call.hpp +++ b/include/chaiscript/dispatchkit/function_call.hpp @@ -7,7 +7,6 @@ // This is an open source non-commercial project. Dear PVS-Studio, please check it. // PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com - #ifndef CHAISCRIPT_FUNCTION_CALL_HPP_ #define CHAISCRIPT_FUNCTION_CALL_HPP_ @@ -20,25 +19,22 @@ #include "proxy_functions.hpp" namespace chaiscript { -class Boxed_Value; -class Type_Conversions_State; -namespace detail { -template struct Cast_Helper; -} // namespace detail -} // namespace chaiscript + class Boxed_Value; + class Type_Conversions_State; + namespace detail { + template + struct Cast_Helper; + } // namespace detail +} // namespace chaiscript -namespace chaiscript -{ - namespace dispatch - { - namespace detail - { - template - constexpr auto arity(Ret (*)(Param...)) noexcept - { +namespace chaiscript { + namespace dispatch { + namespace detail { + template + constexpr auto arity(Ret (*)(Param...)) noexcept { return sizeof...(Param); } - } + } // namespace detail /// Build a function caller that knows how to dispatch on a set of functions /// example: @@ -47,21 +43,19 @@ namespace chaiscript /// \returns A std::function object for dispatching /// \param[in] funcs the set of functions to dispatch on. template - std::function functor(const std::vector &funcs, const Type_Conversions_State *t_conversions) - { - 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(nullptr)); - }); + std::function functor(const std::vector &funcs, const Type_Conversions_State *t_conversions) { + 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(nullptr)); + }); - if (!has_arity_match) { - throw exception::bad_boxed_cast(user_type(), typeid(std::function)); - } - - FunctionType *p=nullptr; - return detail::build_function_caller_helper(p, funcs, t_conversions); + if (!has_arity_match) { + throw exception::bad_boxed_cast(user_type(), typeid(std::function)); } + FunctionType *p = nullptr; + return detail::build_function_caller_helper(p, funcs, t_conversions); + } + /// Build a function caller for a particular Proxy_Function object /// useful in the case that a function is being pass out from scripting back /// into code @@ -74,67 +68,55 @@ namespace chaiscript /// \returns A std::function object for dispatching /// \param[in] func A function to execute. template - std::function functor(Const_Proxy_Function func, const Type_Conversions_State *t_conversions) - { - return functor(std::vector({std::move(func)}), t_conversions); - } + std::function functor(Const_Proxy_Function func, const Type_Conversions_State *t_conversions) { + return functor(std::vector({std::move(func)}), t_conversions); + } /// Helper for automatically unboxing a Boxed_Value that contains a function object /// and creating a typesafe C++ function caller from it. template - std::function functor(const Boxed_Value &bv, const Type_Conversions_State *t_conversions) - { - return functor(boxed_cast(bv, t_conversions), t_conversions); - } - } + std::function functor(const Boxed_Value &bv, const Type_Conversions_State *t_conversions) { + return functor(boxed_cast(bv, t_conversions), t_conversions); + } + } // namespace dispatch - namespace detail{ + namespace detail { /// Cast helper to handle automatic casting to const std::function & template - struct Cast_Helper &> - { - static std::function cast(const Boxed_Value &ob, const Type_Conversions_State *t_conversions) - { - if (ob.get_type_info().bare_equal(user_type())) - { - return dispatch::functor(ob, t_conversions); - } else { - return Cast_Helper_Inner &>::cast(ob, t_conversions); - } + struct Cast_Helper &> { + static std::function cast(const Boxed_Value &ob, const Type_Conversions_State *t_conversions) { + if (ob.get_type_info().bare_equal(user_type())) { + return dispatch::functor(ob, t_conversions); + } else { + return Cast_Helper_Inner &>::cast(ob, t_conversions); } - }; + } + }; /// Cast helper to handle automatic casting to std::function template - struct Cast_Helper > - { - static std::function cast(const Boxed_Value &ob, const Type_Conversions_State *t_conversions) - { - if (ob.get_type_info().bare_equal(user_type())) - { - return dispatch::functor(ob, t_conversions); - } else { - return Cast_Helper_Inner >::cast(ob, t_conversions); - } + struct Cast_Helper> { + static std::function cast(const Boxed_Value &ob, const Type_Conversions_State *t_conversions) { + if (ob.get_type_info().bare_equal(user_type())) { + return dispatch::functor(ob, t_conversions); + } else { + return Cast_Helper_Inner>::cast(ob, t_conversions); } - }; + } + }; /// Cast helper to handle automatic casting to const std::function template - struct Cast_Helper > - { - static std::function cast(const Boxed_Value &ob, const Type_Conversions_State *t_conversions) - { - if (ob.get_type_info().bare_equal(user_type())) - { - return dispatch::functor(ob, t_conversions); - } else { - return Cast_Helper_Inner >::cast(ob, t_conversions); - } + struct Cast_Helper> { + static std::function cast(const Boxed_Value &ob, const Type_Conversions_State *t_conversions) { + if (ob.get_type_info().bare_equal(user_type())) { + return dispatch::functor(ob, t_conversions); + } else { + return Cast_Helper_Inner>::cast(ob, t_conversions); } - }; - } -} + } + }; + } // namespace detail +} // namespace chaiscript #endif - diff --git a/include/chaiscript/dispatchkit/function_call_detail.hpp b/include/chaiscript/dispatchkit/function_call_detail.hpp index 6c572675..f67a5a00 100644 --- a/include/chaiscript/dispatchkit/function_call_detail.hpp +++ b/include/chaiscript/dispatchkit/function_call_detail.hpp @@ -7,7 +7,6 @@ // This is an open source non-commercial project. Dear PVS-Studio, please check it. // PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com - #ifndef CHAISCRIPT_FUNCTION_CALL_DETAIL_HPP_ #define CHAISCRIPT_FUNCTION_CALL_DETAIL_HPP_ @@ -20,96 +19,79 @@ #include "boxed_cast.hpp" #include "boxed_number.hpp" #include "boxed_value.hpp" -#include "type_conversions.hpp" #include "proxy_functions.hpp" +#include "type_conversions.hpp" -namespace chaiscript -{ - namespace dispatch - { - namespace detail - { - /// used internally for unwrapping a function call's types - template - struct Build_Function_Caller_Helper - { - Build_Function_Caller_Helper(std::vector t_funcs, const Type_Conversions *t_conversions) - : m_funcs(std::move(t_funcs)), - m_conversions(t_conversions) - { - } - - Ret call(const chaiscript::Function_Params ¶ms, const Type_Conversions_State &t_state) - { - if constexpr (std::is_arithmetic_v && !std::is_same_v>, bool>) { - return Boxed_Number(dispatch::dispatch(m_funcs, params, t_state)).get_as(); - } else if constexpr (std::is_same_v) { - dispatch::dispatch(m_funcs, params, t_state); - } else { - return boxed_cast(dispatch::dispatch(m_funcs, params, t_state), &t_state); - } - } - - template - Ret operator()(P&& ... param) - { - std::array params{box

(std::forward

(param))...}; - - if (m_conversions) { - Type_Conversions_State state(*m_conversions, m_conversions->conversion_saves()); - return call(chaiscript::Function_Params{params}, state); - } else { - Type_Conversions conv; - Type_Conversions_State state(conv, conv.conversion_saves()); - return call(chaiscript::Function_Params{params}, state); - } - - } - - - template - static Boxed_Value box(Q &&q) { - if constexpr (std::is_same_v>) { - return std::forward(q); - } else if constexpr (std::is_reference_v

) { - return Boxed_Value(std::ref(std::forward(q))); - } else { - return Boxed_Value(std::forward(q)); - } - } - - - std::vector m_funcs; - const Type_Conversions *m_conversions; - }; - - - - /// \todo what happens if t_conversions is deleted out from under us?! - template - std::function build_function_caller_helper(Ret (Params...), const std::vector &funcs, const Type_Conversions_State *t_conversions) - { - /* - if (funcs.size() == 1) - { - std::shared_ptr> pfi = - std::dynamic_pointer_cast > - (funcs[0]); - - if (pfi) - { - return pfi->internal_function(); - } - // 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 - } -*/ - - return std::function(Build_Function_Caller_Helper(funcs, t_conversions?t_conversions->get():nullptr)); - } +namespace chaiscript::dispatch::detail { + /// used internally for unwrapping a function call's types + template + struct Build_Function_Caller_Helper { + Build_Function_Caller_Helper(std::vector t_funcs, const Type_Conversions *t_conversions) + : m_funcs(std::move(t_funcs)) + , m_conversions(t_conversions) { } + + Ret call(const chaiscript::Function_Params ¶ms, const Type_Conversions_State &t_state) { + if constexpr (std::is_arithmetic_v && !std::is_same_v>, bool>) { + return Boxed_Number(dispatch::dispatch(m_funcs, params, t_state)).get_as(); + } else if constexpr (std::is_same_v) { + dispatch::dispatch(m_funcs, params, t_state); + } else { + return boxed_cast(dispatch::dispatch(m_funcs, params, t_state), &t_state); + } + } + + template + Ret operator()(P &&...param) { + std::array params{box

(std::forward

(param))...}; + + if (m_conversions) { + Type_Conversions_State state(*m_conversions, m_conversions->conversion_saves()); + return call(chaiscript::Function_Params{params}, state); + } else { + Type_Conversions conv; + Type_Conversions_State state(conv, conv.conversion_saves()); + return call(chaiscript::Function_Params{params}, state); + } + } + + template + static Boxed_Value box(Q &&q) { + if constexpr (std::is_same_v>) { + return std::forward(q); + } else if constexpr (std::is_reference_v

) { + return Boxed_Value(std::ref(std::forward(q))); + } else { + return Boxed_Value(std::forward(q)); + } + } + + std::vector m_funcs; + const Type_Conversions *m_conversions; + }; + + /// \todo what happens if t_conversions is deleted out from under us?! + template + std::function + build_function_caller_helper(Ret(Params...), const std::vector &funcs, const Type_Conversions_State *t_conversions) { + /* + if (funcs.size() == 1) + { + std::shared_ptr> pfi = + std::dynamic_pointer_cast > + (funcs[0]); + + if (pfi) + { + return pfi->internal_function(); + } + // 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 + } + */ + + return std::function(Build_Function_Caller_Helper(funcs, t_conversions ? t_conversions->get() : nullptr)); } -} +} // namespace chaiscript::dispatch::detail #endif - diff --git a/include/chaiscript/dispatchkit/function_params.hpp b/include/chaiscript/dispatchkit/function_params.hpp index 588164a1..9a77c5ee 100644 --- a/include/chaiscript/dispatchkit/function_params.hpp +++ b/include/chaiscript/dispatchkit/function_params.hpp @@ -7,79 +7,61 @@ // This is an open source non-commercial project. Dear PVS-Studio, please check it. // PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com - #ifndef CHAISCRIPT_FUNCTION_PARAMS_HPP #define CHAISCRIPT_FUNCTION_PARAMS_HPP - #include "boxed_value.hpp" namespace chaiscript { + class Function_Params { + public: + constexpr Function_Params(const Boxed_Value *const t_begin, const Boxed_Value *const t_end) + : m_begin(t_begin) + , m_end(t_end) { + } - class Function_Params - { - public: - constexpr Function_Params(const Boxed_Value * const t_begin, const Boxed_Value * const t_end) - : m_begin(t_begin), m_end(t_end) - { - } + explicit Function_Params(const Boxed_Value &bv) + : m_begin(&bv) + , m_end(m_begin + 1) { + } - explicit Function_Params(const Boxed_Value &bv) - : m_begin(&bv), m_end(m_begin + 1) - { - } + explicit Function_Params(const std::vector &vec) + : m_begin(vec.empty() ? nullptr : &vec.front()) + , m_end(vec.empty() ? nullptr : &vec.front() + vec.size()) { + } - explicit Function_Params(const std::vector &vec) - : m_begin(vec.empty() ? nullptr : &vec.front()), m_end(vec.empty() ? nullptr : &vec.front() + vec.size()) - { - } + template + constexpr explicit Function_Params(const std::array &a) + : m_begin(&a.front()) + , m_end(&a.front() + Size) { + } - template - constexpr explicit Function_Params(const std::array &a) - : m_begin(&a.front()), m_end(&a.front() + Size) - { - } + [[nodiscard]] constexpr const Boxed_Value &operator[](const std::size_t t_i) const noexcept { return m_begin[t_i]; } - [[nodiscard]] constexpr const Boxed_Value &operator[](const std::size_t t_i) const noexcept { - return m_begin[t_i]; - } + [[nodiscard]] constexpr const Boxed_Value *begin() const noexcept { return m_begin; } - [[nodiscard]] constexpr const Boxed_Value *begin() const noexcept { - return m_begin; - } + [[nodiscard]] constexpr const Boxed_Value &front() const noexcept { return *m_begin; } - [[nodiscard]] constexpr const Boxed_Value &front() const noexcept { - return *m_begin; - } + [[nodiscard]] constexpr const Boxed_Value *end() const noexcept { return m_end; } - [[nodiscard]] constexpr const Boxed_Value *end() const noexcept { - return m_end; - } + [[nodiscard]] constexpr std::size_t size() const noexcept { return std::size_t(m_end - m_begin); } - [[nodiscard]] constexpr std::size_t size() const noexcept { - return std::size_t(m_end - m_begin); - } + [[nodiscard]] std::vector to_vector() const { return std::vector{m_begin, m_end}; } - [[nodiscard]] std::vector to_vector() const { - return std::vector{m_begin, m_end}; - } + [[nodiscard]] constexpr bool empty() const noexcept { return m_begin == m_end; } - [[nodiscard]] constexpr bool empty() const noexcept { - return m_begin == m_end; - } - - private: - const Boxed_Value *m_begin = nullptr; - const Boxed_Value *m_end = nullptr; + private: + const Boxed_Value *m_begin = nullptr; + const Boxed_Value *m_end = nullptr; }; // Constructor specialization for array of size 0 template<> constexpr Function_Params::Function_Params(const std::array & /* a */) - : m_begin(nullptr), m_end(nullptr) - { + : m_begin(nullptr) + , m_end(nullptr) { } -} +} // namespace chaiscript #endif diff --git a/include/chaiscript/dispatchkit/function_signature.hpp b/include/chaiscript/dispatchkit/function_signature.hpp index 6ee9996c..174f8576 100644 --- a/include/chaiscript/dispatchkit/function_signature.hpp +++ b/include/chaiscript/dispatchkit/function_signature.hpp @@ -4,142 +4,146 @@ #include namespace chaiscript::dispatch::detail { + template + struct Function_Params { + }; -template -struct Function_Params -{ -}; + template + struct Function_Signature { + using Param_Types = Params; + using Return_Type = Ret; + constexpr static const bool is_object = IsObject; + constexpr static const bool is_member_object = IsMemberObject; + constexpr static const bool is_noexcept = IsNoExcept; + template + constexpr Function_Signature(T &&) noexcept { + } + constexpr Function_Signature() noexcept = default; + }; -template -struct Function_Signature -{ - using Param_Types = Params; - using Return_Type = Ret; - constexpr static const bool is_object = IsObject; - constexpr static const bool is_member_object = IsMemberObject; - constexpr static const bool is_noexcept = IsNoExcept; - template - constexpr Function_Signature(T &&) noexcept {} - constexpr Function_Signature() noexcept = default; -}; + // Free functions -// Free functions + template + Function_Signature(Ret (*f)(Param...)) -> Function_Signature>; -template -Function_Signature(Ret (*f)(Param...))->Function_Signature>; + template + Function_Signature(Ret (*f)(Param...) noexcept) -> Function_Signature, true>; -template -Function_Signature(Ret (*f)(Param...) noexcept)->Function_Signature, true>; + // no reference specifier -// no reference specifier + template + Function_Signature(Ret (Class::*f)(Param...) volatile) -> Function_Signature, false, true>; -template -Function_Signature(Ret (Class::*f)(Param...) volatile)->Function_Signature, false, true>; + template + Function_Signature(Ret (Class::*f)(Param...) volatile noexcept) + -> Function_Signature, true, true>; -template -Function_Signature(Ret (Class::*f)(Param...) volatile noexcept)->Function_Signature, true, true>; + template + Function_Signature(Ret (Class::*f)(Param...) volatile const) + -> Function_Signature, false, true>; -template -Function_Signature(Ret (Class::*f)(Param...) volatile const)->Function_Signature, false, true>; + template + Function_Signature(Ret (Class::*f)(Param...) volatile const noexcept) + -> Function_Signature, true, true>; -template -Function_Signature(Ret (Class::*f)(Param...) volatile const noexcept)->Function_Signature, true, true>; + template + Function_Signature(Ret (Class::*f)(Param...)) -> Function_Signature, false, true>; -template -Function_Signature(Ret (Class::*f)(Param...))->Function_Signature, false, true>; + template + Function_Signature(Ret (Class::*f)(Param...) noexcept) -> Function_Signature, true, true>; -template -Function_Signature(Ret (Class::*f)(Param...) noexcept)->Function_Signature, true, true>; + template + Function_Signature(Ret (Class::*f)(Param...) const) -> Function_Signature, false, true>; -template -Function_Signature(Ret (Class::*f)(Param...) const)->Function_Signature, false, true>; + template + Function_Signature(Ret (Class::*f)(Param...) const noexcept) -> Function_Signature, true, true>; -template -Function_Signature(Ret (Class::*f)(Param...) const noexcept)->Function_Signature, true, true>; + // & reference specifier -// & reference specifier + template + Function_Signature(Ret (Class::*f)(Param...) volatile &) -> Function_Signature, false, true>; -template -Function_Signature(Ret (Class::*f)(Param...) volatile &)->Function_Signature, false, true>; + template + Function_Signature(Ret (Class::*f)(Param...) volatile &noexcept) + -> Function_Signature, true, true>; -template -Function_Signature(Ret (Class::*f)(Param...) volatile &noexcept)->Function_Signature, true, true>; + template + Function_Signature(Ret (Class::*f)(Param...) volatile const &) + -> Function_Signature, false, true>; -template -Function_Signature(Ret (Class::*f)(Param...) volatile const &)->Function_Signature, false, true>; + template + Function_Signature(Ret (Class::*f)(Param...) volatile const &noexcept) + -> Function_Signature, true, true>; -template -Function_Signature(Ret (Class::*f)(Param...) volatile const &noexcept)->Function_Signature, true, true>; + template + Function_Signature(Ret (Class::*f)(Param...) &) -> Function_Signature, false, true>; -template -Function_Signature(Ret (Class::*f)(Param...) &)->Function_Signature, false, true>; + template + Function_Signature(Ret (Class::*f)(Param...) &noexcept) -> Function_Signature, true, true>; -template -Function_Signature(Ret (Class::*f)(Param...) & noexcept)->Function_Signature, true, true>; + template + Function_Signature(Ret (Class::*f)(Param...) const &) -> Function_Signature, false, true>; -template -Function_Signature(Ret (Class::*f)(Param...) const &)->Function_Signature, false, true>; + template + Function_Signature(Ret (Class::*f)(Param...) const &noexcept) -> Function_Signature, true, true>; -template -Function_Signature(Ret (Class::*f)(Param...) const &noexcept)->Function_Signature, true, true>; + // && reference specifier -// && reference specifier + template + Function_Signature(Ret (Class::*f)(Param...) volatile &&) -> Function_Signature, false, true>; -template -Function_Signature(Ret (Class::*f)(Param...) volatile &&)->Function_Signature, false, true>; + template + Function_Signature(Ret (Class::*f)(Param...) volatile &&noexcept) + -> Function_Signature, true, true>; -template -Function_Signature(Ret (Class::*f)(Param...) volatile &&noexcept)->Function_Signature, true, true>; + template + Function_Signature(Ret (Class::*f)(Param...) volatile const &&) + -> Function_Signature, false, true>; -template -Function_Signature(Ret (Class::*f)(Param...) volatile const &&)->Function_Signature, false, true>; + template + Function_Signature(Ret (Class::*f)(Param...) volatile const &&noexcept) + -> Function_Signature, true, true>; -template -Function_Signature(Ret (Class::*f)(Param...) volatile const &&noexcept)->Function_Signature, true, true>; + template + Function_Signature(Ret (Class::*f)(Param...) &&) -> Function_Signature, false, true>; -template -Function_Signature(Ret (Class::*f)(Param...) &&)->Function_Signature, false, true>; + template + Function_Signature(Ret (Class::*f)(Param...) &&noexcept) -> Function_Signature, true, true>; -template -Function_Signature(Ret (Class::*f)(Param...) && noexcept)->Function_Signature, true, true>; + template + Function_Signature(Ret (Class::*f)(Param...) const &&) -> Function_Signature, false, true>; -template -Function_Signature(Ret (Class::*f)(Param...) const &&)->Function_Signature, false, true>; + template + Function_Signature(Ret (Class::*f)(Param...) const &&noexcept) + -> Function_Signature, true, true>; -template -Function_Signature(Ret (Class::*f)(Param...) const &&noexcept)->Function_Signature, true, true>; + template + Function_Signature(Ret Class::*f) -> Function_Signature, true, true, true>; -template -Function_Signature(Ret Class::*f)->Function_Signature, true, true, true>; + // primary template handles types that have no nested ::type member: + template> + struct has_call_operator : std::false_type { + }; -// primary template handles types that have no nested ::type member: -template> -struct has_call_operator : std::false_type -{ -}; + // specialization recognizes types that do have a nested ::type member: + template + struct has_call_operator> : std::true_type { + }; -// specialization recognizes types that do have a nested ::type member: -template -struct has_call_operator> : std::true_type -{ -}; - -template -auto function_signature(const Func &f) -{ - if constexpr (has_call_operator::value) { - return Function_Signature< - typename decltype(Function_Signature{ &std::decay_t::operator() })::Return_Type, - typename decltype(Function_Signature{ &std::decay_t::operator() })::Param_Types, - decltype(Function_Signature{ &std::decay_t::operator() })::is_noexcept, - false, - false, - true>{}; - } else { - return Function_Signature{ f }; + template + auto function_signature(const Func &f) { + if constexpr (has_call_operator::value) { + return Function_Signature::operator()})::Return_Type, + typename decltype(Function_Signature{&std::decay_t::operator()})::Param_Types, + decltype(Function_Signature{&std::decay_t::operator()})::is_noexcept, + false, + false, + true>{}; + } else { + return Function_Signature{f}; + } } -} -}// namespace chaiscript::dispatch::detail +} // namespace chaiscript::dispatch::detail #endif diff --git a/include/chaiscript/dispatchkit/handle_return.hpp b/include/chaiscript/dispatchkit/handle_return.hpp index b5609ef4..e0a3b132 100644 --- a/include/chaiscript/dispatchkit/handle_return.hpp +++ b/include/chaiscript/dispatchkit/handle_return.hpp @@ -7,7 +7,6 @@ // This is an open source non-commercial project. Dear PVS-Studio, please check it. // PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com - #ifndef CHAISCRIPT_HANDLE_RETURN_HPP_ #define CHAISCRIPT_HANDLE_RETURN_HPP_ @@ -19,254 +18,178 @@ #include "boxed_value.hpp" namespace chaiscript { -class Boxed_Number; -} // namespace chaiscript + class Boxed_Number; +} // namespace chaiscript -namespace chaiscript -{ - namespace dispatch - { - template class Proxy_Function_Callable_Impl; - template class Assignable_Proxy_Function_Impl; +namespace chaiscript { + namespace dispatch { + template + class Proxy_Function_Callable_Impl; + template + class Assignable_Proxy_Function_Impl; - namespace detail - { + namespace detail { /// Used internally for handling a return value from a Proxy_Function call template - struct Handle_Return - { - template>>> - static Boxed_Value handle(T r) - { - return Boxed_Value(std::move(r), true); - } + struct Handle_Return { + template>>> + static Boxed_Value handle(T r) { + return Boxed_Value(std::move(r), true); + } - template>)>> - static Boxed_Value handle(T &&r) - { - return Boxed_Value(std::make_shared(std::forward(r)), true); - } - }; + template>)>> + static Boxed_Value handle(T &&r) { + return Boxed_Value(std::make_shared(std::forward(r)), true); + } + }; template - struct Handle_Return &> - { - static Boxed_Value handle(const std::function &f) { - return Boxed_Value( - chaiscript::make_shared>>(f) - ); - } - }; + struct Handle_Return &> { + static Boxed_Value handle(const std::function &f) { + return Boxed_Value( + chaiscript::make_shared>>(f)); + } + }; template - struct Handle_Return> : Handle_Return &> - { - }; + struct Handle_Return> : Handle_Return &> { + }; template - struct Handle_Return>> - { - static Boxed_Value handle(const std::shared_ptr> &f) { - return Boxed_Value( - chaiscript::make_shared>(std::ref(*f),f) - ); - } - }; + struct Handle_Return>> { + static Boxed_Value handle(const std::shared_ptr> &f) { + return Boxed_Value( + chaiscript::make_shared>(std::ref(*f), f)); + } + }; template - struct Handle_Return> &> : Handle_Return>> - { - }; + struct Handle_Return> &> : Handle_Return>> { + }; template - struct Handle_Return>> : Handle_Return>> - { - }; + struct Handle_Return>> : Handle_Return>> { + }; template - struct Handle_Return &> - { - static Boxed_Value handle(std::function &f) { - return Boxed_Value( - chaiscript::make_shared>(std::ref(f), - std::shared_ptr>()) - ); - } + struct Handle_Return &> { + static Boxed_Value handle(std::function &f) { + return Boxed_Value(chaiscript::make_shared>( + std::ref(f), std::shared_ptr>())); + } - static Boxed_Value handle(const std::function &f) { - return Boxed_Value( - chaiscript::make_shared>>(f) - ); - } - }; + static Boxed_Value handle(const std::function &f) { + return Boxed_Value( + chaiscript::make_shared>>(f)); + } + }; template - struct Handle_Return - { - static Boxed_Value handle(Ret *p) - { - return Boxed_Value(p, true); - } - }; + struct Handle_Return { + static Boxed_Value handle(Ret *p) { return Boxed_Value(p, true); } + }; template - struct Handle_Return - { - static Boxed_Value handle(const Ret *p) - { - return Boxed_Value(p, true); - } - }; + struct Handle_Return { + static Boxed_Value handle(const Ret *p) { return Boxed_Value(p, true); } + }; template - struct Handle_Return - { - static Boxed_Value handle(Ret *p) - { - return Boxed_Value(p, true); - } - }; + struct Handle_Return { + static Boxed_Value handle(Ret *p) { return Boxed_Value(p, true); } + }; template - struct Handle_Return - { - static Boxed_Value handle(const Ret *p) - { - return Boxed_Value(p, true); - } - }; + struct Handle_Return { + static Boxed_Value handle(const Ret *p) { return Boxed_Value(p, true); } + }; template - struct Handle_Return &> - { - static Boxed_Value handle(const std::shared_ptr &r) - { - return Boxed_Value(r, true); - } - }; + struct Handle_Return &> { + static Boxed_Value handle(const std::shared_ptr &r) { return Boxed_Value(r, true); } + }; template - struct Handle_Return> : Handle_Return &> - { - }; + struct Handle_Return> : Handle_Return &> { + }; template - struct Handle_Return &> : Handle_Return &> - { - }; - + struct Handle_Return &> : Handle_Return &> { + }; template - struct Handle_Return> : Handle_Return &> - { - static Boxed_Value handle(std::unique_ptr &&r) - { - return Boxed_Value(std::move(r), true); - } - }; + struct Handle_Return> : Handle_Return &> { + static Boxed_Value handle(std::unique_ptr &&r) { return Boxed_Value(std::move(r), true); } + }; template - struct Handle_Return_Ref - { - template - static Boxed_Value handle(T &&r) - { - return Boxed_Value(std::cref(r), true); - } - }; + struct Handle_Return_Ref { + template + static Boxed_Value handle(T &&r) { + return Boxed_Value(std::cref(r), true); + } + }; template - struct Handle_Return_Ref - { - template - static Boxed_Value handle(T &&r) - { - return Boxed_Value(typename std::remove_reference::type{r}, true); - } - }; + struct Handle_Return_Ref { + template + static Boxed_Value handle(T &&r) { + return Boxed_Value(typename std::remove_reference::type{r}, true); + } + }; template - struct Handle_Return : Handle_Return_Ref::type>::value> - { - - }; - + struct Handle_Return : Handle_Return_Ref::type>::value> { + }; template - struct Handle_Return - { - static Boxed_Value handle(Ret r) - { - return Boxed_Value(std::move(r)); - } - }; + struct Handle_Return { + static Boxed_Value handle(Ret r) { return Boxed_Value(std::move(r)); } + }; template - struct Handle_Return - { - static Boxed_Value handle(Ret &r) - { - return Boxed_Value(std::ref(r)); - } - }; + struct Handle_Return { + static Boxed_Value handle(Ret &r) { return Boxed_Value(std::ref(r)); } + }; template<> - struct Handle_Return - { - static Boxed_Value handle(const Boxed_Value &r) noexcept - { - return r; - } - }; + struct Handle_Return { + static Boxed_Value handle(const Boxed_Value &r) noexcept { return r; } + }; template<> - struct Handle_Return : Handle_Return - { - }; + struct Handle_Return : Handle_Return { + }; template<> - struct Handle_Return : Handle_Return - { - }; + struct Handle_Return : Handle_Return { + }; template<> - struct Handle_Return : Handle_Return - { - }; + struct Handle_Return : Handle_Return { + }; /** - * 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<> - struct Handle_Return - { - static Boxed_Value handle(const Boxed_Number &r) noexcept - { - return r.bv; - } - }; + struct Handle_Return { + static Boxed_Value handle(const Boxed_Number &r) noexcept { return r.bv; } + }; template<> - struct Handle_Return : Handle_Return - { - }; - + struct Handle_Return : Handle_Return { + }; /** - * 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<> - struct Handle_Return - { - static Boxed_Value handle() - { - return void_var(); - } - }; - } - } -} + struct Handle_Return { + static Boxed_Value handle() { return void_var(); } + }; + } // namespace detail + } // namespace dispatch +} // namespace chaiscript #endif diff --git a/include/chaiscript/dispatchkit/operators.hpp b/include/chaiscript/dispatchkit/operators.hpp index ceb177ad..2545bfce 100644 --- a/include/chaiscript/dispatchkit/operators.hpp +++ b/include/chaiscript/dispatchkit/operators.hpp @@ -7,218 +7,178 @@ // This is an open source non-commercial project. Dear PVS-Studio, please check it. // PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com - #ifndef CHAISCRIPT_OPERATORS_HPP_ #define CHAISCRIPT_OPERATORS_HPP_ #include "../chaiscript_defines.hpp" +#include "../dispatchkit/dispatchkit.hpp" #include "register_function.hpp" -namespace chaiscript -{ - namespace bootstrap - { - namespace operators - { - template - void assign(Module& m) - { - m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs = rhs;}), "="); - } - - template - void assign_bitwise_and(Module& m) - { - m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs &= rhs;}), "&="); - } - - template - void assign_xor(Module& m) - { - m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs ^= rhs;}), "^="); - } - - template - void assign_bitwise_or(Module& m) - { - m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs |= rhs;}), "|="); - } - - template - void assign_difference(Module& m) - { - m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs -= rhs;}), "-="); - } - - template - void assign_left_shift(Module& m) - { - m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs <<= rhs;}), "<<="); - } - - template - void assign_product(Module& m) - { - m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs <<= rhs;}), "*="); - } - - template - void assign_quotient(Module& m) - { - m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs /= rhs;}), "/="); - } - - template - void assign_remainder(Module& m) - { - m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs %= rhs;}), "%="); - } - - template - void assign_right_shift(Module& m) - { - m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs >>= rhs;}), ">>="); - } - - template - void assign_sum(Module& m) - { - m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs += rhs;}), "+="); - } - - template - void prefix_decrement(Module& m) - { - m.add(chaiscript::fun([](T &lhs)->T&{return --lhs;}), "--"); - } - - template - void prefix_increment(Module& m) - { - m.add(chaiscript::fun([](T &lhs)->T&{return ++lhs;}), "++"); - } - - template - void equal(Module& m) - { - m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs==rhs;}), "=="); - } - - template - void greater_than(Module& m) - { - m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs>rhs;}), ">"); - } - - template - void greater_than_equal(Module& m) - { - m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs>=rhs;}), ">="); - } - - template - void less_than(Module& m) - { - m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs - void less_than_equal(Module& m) - { - m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs<=rhs;}), "<="); - } - - template - void logical_compliment(Module& m) - { - m.add(chaiscript::fun([](const T &lhs){return !lhs;}), "!"); - } - - template - void not_equal(Module& m) - { - m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs!=rhs;}), "!="); - } - - template - void addition(Module& m) - { - m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs+rhs;}), "+"); - } - - template - void unary_plus(Module& m) - { - m.add(chaiscript::fun([](const T &lhs){return +lhs;}), "+"); - } - - template - void subtraction(Module& m) - { - m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs-rhs;}), "-"); - } - - template - void unary_minus(Module& m) - { - m.add(chaiscript::fun([](const T &lhs){return -lhs;}), "-"); - } - - template - void bitwise_and(Module& m) - { - m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs&rhs;}), "&"); - } - - template - void bitwise_compliment(Module& m) - { - m.add(chaiscript::fun([](const T &lhs){return ~lhs;}), "~"); - } - - template - void bitwise_xor(Module& m) - { - m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs^rhs;}), "^"); - } - - template - void bitwise_or(Module& m) - { - m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs|rhs;}), "|"); - } - - template - void division(Module& m) - { - m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs/rhs;}), "/"); - } - - template - void left_shift(Module& m) - { - m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs< - void multiplication(Module& m) - { - m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs*rhs;}), "*"); - } - - template - void remainder(Module& m) - { - m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs%rhs;}), "%"); - } - - template - void right_shift(Module& m) - { - m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs>>rhs;}), ">>"); - } - } +namespace chaiscript::bootstrap::operators { + template + void assign(Module &m) { + m.add(chaiscript::fun([](T &lhs, const T &rhs) -> T & { return lhs = rhs; }), "="); } -} + + template + void assign_bitwise_and(Module &m) { + m.add(chaiscript::fun([](T &lhs, const T &rhs) -> T & { return lhs &= rhs; }), "&="); + } + + template + void assign_xor(Module &m) { + m.add(chaiscript::fun([](T &lhs, const T &rhs) -> T & { return lhs ^= rhs; }), "^="); + } + + template + void assign_bitwise_or(Module &m) { + m.add(chaiscript::fun([](T &lhs, const T &rhs) -> T & { return lhs |= rhs; }), "|="); + } + + template + void assign_difference(Module &m) { + m.add(chaiscript::fun([](T &lhs, const T &rhs) -> T & { return lhs -= rhs; }), "-="); + } + + template + void assign_left_shift(Module &m) { + m.add(chaiscript::fun([](T &lhs, const T &rhs) -> T & { return lhs <<= rhs; }), "<<="); + } + + template + void assign_product(Module &m) { + m.add(chaiscript::fun([](T &lhs, const T &rhs) -> T & { return lhs <<= rhs; }), "*="); + } + + template + void assign_quotient(Module &m) { + m.add(chaiscript::fun([](T &lhs, const T &rhs) -> T & { return lhs /= rhs; }), "/="); + } + + template + void assign_remainder(Module &m) { + m.add(chaiscript::fun([](T &lhs, const T &rhs) -> T & { return lhs %= rhs; }), "%="); + } + + template + void assign_right_shift(Module &m) { + m.add(chaiscript::fun([](T &lhs, const T &rhs) -> T & { return lhs >>= rhs; }), ">>="); + } + + template + void assign_sum(Module &m) { + m.add(chaiscript::fun([](T &lhs, const T &rhs) -> T & { return lhs += rhs; }), "+="); + } + + template + void prefix_decrement(Module &m) { + m.add(chaiscript::fun([](T &lhs) -> T & { return --lhs; }), "--"); + } + + template + void prefix_increment(Module &m) { + m.add(chaiscript::fun([](T &lhs) -> T & { return ++lhs; }), "++"); + } + + template + void equal(Module &m) { + m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs == rhs; }), "=="); + } + + template + void greater_than(Module &m) { + m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs > rhs; }), ">"); + } + + template + void greater_than_equal(Module &m) { + m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs >= rhs; }), ">="); + } + + template + void less_than(Module &m) { + m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs < rhs; }), "<"); + } + + template + void less_than_equal(Module &m) { + m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs <= rhs; }), "<="); + } + + template + void logical_compliment(Module &m) { + m.add(chaiscript::fun([](const T &lhs) { return !lhs; }), "!"); + } + + template + void not_equal(Module &m) { + m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs != rhs; }), "!="); + } + + template + void addition(Module &m) { + m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs + rhs; }), "+"); + } + + template + void unary_plus(Module &m) { + m.add(chaiscript::fun([](const T &lhs) { return +lhs; }), "+"); + } + + template + void subtraction(Module &m) { + m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs - rhs; }), "-"); + } + + template + void unary_minus(Module &m) { + m.add(chaiscript::fun([](const T &lhs) { return -lhs; }), "-"); + } + + template + void bitwise_and(Module &m) { + m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs & rhs; }), "&"); + } + + template + void bitwise_compliment(Module &m) { + m.add(chaiscript::fun([](const T &lhs) { return ~lhs; }), "~"); + } + + template + void bitwise_xor(Module &m) { + m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs ^ rhs; }), "^"); + } + + template + void bitwise_or(Module &m) { + m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs | rhs; }), "|"); + } + + template + void division(Module &m) { + m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs / rhs; }), "/"); + } + + template + void left_shift(Module &m) { + m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs << rhs; }), "<<"); + } + + template + void multiplication(Module &m) { + m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs * rhs; }), "*"); + } + + template + void remainder(Module &m) { + m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs % rhs; }), "%"); + } + + template + void right_shift(Module &m) { + m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs >> rhs; }), ">>"); + } +} // namespace chaiscript::bootstrap::operators #endif diff --git a/include/chaiscript/dispatchkit/proxy_constructors.hpp b/include/chaiscript/dispatchkit/proxy_constructors.hpp index e2e9a4ba..b7e0d44a 100644 --- a/include/chaiscript/dispatchkit/proxy_constructors.hpp +++ b/include/chaiscript/dispatchkit/proxy_constructors.hpp @@ -7,45 +7,35 @@ // This is an open source non-commercial project. Dear PVS-Studio, please check it. // PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com - #ifndef CHAISCRIPT_PROXY_CONSTRUCTORS_HPP_ #define CHAISCRIPT_PROXY_CONSTRUCTORS_HPP_ #include "proxy_functions.hpp" -namespace chaiscript -{ - namespace dispatch - { - namespace detail - { - template - Proxy_Function build_constructor_(Class (*)(Params...)) - { - if constexpr (!std::is_copy_constructible_v) { - auto call = [](auto && ... param) { - return std::make_shared(std::forward(param)...); - }; +namespace chaiscript::dispatch::detail { + template + Proxy_Function build_constructor_(Class (*)(Params...)) { + if constexpr (!std::is_copy_constructible_v) { + auto call = [](auto &&...param) { return std::make_shared(std::forward(param)...); }; - return Proxy_Function( - chaiscript::make_shared (Params...), decltype(call)>>(call)); - } else if constexpr (true) { - auto call = [](auto && ... param){ - return Class(std::forward(param)...); - }; + return Proxy_Function( + chaiscript::make_shared(Params...), decltype(call)>>(call)); + } else if constexpr (true) { + auto call = [](auto &&...param) { return Class(std::forward(param)...); }; - return Proxy_Function( - chaiscript::make_shared>(call)); - } - } + return Proxy_Function( + chaiscript::make_shared>( + call)); } } +} // namespace chaiscript::dispatch::detail - +namespace 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, ...) - /// + /// /// Example: /// \code /// chaiscript::ChaiScript chai; @@ -54,13 +44,10 @@ namespace chaiscript /// chai.add(constructor(), "MyClass"); /// \endcode template - Proxy_Function constructor() - { - T *f = nullptr; - return (dispatch::detail::build_constructor_(f)); - } - -} + Proxy_Function constructor() { + T *f = nullptr; + return (dispatch::detail::build_constructor_(f)); + } +} // namespace chaiscript #endif - diff --git a/include/chaiscript/dispatchkit/proxy_functions.hpp b/include/chaiscript/dispatchkit/proxy_functions.hpp index 00b81f43..a481e2c6 100644 --- a/include/chaiscript/dispatchkit/proxy_functions.hpp +++ b/include/chaiscript/dispatchkit/proxy_functions.hpp @@ -7,101 +7,86 @@ // This is an open source non-commercial project. Dear PVS-Studio, please check it. // PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com - #ifndef CHAISCRIPT_PROXY_FUNCTIONS_HPP_ #define CHAISCRIPT_PROXY_FUNCTIONS_HPP_ - #include #include +#include #include #include #include #include #include -#include #include "../chaiscript_defines.hpp" #include "boxed_cast.hpp" #include "boxed_value.hpp" -#include "proxy_functions_detail.hpp" -#include "type_info.hpp" #include "dynamic_object.hpp" #include "function_params.hpp" +#include "proxy_functions_detail.hpp" +#include "type_info.hpp" namespace chaiscript { -class Type_Conversions; -namespace exception { -class bad_boxed_cast; -struct arity_error; -} // namespace exception -} // namespace chaiscript + class Type_Conversions; + namespace exception { + class bad_boxed_cast; + struct arity_error; + } // namespace exception +} // namespace chaiscript -namespace chaiscript -{ +namespace chaiscript { class Boxed_Number; struct AST_Node; using AST_NodePtr = std::unique_ptr; - namespace dispatch - { + namespace dispatch { template - std::function functor(std::shared_ptr func, const Type_Conversions_State *t_conversions); + std::function functor(std::shared_ptr func, const Type_Conversions_State *t_conversions); - class Param_Types - { - public: - Param_Types() - : m_has_types(false) - {} + class Param_Types { + public: + Param_Types() + : m_has_types(false) { + } - explicit Param_Types(std::vector> t_types) - : m_types(std::move(t_types)), - m_has_types(false) - { - update_has_types(); - } + explicit Param_Types(std::vector> t_types) + : m_types(std::move(t_types)) + , m_has_types(false) { + update_has_types(); + } - void push_front(std::string t_name, Type_Info t_ti) - { - m_types.emplace(m_types.begin(), std::move(t_name), t_ti); - update_has_types(); - } + void push_front(std::string t_name, Type_Info t_ti) { + m_types.emplace(m_types.begin(), std::move(t_name), t_ti); + update_has_types(); + } - bool operator==(const Param_Types &t_rhs) const noexcept - { - return m_types == t_rhs.m_types; - } + bool operator==(const Param_Types &t_rhs) const noexcept { return m_types == t_rhs.m_types; } - std::vector convert(Function_Params t_params, const Type_Conversions_State &t_conversions) const - { - auto vals = t_params.to_vector(); - const auto dynamic_object_type_info = user_type(); - for (size_t i = 0; i < vals.size(); ++i) - { - const auto &name = m_types[i].first; - if (!name.empty()) { - const auto &bv = vals[i]; + std::vector convert(Function_Params t_params, const Type_Conversions_State &t_conversions) const { + auto vals = t_params.to_vector(); + const auto dynamic_object_type_info = user_type(); + for (size_t i = 0; i < vals.size(); ++i) { + const auto &name = m_types[i].first; + if (!name.empty()) { + const auto &bv = vals[i]; - if (!bv.get_type_info().bare_equal(dynamic_object_type_info)) - { - const auto &ti = m_types[i].second; - if (!ti.is_undef()) - { - if (!bv.get_type_info().bare_equal(ti)) { - if (t_conversions->converts(ti, bv.get_type_info())) { + if (!bv.get_type_info().bare_equal(dynamic_object_type_info)) { + const auto &ti = m_types[i].second; + if (!ti.is_undef()) { + if (!bv.get_type_info().bare_equal(ti)) { + if (t_conversions->converts(ti, bv.get_type_info())) { + try { + // 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 + vals[i] = t_conversions->boxed_type_conversion(m_types[i].second, t_conversions.saves(), vals[i]); + } catch (...) { try { - // 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 - vals[i] = t_conversions->boxed_type_conversion(m_types[i].second, t_conversions.saves(), vals[i]); - } catch (...) { - try { - // try going the other way - vals[i] = t_conversions->boxed_type_down_conversion(m_types[i].second, t_conversions.saves(), vals[i]); - } catch (const chaiscript::detail::exception::bad_any_cast &) { - throw exception::bad_boxed_cast(bv.get_type_info(), *m_types[i].second.bare_type_info()); - } + // try going the other way + vals[i] = t_conversions->boxed_type_down_conversion(m_types[i].second, t_conversions.saves(), vals[i]); + } catch (const chaiscript::detail::exception::bad_any_cast &) { + throw exception::bad_boxed_cast(bv.get_type_info(), *m_types[i].second.bare_type_info()); } } } @@ -109,215 +94,184 @@ namespace chaiscript } } } - - return vals; } - // first result: is a match - // second result: needs conversions - std::pair match(const Function_Params &vals, const Type_Conversions_State &t_conversions) const noexcept - { - const auto dynamic_object_type_info = user_type(); - bool needs_conversion = false; + return vals; + } - if (!m_has_types) { return std::make_pair(true, needs_conversion); } - if (vals.size() != m_types.size()) { return std::make_pair(false, needs_conversion); } + // first result: is a match + // second result: needs conversions + std::pair match(const Function_Params &vals, const Type_Conversions_State &t_conversions) const noexcept { + const auto dynamic_object_type_info = user_type(); + bool needs_conversion = false; - for (size_t i = 0; i < vals.size(); ++i) - { - const auto &name = m_types[i].first; - if (!name.empty()) { - const auto &bv = vals[i]; + if (!m_has_types) { + return std::make_pair(true, needs_conversion); + } + if (vals.size() != m_types.size()) { + return std::make_pair(false, needs_conversion); + } - if (bv.get_type_info().bare_equal(dynamic_object_type_info)) - { - try { - const Dynamic_Object &d = boxed_cast(bv, &t_conversions); - if (!(name == "Dynamic_Object" || d.get_type_name() == name)) { - return std::make_pair(false, false); - } - } catch (const std::bad_cast &) { + for (size_t i = 0; i < vals.size(); ++i) { + const auto &name = m_types[i].first; + if (!name.empty()) { + const auto &bv = vals[i]; + + if (bv.get_type_info().bare_equal(dynamic_object_type_info)) { + try { + const Dynamic_Object &d = boxed_cast(bv, &t_conversions); + if (!(name == "Dynamic_Object" || d.get_type_name() == name)) { return std::make_pair(false, false); } + } catch (const std::bad_cast &) { + return std::make_pair(false, false); + } + } else { + const auto &ti = m_types[i].second; + if (!ti.is_undef()) { + if (!bv.get_type_info().bare_equal(ti)) { + if (!t_conversions->converts(ti, bv.get_type_info())) { + return std::make_pair(false, false); + } else { + needs_conversion = true; + } + } } else { - const auto &ti = m_types[i].second; - if (!ti.is_undef()) - { - if (!bv.get_type_info().bare_equal(ti)) { - if (!t_conversions->converts(ti, bv.get_type_info())) { - return std::make_pair(false, false); - } else { - needs_conversion = true; - } - } - } else { - return std::make_pair(false, false); - } + return std::make_pair(false, false); } } } - - return std::make_pair(true, needs_conversion); } - const std::vector> &types() const noexcept - { - return m_types; - } + return std::make_pair(true, needs_conversion); + } - private: - void update_has_types() - { - for (const auto &type : m_types) - { - if (!type.first.empty()) - { - m_has_types = true; - return; - } + const std::vector> &types() const noexcept { return m_types; } + + private: + void update_has_types() { + for (const auto &type : m_types) { + if (!type.first.empty()) { + m_has_types = true; + return; } - - m_has_types = false; } - std::vector> m_types; - bool m_has_types; + m_has_types = false; + } + std::vector> m_types; + bool m_has_types; }; /** - * Pure virtual base class for all Proxy_Function implementations - * Proxy_Functions are a type erasure of type safe C++ - * function calls. At runtime parameter types are expected to be - * tested against passed in types. - * Dispatch_Engine only knows how to work with Proxy_Function, no other - * function classes. - */ - class Proxy_Function_Base - { - public: - virtual ~Proxy_Function_Base() = default; + * Pure virtual base class for all Proxy_Function implementations + * Proxy_Functions are a type erasure of type safe C++ + * function calls. At runtime parameter types are expected to be + * tested against passed in types. + * Dispatch_Engine only knows how to work with Proxy_Function, no other + * function classes. + */ + class Proxy_Function_Base { + public: + virtual ~Proxy_Function_Base() = default; - Boxed_Value operator()(const Function_Params ¶ms, const chaiscript::Type_Conversions_State &t_conversions) const - { - if (m_arity < 0 || size_t(m_arity) == params.size()) { - return do_call(params, t_conversions); - } else { - throw exception::arity_error(static_cast(params.size()), m_arity); - } + Boxed_Value operator()(const Function_Params ¶ms, const chaiscript::Type_Conversions_State &t_conversions) const { + if (m_arity < 0 || size_t(m_arity) == params.size()) { + return do_call(params, t_conversions); + } else { + throw exception::arity_error(static_cast(params.size()), m_arity); } + } - /// Returns a vector containing all of the types of the parameters the function returns/takes - /// if the function is variadic or takes no arguments (arity of 0 or -1), the returned - /// value contains exactly 1 Type_Info object: the return type - /// \returns the types of all parameters. - const std::vector &get_param_types() const noexcept { return m_types; } + /// Returns a vector containing all of the types of the parameters the function returns/takes + /// if the function is variadic or takes no arguments (arity of 0 or -1), the returned + /// value contains exactly 1 Type_Info object: the return type + /// \returns the types of all parameters. + const std::vector &get_param_types() const noexcept { return m_types; } - virtual bool operator==(const Proxy_Function_Base &) const noexcept = 0; - virtual bool call_match(const Function_Params &vals, const Type_Conversions_State &t_conversions) const = 0; + virtual bool operator==(const Proxy_Function_Base &) const noexcept = 0; + virtual bool call_match(const Function_Params &vals, const Type_Conversions_State &t_conversions) const = 0; - virtual bool is_attribute_function() const noexcept { return false; } + virtual bool is_attribute_function() const noexcept { return false; } - bool has_arithmetic_param() const noexcept - { - return m_has_arithmetic_param; - } + bool has_arithmetic_param() const noexcept { return m_has_arithmetic_param; } - virtual std::vector > get_contained_functions() const - { - return std::vector >(); - } + virtual std::vector> get_contained_functions() const { + return std::vector>(); + } - //! Return true if the function is a possible match - //! to the passed in values - bool filter(const Function_Params &vals, const Type_Conversions_State &t_conversions) const noexcept - { - assert(m_arity == -1 || (m_arity > 0 && static_cast(vals.size()) == m_arity)); + //! Return true if the function is a possible match + //! to the passed in values + bool filter(const Function_Params &vals, const Type_Conversions_State &t_conversions) const noexcept { + assert(m_arity == -1 || (m_arity > 0 && static_cast(vals.size()) == m_arity)); - if (m_arity < 0) - { - return true; - } else if (m_arity > 1) { - return compare_type_to_param(m_types[1], vals[0], t_conversions) && compare_type_to_param(m_types[2], vals[1], t_conversions); - } else { - return compare_type_to_param(m_types[1], vals[0], t_conversions); - } - } - - /// \returns the number of arguments the function takes or -1 if it is variadic - int get_arity() const noexcept - { - return m_arity; - } - - static bool compare_type_to_param(const Type_Info &ti, const Boxed_Value &bv, const Type_Conversions_State &t_conversions) noexcept - { - const auto boxed_value_ti = user_type(); - const auto boxed_number_ti = user_type(); - const auto function_ti = user_type>(); - - if (ti.is_undef() - || ti.bare_equal(boxed_value_ti) - || (!bv.get_type_info().is_undef() - && ( (ti.bare_equal(boxed_number_ti) && bv.get_type_info().is_arithmetic()) - || ti.bare_equal(bv.get_type_info()) - || bv.get_type_info().bare_equal(function_ti) - || t_conversions->converts(ti, bv.get_type_info()) - ) - ) - ) - { - return true; - } else { - return false; - } - } - - virtual bool compare_first_type(const Boxed_Value &bv, const Type_Conversions_State &t_conversions) const noexcept - { - /// TODO is m_types guaranteed to be at least 2?? - return compare_type_to_param(m_types[1], bv, t_conversions); - } - - protected: - virtual Boxed_Value do_call(const Function_Params ¶ms, const Type_Conversions_State &t_conversions) const = 0; - - Proxy_Function_Base(std::vector t_types, int t_arity) - : m_types(std::move(t_types)), m_arity(t_arity), m_has_arithmetic_param(false) - { - for (size_t i = 1; i < m_types.size(); ++i) - { - if (m_types[i].is_arithmetic()) - { - m_has_arithmetic_param = true; - return; - } - } - - } - - - static bool compare_types(const std::vector &tis, const Function_Params &bvs, - const Type_Conversions_State &t_conversions) noexcept - { - if (tis.size() - 1 != bvs.size()) - { - return false; - } else { - const size_t size = bvs.size(); - for (size_t i = 0; i < size; ++i) - { - if (!compare_type_to_param(tis[i + 1], bvs[i], t_conversions)) { return false; } - } - } + if (m_arity < 0) { return true; + } else if (m_arity > 1) { + return compare_type_to_param(m_types[1], vals[0], t_conversions) && compare_type_to_param(m_types[2], vals[1], t_conversions); + } else { + return compare_type_to_param(m_types[1], vals[0], t_conversions); } + } - std::vector m_types; - int m_arity; - bool m_has_arithmetic_param; + /// \returns the number of arguments the function takes or -1 if it is variadic + int get_arity() const noexcept { return m_arity; } + + static bool compare_type_to_param(const Type_Info &ti, const Boxed_Value &bv, const Type_Conversions_State &t_conversions) noexcept { + const auto boxed_value_ti = user_type(); + const auto boxed_number_ti = user_type(); + const auto function_ti = user_type>(); + + if (ti.is_undef() || ti.bare_equal(boxed_value_ti) + || (!bv.get_type_info().is_undef() + && ((ti.bare_equal(boxed_number_ti) && bv.get_type_info().is_arithmetic()) || ti.bare_equal(bv.get_type_info()) + || bv.get_type_info().bare_equal(function_ti) || t_conversions->converts(ti, bv.get_type_info())))) { + return true; + } else { + return false; + } + } + + virtual bool compare_first_type(const Boxed_Value &bv, const Type_Conversions_State &t_conversions) const noexcept { + /// TODO is m_types guaranteed to be at least 2?? + return compare_type_to_param(m_types[1], bv, t_conversions); + } + + protected: + virtual Boxed_Value do_call(const Function_Params ¶ms, const Type_Conversions_State &t_conversions) const = 0; + + Proxy_Function_Base(std::vector t_types, int t_arity) + : m_types(std::move(t_types)) + , m_arity(t_arity) + , m_has_arithmetic_param(false) { + for (size_t i = 1; i < m_types.size(); ++i) { + if (m_types[i].is_arithmetic()) { + m_has_arithmetic_param = true; + return; + } + } + } + + static bool compare_types(const std::vector &tis, const Function_Params &bvs, const Type_Conversions_State &t_conversions) noexcept { + if (tis.size() - 1 != bvs.size()) { + return false; + } else { + const size_t size = bvs.size(); + for (size_t i = 0; i < size; ++i) { + if (!compare_type_to_param(tis[i + 1], bvs[i], t_conversions)) { + return false; + } + } + } + return true; + } + + std::vector m_types; + int m_arity; + bool m_has_arithmetic_param; }; - } + } // namespace dispatch /// \brief Common typedef used for passing of any registered function in ChaiScript using Proxy_Function = std::shared_ptr; @@ -326,668 +280,542 @@ namespace chaiscript /// are handled internally. using Const_Proxy_Function = std::shared_ptr; - namespace exception - { + namespace exception { /// \brief Exception thrown if a function's guard fails - class guard_error : public std::runtime_error - { - public: - guard_error() noexcept - : std::runtime_error("Guard evaluation failed") - { } + class guard_error : public std::runtime_error { + public: + guard_error() noexcept + : std::runtime_error("Guard evaluation failed") { + } - guard_error(const guard_error &) = default; + guard_error(const guard_error &) = default; - ~guard_error() noexcept override = default; + ~guard_error() noexcept override = default; }; - } + } // namespace exception - namespace dispatch - { + namespace dispatch { /// A Proxy_Function implementation that is not type safe, the called function /// is expecting a vector that it works with how it chooses. - class Dynamic_Proxy_Function : public Proxy_Function_Base - { - public: - Dynamic_Proxy_Function( - const int t_arity, - std::shared_ptr t_parsenode, - Param_Types t_param_types = Param_Types(), - Proxy_Function t_guard = Proxy_Function()) - : Proxy_Function_Base(build_param_type_list(t_param_types), t_arity), - m_param_types(std::move(t_param_types)), - m_guard(std::move(t_guard)), m_parsenode(std::move(t_parsenode)) - { - // assert(t_parsenode); - } + class Dynamic_Proxy_Function : public Proxy_Function_Base { + public: + Dynamic_Proxy_Function(const int t_arity, + std::shared_ptr t_parsenode, + Param_Types t_param_types = Param_Types(), + Proxy_Function t_guard = Proxy_Function()) + : Proxy_Function_Base(build_param_type_list(t_param_types), t_arity) + , m_param_types(std::move(t_param_types)) + , m_guard(std::move(t_guard)) + , m_parsenode(std::move(t_parsenode)) { + // assert(t_parsenode); + } + bool operator==(const Proxy_Function_Base &rhs) const noexcept override { + const Dynamic_Proxy_Function *prhs = dynamic_cast(&rhs); - bool operator==(const Proxy_Function_Base &rhs) const noexcept override - { - const Dynamic_Proxy_Function *prhs = dynamic_cast(&rhs); - - return this == &rhs - || ((prhs != nullptr) - && this->m_arity == prhs->m_arity - && !this->m_guard && !prhs->m_guard + return this == &rhs + || ((prhs != nullptr) && this->m_arity == prhs->m_arity && !this->m_guard && !prhs->m_guard && this->m_param_types == prhs->m_param_types); - } + } - bool call_match(const Function_Params &vals, const Type_Conversions_State &t_conversions) const override - { - return call_match_internal(vals, t_conversions).first; - } + bool call_match(const Function_Params &vals, const Type_Conversions_State &t_conversions) const override { + return call_match_internal(vals, t_conversions).first; + } - bool has_guard() const noexcept - { - return bool(m_guard); - } + bool has_guard() const noexcept { return bool(m_guard); } - Proxy_Function get_guard() const noexcept - { - return m_guard; - } + Proxy_Function get_guard() const noexcept { return m_guard; } - bool has_parse_tree() const noexcept { - return static_cast(m_parsenode); - } + bool has_parse_tree() const noexcept { return static_cast(m_parsenode); } - const AST_Node &get_parse_tree() const - { - if (m_parsenode) { - return *m_parsenode; + const AST_Node &get_parse_tree() const { + if (m_parsenode) { + return *m_parsenode; + } else { + throw std::runtime_error("Dynamic_Proxy_Function does not have parse_tree"); + } + } + + protected: + bool test_guard(const Function_Params ¶ms, const Type_Conversions_State &t_conversions) const { + if (m_guard) { + try { + return boxed_cast((*m_guard)(params, t_conversions)); + } catch (const exception::arity_error &) { + return false; + } catch (const exception::bad_boxed_cast &) { + return false; + } + } else { + return true; + } + } + + // first result: is a match + // second result: needs conversions + std::pair call_match_internal(const Function_Params &vals, const Type_Conversions_State &t_conversions) const { + const auto comparison_result = [&]() { + if (m_arity < 0) { + return std::make_pair(true, false); + } else if (vals.size() == size_t(m_arity)) { + return m_param_types.match(vals, t_conversions); } else { - throw std::runtime_error("Dynamic_Proxy_Function does not have parse_tree"); + return std::make_pair(false, false); } - } + }(); + return std::make_pair(comparison_result.first && test_guard(vals, t_conversions), comparison_result.second); + } - protected: - bool test_guard(const Function_Params ¶ms, const Type_Conversions_State &t_conversions) const - { - if (m_guard) - { - try { - return boxed_cast((*m_guard)(params, t_conversions)); - } catch (const exception::arity_error &) { - return false; - } catch (const exception::bad_boxed_cast &) { - return false; - } + private: + static std::vector build_param_type_list(const Param_Types &t_types) { + // For the return type + std::vector types{chaiscript::detail::Get_Type_Info::get()}; + + for (const auto &t : t_types.types()) { + if (t.second.is_undef()) { + types.push_back(chaiscript::detail::Get_Type_Info::get()); } else { - return true; + types.push_back(t.second); } } - // first result: is a match - // second result: needs conversions - std::pair call_match_internal(const Function_Params &vals, const Type_Conversions_State &t_conversions) const - { - const auto comparison_result = [&](){ - if (m_arity < 0) { - return std::make_pair(true, false); - } else if (vals.size() == size_t(m_arity)) { - return m_param_types.match(vals, t_conversions); - } else { - return std::make_pair(false, false); - } - }(); + return types; + } - return std::make_pair( - comparison_result.first && test_guard(vals, t_conversions), - comparison_result.second - ); - } + protected: + Param_Types m_param_types; - private: - static std::vector build_param_type_list(const Param_Types &t_types) - { - // For the return type - std::vector types{chaiscript::detail::Get_Type_Info::get()}; - - for (const auto &t : t_types.types()) - { - if (t.second.is_undef()) { - types.push_back(chaiscript::detail::Get_Type_Info::get()); - } else { - types.push_back(t.second); - } - } - - return types; - } - - protected: - Param_Types m_param_types; - - private: - Proxy_Function m_guard; - std::shared_ptr m_parsenode; + private: + Proxy_Function m_guard; + std::shared_ptr m_parsenode; }; - - template - class Dynamic_Proxy_Function_Impl final : public Dynamic_Proxy_Function - { - public: - Dynamic_Proxy_Function_Impl( - Callable t_f, - int t_arity=-1, - std::shared_ptr t_parsenode = AST_NodePtr(), - Param_Types t_param_types = Param_Types(), - Proxy_Function t_guard = Proxy_Function()) - : Dynamic_Proxy_Function( - t_arity, - std::move(t_parsenode), - std::move(t_param_types), - std::move(t_guard) - ), - m_f(std::move(t_f)) - { - } + class Dynamic_Proxy_Function_Impl final : public Dynamic_Proxy_Function { + public: + Dynamic_Proxy_Function_Impl(Callable t_f, + int t_arity = -1, + std::shared_ptr t_parsenode = AST_NodePtr(), + Param_Types t_param_types = Param_Types(), + Proxy_Function t_guard = Proxy_Function()) + : Dynamic_Proxy_Function(t_arity, std::move(t_parsenode), std::move(t_param_types), std::move(t_guard)) + , m_f(std::move(t_f)) { + } - - protected: - Boxed_Value do_call(const Function_Params ¶ms, const Type_Conversions_State &t_conversions) const override - { - const auto [is_a_match, needs_conversions] = call_match_internal(params, t_conversions); - if (is_a_match) - { - if (needs_conversions) { - return m_f(Function_Params{m_param_types.convert(params, t_conversions)}); - } else { - return m_f(params); - } + protected: + Boxed_Value do_call(const Function_Params ¶ms, const Type_Conversions_State &t_conversions) const override { + const auto [is_a_match, needs_conversions] = call_match_internal(params, t_conversions); + if (is_a_match) { + if (needs_conversions) { + return m_f(Function_Params{m_param_types.convert(params, t_conversions)}); } else { - throw exception::guard_error(); + return m_f(params); } + } else { + throw exception::guard_error(); } + } - private: - Callable m_f; + private: + Callable m_f; }; - template - Proxy_Function make_dynamic_proxy_function(Callable &&c, Arg&& ... a) - { - return chaiscript::make_shared>( - std::forward(c), std::forward(a)...); + template + Proxy_Function make_dynamic_proxy_function(Callable &&c, Arg &&...a) { + return chaiscript::make_shared>(std::forward(c), + std::forward(a)...); } /// An object used by Bound_Function to represent "_" parameters /// of a binding. This allows for unbound parameters during bind. - struct Placeholder_Object - { + struct Placeholder_Object { }; /// An implementation of Proxy_Function that takes a Proxy_Function /// and substitutes bound parameters into the parameter list /// at runtime, when call() is executed. /// it is used for bind(function, param1, _, param2) style calls - class Bound_Function final : public Proxy_Function_Base - { - public: - Bound_Function(const Const_Proxy_Function &t_f, - const std::vector &t_args) - : Proxy_Function_Base(build_param_type_info(t_f, t_args), (t_f->get_arity()<0?-1:static_cast(build_param_type_info(t_f, t_args).size())-1)), - m_f(t_f), m_args(t_args) - { - assert(m_f->get_arity() < 0 || m_f->get_arity() == static_cast(m_args.size())); - } + class Bound_Function final : public Proxy_Function_Base { + public: + Bound_Function(const Const_Proxy_Function &t_f, const std::vector &t_args) + : Proxy_Function_Base(build_param_type_info(t_f, t_args), + (t_f->get_arity() < 0 ? -1 : static_cast(build_param_type_info(t_f, t_args).size()) - 1)) + , m_f(t_f) + , m_args(t_args) { + assert(m_f->get_arity() < 0 || m_f->get_arity() == static_cast(m_args.size())); + } - bool operator==(const Proxy_Function_Base &t_f) const noexcept override - { - return &t_f == this; - } + bool operator==(const Proxy_Function_Base &t_f) const noexcept override { return &t_f == this; } + bool call_match(const Function_Params &vals, const Type_Conversions_State &t_conversions) const override { + return m_f->call_match(Function_Params(build_param_list(vals)), t_conversions); + } - bool call_match(const Function_Params &vals, const Type_Conversions_State &t_conversions) const override - { - return m_f->call_match(Function_Params(build_param_list(vals)), t_conversions); - } + std::vector get_contained_functions() const override { return std::vector{m_f}; } - std::vector get_contained_functions() const override - { - return std::vector{m_f}; - } + std::vector build_param_list(const Function_Params ¶ms) const { + auto parg = params.begin(); + auto barg = m_args.begin(); + std::vector args; - std::vector build_param_list(const Function_Params ¶ms) const - { - auto parg = params.begin(); - auto barg = m_args.begin(); - - std::vector args; - - while (!(parg == params.end() && barg == m_args.end())) - { - while (barg != m_args.end() - && !(barg->get_type_info() == chaiscript::detail::Get_Type_Info::get())) - { - args.push_back(*barg); - ++barg; - } - - if (parg != params.end()) - { - args.push_back(*parg); - ++parg; - } - - if (barg != m_args.end() - && barg->get_type_info() == chaiscript::detail::Get_Type_Info::get()) - { - ++barg; - } - } - return args; - } - - - protected: - static std::vector build_param_type_info(const Const_Proxy_Function &t_f, - const std::vector &t_args) - { - assert(t_f->get_arity() < 0 || t_f->get_arity() == static_cast(t_args.size())); - - if (t_f->get_arity() < 0) { return std::vector(); } - - const auto types = t_f->get_param_types(); - assert(types.size() == t_args.size() + 1); - - // this analysis warning is invalid in MSVC12 and doesn't exist in MSVC14 - std::vector retval{types[0]}; - - for (size_t i = 0; i < types.size() - 1; ++i) - { - if (t_args[i].get_type_info() == chaiscript::detail::Get_Type_Info::get()) - { - retval.push_back(types[i+1]); - } + while (!(parg == params.end() && barg == m_args.end())) { + while (barg != m_args.end() && !(barg->get_type_info() == chaiscript::detail::Get_Type_Info::get())) { + args.push_back(*barg); + ++barg; } - return retval; + if (parg != params.end()) { + args.push_back(*parg); + ++parg; + } + + if (barg != m_args.end() && barg->get_type_info() == chaiscript::detail::Get_Type_Info::get()) { + ++barg; + } + } + return args; + } + + protected: + static std::vector build_param_type_info(const Const_Proxy_Function &t_f, const std::vector &t_args) { + assert(t_f->get_arity() < 0 || t_f->get_arity() == static_cast(t_args.size())); + + if (t_f->get_arity() < 0) { + return std::vector(); } - Boxed_Value do_call(const Function_Params ¶ms, const Type_Conversions_State &t_conversions) const override - { - return (*m_f)(Function_Params{build_param_list(params)}, t_conversions); + const auto types = t_f->get_param_types(); + assert(types.size() == t_args.size() + 1); + + // this analysis warning is invalid in MSVC12 and doesn't exist in MSVC14 + std::vector retval{types[0]}; + + for (size_t i = 0; i < types.size() - 1; ++i) { + if (t_args[i].get_type_info() == chaiscript::detail::Get_Type_Info::get()) { + retval.push_back(types[i + 1]); + } } - private: - Const_Proxy_Function m_f; - std::vector m_args; + return retval; + } + + Boxed_Value do_call(const Function_Params ¶ms, const Type_Conversions_State &t_conversions) const override { + return (*m_f)(Function_Params{build_param_list(params)}, t_conversions); + } + + private: + Const_Proxy_Function m_f; + std::vector m_args; }; - class Proxy_Function_Impl_Base : public Proxy_Function_Base - { - public: - explicit Proxy_Function_Impl_Base(const std::vector &t_types) - : Proxy_Function_Base(t_types, static_cast(t_types.size()) - 1) - { - } + class Proxy_Function_Impl_Base : public Proxy_Function_Base { + public: + explicit Proxy_Function_Impl_Base(const std::vector &t_types) + : Proxy_Function_Base(t_types, static_cast(t_types.size()) - 1) { + } - bool call_match(const Function_Params &vals, const Type_Conversions_State &t_conversions) const noexcept override - { - return static_cast(vals.size()) == get_arity() + bool call_match(const Function_Params &vals, const Type_Conversions_State &t_conversions) const noexcept override { + return static_cast(vals.size()) == get_arity() && (compare_types(m_types, vals, t_conversions) && compare_types_with_cast(vals, t_conversions)); - } + } - virtual bool compare_types_with_cast(const Function_Params &vals, const Type_Conversions_State &t_conversions) const noexcept = 0; + virtual bool compare_types_with_cast(const Function_Params &vals, const Type_Conversions_State &t_conversions) const noexcept = 0; }; - - /// For any callable object template - class Proxy_Function_Callable_Impl final : public Proxy_Function_Impl_Base - { - public: - explicit Proxy_Function_Callable_Impl(Callable f) - : Proxy_Function_Impl_Base(detail::build_param_type_list(static_cast(nullptr))), - m_f(std::move(f)) - { - } + class Proxy_Function_Callable_Impl final : public Proxy_Function_Impl_Base { + public: + explicit Proxy_Function_Callable_Impl(Callable f) + : Proxy_Function_Impl_Base(detail::build_param_type_list(static_cast(nullptr))) + , m_f(std::move(f)) { + } - bool compare_types_with_cast(const Function_Params &vals, const Type_Conversions_State &t_conversions) const noexcept override - { - return detail::compare_types_cast(static_cast(nullptr), vals, t_conversions); - } + bool compare_types_with_cast(const Function_Params &vals, const Type_Conversions_State &t_conversions) const noexcept override { + return detail::compare_types_cast(static_cast(nullptr), vals, t_conversions); + } - bool operator==(const Proxy_Function_Base &t_func) const noexcept override - { - return dynamic_cast *>(&t_func) != nullptr; - } + bool operator==(const Proxy_Function_Base &t_func) const noexcept override { + return dynamic_cast *>(&t_func) != nullptr; + } + protected: + Boxed_Value do_call(const Function_Params ¶ms, const Type_Conversions_State &t_conversions) const override { + return detail::call_func(static_cast(nullptr), m_f, params, t_conversions); + } - protected: - Boxed_Value do_call(const Function_Params ¶ms, const Type_Conversions_State &t_conversions) const override - { - return detail::call_func(static_cast(nullptr), m_f, params, t_conversions); - } - - private: - Callable m_f; + private: + Callable m_f; }; + class Assignable_Proxy_Function : public Proxy_Function_Impl_Base { + public: + explicit Assignable_Proxy_Function(const std::vector &t_types) + : Proxy_Function_Impl_Base(t_types) { + } - class Assignable_Proxy_Function : public Proxy_Function_Impl_Base - { - public: - explicit Assignable_Proxy_Function(const std::vector &t_types) - : Proxy_Function_Impl_Base(t_types) - { - } - - virtual void assign(const std::shared_ptr &t_rhs) = 0; + virtual void assign(const std::shared_ptr &t_rhs) = 0; }; template - class Assignable_Proxy_Function_Impl final : public Assignable_Proxy_Function - { - public: - Assignable_Proxy_Function_Impl(std::reference_wrapper> t_f, std::shared_ptr> t_ptr) - : Assignable_Proxy_Function(detail::build_param_type_list(static_cast(nullptr))), - m_f(std::move(t_f)), m_shared_ptr_holder(std::move(t_ptr)) - { - assert(!m_shared_ptr_holder || m_shared_ptr_holder.get() == &m_f.get()); - } + class Assignable_Proxy_Function_Impl final : public Assignable_Proxy_Function { + public: + Assignable_Proxy_Function_Impl(std::reference_wrapper> t_f, std::shared_ptr> t_ptr) + : Assignable_Proxy_Function(detail::build_param_type_list(static_cast(nullptr))) + , m_f(std::move(t_f)) + , m_shared_ptr_holder(std::move(t_ptr)) { + assert(!m_shared_ptr_holder || m_shared_ptr_holder.get() == &m_f.get()); + } - bool compare_types_with_cast(const Function_Params &vals, const Type_Conversions_State &t_conversions) const noexcept override - { - return detail::compare_types_cast(static_cast(nullptr), vals, t_conversions); - } + bool compare_types_with_cast(const Function_Params &vals, const Type_Conversions_State &t_conversions) const noexcept override { + return detail::compare_types_cast(static_cast(nullptr), vals, t_conversions); + } - bool operator==(const Proxy_Function_Base &t_func) const noexcept override - { - return dynamic_cast *>(&t_func) != nullptr; - } + bool operator==(const Proxy_Function_Base &t_func) const noexcept override { + return dynamic_cast *>(&t_func) != nullptr; + } - std::function internal_function() const - { - return m_f.get(); - } + std::function internal_function() const { return m_f.get(); } - void assign(const std::shared_ptr &t_rhs) override { - m_f.get() = dispatch::functor(t_rhs, nullptr); - } + void assign(const std::shared_ptr &t_rhs) override { m_f.get() = dispatch::functor(t_rhs, nullptr); } - protected: - Boxed_Value do_call(const Function_Params ¶ms, const Type_Conversions_State &t_conversions) const override - { - return detail::call_func(static_cast(nullptr), m_f.get(), params, t_conversions); - } + protected: + Boxed_Value do_call(const Function_Params ¶ms, const Type_Conversions_State &t_conversions) const override { + return detail::call_func(static_cast(nullptr), m_f.get(), params, t_conversions); + } - - private: - std::reference_wrapper> m_f; - std::shared_ptr> m_shared_ptr_holder; + private: + std::reference_wrapper> m_f; + std::shared_ptr> m_shared_ptr_holder; }; - /// Attribute getter Proxy_Function implementation template - class Attribute_Access final : public Proxy_Function_Base - { - public: - explicit Attribute_Access(T Class::* t_attr) - : Proxy_Function_Base(param_types(), 1), - m_attr(t_attr) - { + class Attribute_Access final : public Proxy_Function_Base { + public: + explicit Attribute_Access(T Class::*t_attr) + : Proxy_Function_Base(param_types(), 1) + , m_attr(t_attr) { + } + + bool is_attribute_function() const noexcept override { return true; } + + bool operator==(const Proxy_Function_Base &t_func) const noexcept override { + const Attribute_Access *aa = dynamic_cast *>(&t_func); + + if (aa) { + return m_attr == aa->m_attr; + } else { + return false; } + } - bool is_attribute_function() const noexcept override { return true; } - - bool operator==(const Proxy_Function_Base &t_func) const noexcept override - { - const Attribute_Access * aa - = dynamic_cast *>(&t_func); - - if (aa) { - return m_attr == aa->m_attr; - } else { - return false; - } + bool call_match(const Function_Params &vals, const Type_Conversions_State &) const noexcept override { + if (vals.size() != 1) { + return false; } + const auto class_type_info = user_type(); + return vals[0].get_type_info().bare_equal(class_type_info); + } - bool call_match(const Function_Params &vals, const Type_Conversions_State &) const noexcept override - { - if (vals.size() != 1) - { - return false; - } - const auto class_type_info = user_type(); - return vals[0].get_type_info().bare_equal(class_type_info); + protected: + Boxed_Value do_call(const Function_Params ¶ms, const Type_Conversions_State &t_conversions) const override { + const Boxed_Value &bv = params[0]; + if (bv.is_const()) { + const Class *o = boxed_cast(bv, &t_conversions); + return do_call_impl(o); + } else { + Class *o = boxed_cast(bv, &t_conversions); + return do_call_impl(o); } + } - protected: - Boxed_Value do_call(const Function_Params ¶ms, const Type_Conversions_State &t_conversions) const override - { - const Boxed_Value &bv = params[0]; - if (bv.is_const()) - { - const Class *o = boxed_cast(bv, &t_conversions); - return do_call_impl(o); - } else { - Class *o = boxed_cast(bv, &t_conversions); - return do_call_impl(o); - } + private: + template + auto do_call_impl(Class *o) const { + if constexpr (std::is_pointer::value) { + return detail::Handle_Return::handle(o->*m_attr); + } else { + return detail::Handle_Return::type>::handle(o->*m_attr); } + } - private: - template - auto do_call_impl(Class *o) const - { - if constexpr(std::is_pointer::value) { - return detail::Handle_Return::handle(o->*m_attr); - } else { - return detail::Handle_Return::type>::handle(o->*m_attr); - } + template + auto do_call_impl(const Class *o) const { + if constexpr (std::is_pointer::value) { + return detail::Handle_Return::handle(o->*m_attr); + } else { + return detail::Handle_Return::type>::type>::handle(o->*m_attr); } + } - template - auto do_call_impl(const Class *o) const - { - if constexpr(std::is_pointer::value) { - return detail::Handle_Return::handle(o->*m_attr); - } else { - return detail::Handle_Return::type>::type>::handle(o->*m_attr); - } - } + static std::vector param_types() { return {user_type(), user_type()}; } - - static std::vector param_types() - { - return {user_type(), user_type()}; - } - - std::vector m_param_types{user_type(), user_type()}; - T Class::* m_attr; + std::vector m_param_types{user_type(), user_type()}; + T Class::*m_attr; }; - } + } // namespace dispatch - namespace exception - { - /// \brief Exception thrown in the case that a method dispatch fails - /// because no matching function was found - /// - /// May be thrown due to an arity_error, a guard_error or a bad_boxed_cast - /// exception - class dispatch_error : public std::runtime_error - { - public: - dispatch_error(const Function_Params &t_parameters, - std::vector t_functions) - : std::runtime_error("Error with function dispatch"), parameters(t_parameters.to_vector()), functions(std::move(t_functions)) - { - } + namespace exception { + /// \brief Exception thrown in the case that a method dispatch fails + /// because no matching function was found + /// + /// May be thrown due to an arity_error, a guard_error or a bad_boxed_cast + /// exception + class dispatch_error : public std::runtime_error { + public: + dispatch_error(const Function_Params &t_parameters, std::vector t_functions) + : std::runtime_error("Error with function dispatch") + , parameters(t_parameters.to_vector()) + , functions(std::move(t_functions)) { + } - dispatch_error(const Function_Params &t_parameters, - std::vector t_functions, - const std::string &t_desc) - : std::runtime_error(t_desc), parameters(t_parameters.to_vector()), functions(std::move(t_functions)) - { - } + dispatch_error(const Function_Params &t_parameters, std::vector t_functions, const std::string &t_desc) + : std::runtime_error(t_desc) + , parameters(t_parameters.to_vector()) + , functions(std::move(t_functions)) { + } + dispatch_error(const dispatch_error &) = default; + ~dispatch_error() noexcept override = default; - dispatch_error(const dispatch_error &) = default; - ~dispatch_error() noexcept override = default; - - std::vector parameters; - std::vector functions; + std::vector parameters; + std::vector functions; }; - } + } // namespace exception - namespace dispatch - { - namespace detail - { + namespace dispatch { + namespace detail { template - bool types_match_except_for_arithmetic(const FuncType &t_func, const chaiscript::Function_Params &plist, - const Type_Conversions_State &t_conversions) noexcept - { - const std::vector &types = t_func->get_param_types(); + bool types_match_except_for_arithmetic(const FuncType &t_func, + const chaiscript::Function_Params &plist, + const Type_Conversions_State &t_conversions) noexcept { + const std::vector &types = t_func->get_param_types(); - if (t_func->get_arity() == -1) { return false; } - - assert(plist.size() == types.size() - 1); - - return std::mismatch(plist.begin(), plist.end(), - types.begin()+1, - [&](const Boxed_Value &bv, const Type_Info &ti) { - return Proxy_Function_Base::compare_type_to_param(ti, bv, t_conversions) - || (bv.get_type_info().is_arithmetic() && ti.is_arithmetic()); - } - ) == std::make_pair(plist.end(), types.end()); + if (t_func->get_arity() == -1) { + return false; } + assert(plist.size() == types.size() - 1); + + return std::mismatch(plist.begin(), + plist.end(), + types.begin() + 1, + [&](const Boxed_Value &bv, const Type_Info &ti) { + return Proxy_Function_Base::compare_type_to_param(ti, bv, t_conversions) + || (bv.get_type_info().is_arithmetic() && ti.is_arithmetic()); + }) + == std::make_pair(plist.end(), types.end()); + } + template - Boxed_Value dispatch_with_conversions(InItr begin, const InItr &end, const chaiscript::Function_Params &plist, - const Type_Conversions_State &t_conversions, const Funcs &t_funcs) - { - InItr matching_func(end); + Boxed_Value dispatch_with_conversions(InItr begin, + const InItr &end, + const chaiscript::Function_Params &plist, + const Type_Conversions_State &t_conversions, + const Funcs &t_funcs) { + InItr matching_func(end); - while (begin != end) - { - if (types_match_except_for_arithmetic(begin->second, plist, t_conversions)) - { - if (matching_func == end) - { - matching_func = begin; + while (begin != end) { + if (types_match_except_for_arithmetic(begin->second, plist, t_conversions)) { + if (matching_func == end) { + matching_func = begin; + } else { + // handle const members vs non-const member, which is not really ambiguous + const auto &mat_fun_param_types = matching_func->second->get_param_types(); + const auto &next_fun_param_types = begin->second->get_param_types(); + + if (plist[0].is_const() && !mat_fun_param_types[1].is_const() && next_fun_param_types[1].is_const()) { + matching_func = begin; // keep the new one, the const/non-const matchup is correct + } else if (!plist[0].is_const() && !mat_fun_param_types[1].is_const() && next_fun_param_types[1].is_const()) { + // keep the old one, it has a better const/non-const matchup } else { - // handle const members vs non-const member, which is not really ambiguous - const auto &mat_fun_param_types = matching_func->second->get_param_types(); - const auto &next_fun_param_types = begin->second->get_param_types(); - - if (plist[0].is_const() && !mat_fun_param_types[1].is_const() && next_fun_param_types[1].is_const()) { - matching_func = begin; // keep the new one, the const/non-const matchup is correct - } else if (!plist[0].is_const() && !mat_fun_param_types[1].is_const() && next_fun_param_types[1].is_const()) { - // keep the old one, it has a better const/non-const matchup - } else { - // ambiguous function call - throw exception::dispatch_error(plist, std::vector(t_funcs.begin(), t_funcs.end())); - } + // ambiguous function call + throw exception::dispatch_error(plist, std::vector(t_funcs.begin(), t_funcs.end())); } } - - ++begin; } - if (matching_func == end) - { - // no appropriate function to attempt arithmetic type conversion on - throw exception::dispatch_error(plist, std::vector(t_funcs.begin(), t_funcs.end())); - } - - - std::vector newplist; - newplist.reserve(plist.size()); - - const std::vector &tis = matching_func->second->get_param_types(); - std::transform(tis.begin() + 1, tis.end(), - plist.begin(), - std::back_inserter(newplist), - [](const Type_Info &ti, const Boxed_Value ¶m) -> Boxed_Value { - if (ti.is_arithmetic() && param.get_type_info().is_arithmetic() - && param.get_type_info() != ti) { - return Boxed_Number(param).get_as(ti).bv; - } else { - return param; - } - } - ); - - try { - return (*(matching_func->second))(chaiscript::Function_Params{newplist}, t_conversions); - } catch (const exception::bad_boxed_cast &) { - //parameter failed to cast - } catch (const exception::arity_error &) { - //invalid num params - } catch (const exception::guard_error &) { - //guard failed to allow the function to execute - } - - throw exception::dispatch_error(plist, std::vector(t_funcs.begin(), t_funcs.end())); - + ++begin; } - } + + if (matching_func == end) { + // no appropriate function to attempt arithmetic type conversion on + throw exception::dispatch_error(plist, std::vector(t_funcs.begin(), t_funcs.end())); + } + + std::vector newplist; + newplist.reserve(plist.size()); + + const std::vector &tis = matching_func->second->get_param_types(); + std::transform(tis.begin() + 1, tis.end(), plist.begin(), std::back_inserter(newplist), [](const Type_Info &ti, const Boxed_Value ¶m) -> Boxed_Value { + if (ti.is_arithmetic() && param.get_type_info().is_arithmetic() && param.get_type_info() != ti) { + return Boxed_Number(param).get_as(ti).bv; + } else { + return param; + } + }); + + try { + return (*(matching_func->second))(chaiscript::Function_Params{newplist}, t_conversions); + } catch (const exception::bad_boxed_cast &) { + // parameter failed to cast + } catch (const exception::arity_error &) { + // invalid num params + } catch (const exception::guard_error &) { + // guard failed to allow the function to execute + } + + throw exception::dispatch_error(plist, std::vector(t_funcs.begin(), t_funcs.end())); + } + } // namespace detail /// Take a vector of functions and a vector of parameters. Attempt to execute /// each function against the set of parameters, in order, until a matching /// function is found or throw dispatch_error if no matching function is found template - Boxed_Value dispatch(const Funcs &funcs, - const Function_Params &plist, const Type_Conversions_State &t_conversions) - { - std::vector> ordered_funcs; - ordered_funcs.reserve(funcs.size()); + Boxed_Value dispatch(const Funcs &funcs, const Function_Params &plist, const Type_Conversions_State &t_conversions) { + std::vector> ordered_funcs; + ordered_funcs.reserve(funcs.size()); - for (const auto &func : funcs) - { - const auto arity = func->get_arity(); + for (const auto &func : funcs) { + const auto arity = func->get_arity(); - if (arity == -1) - { - ordered_funcs.emplace_back(plist.size(), func.get()); - } else if (arity == static_cast(plist.size())) { - size_t numdiffs = 0; - for (size_t i = 0; i < plist.size(); ++i) - { - if (!func->get_param_types()[i+1].bare_equal(plist[i].get_type_info())) - { - ++numdiffs; - } - } - ordered_funcs.emplace_back(numdiffs, func.get()); - } - } - - - for (size_t i = 0; i <= plist.size(); ++i) - { - for (const auto &func : ordered_funcs ) - { - try { - if (func.first == i && (i == 0 || func.second->filter(plist, t_conversions))) - { - return (*(func.second))(plist, t_conversions); - } - } catch (const exception::bad_boxed_cast &) { - //parameter failed to cast, try again - } catch (const exception::arity_error &) { - //invalid num params, try again - } catch (const exception::guard_error &) { - //guard failed to allow the function to execute, - //try again + if (arity == -1) { + ordered_funcs.emplace_back(plist.size(), func.get()); + } else if (arity == static_cast(plist.size())) { + size_t numdiffs = 0; + for (size_t i = 0; i < plist.size(); ++i) { + if (!func->get_param_types()[i + 1].bare_equal(plist[i].get_type_info())) { + ++numdiffs; } } + ordered_funcs.emplace_back(numdiffs, func.get()); } - - return detail::dispatch_with_conversions(ordered_funcs.cbegin(), ordered_funcs.cend(), plist, t_conversions, funcs); } - } -} + for (size_t i = 0; i <= plist.size(); ++i) { + for (const auto &func : ordered_funcs) { + try { + if (func.first == i && (i == 0 || func.second->filter(plist, t_conversions))) { + return (*(func.second))(plist, t_conversions); + } + } catch (const exception::bad_boxed_cast &) { + // parameter failed to cast, try again + } catch (const exception::arity_error &) { + // invalid num params, try again + } catch (const exception::guard_error &) { + // guard failed to allow the function to execute, + // try again + } + } + } + + return detail::dispatch_with_conversions(ordered_funcs.cbegin(), ordered_funcs.cend(), plist, t_conversions, funcs); + } + } // namespace dispatch +} // namespace chaiscript #endif diff --git a/include/chaiscript/dispatchkit/proxy_functions_detail.hpp b/include/chaiscript/dispatchkit/proxy_functions_detail.hpp index d4f7cb9e..d43d4a13 100644 --- a/include/chaiscript/dispatchkit/proxy_functions_detail.hpp +++ b/include/chaiscript/dispatchkit/proxy_functions_detail.hpp @@ -7,43 +7,39 @@ // This is an open source non-commercial project. Dear PVS-Studio, please check it. // PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com - #ifndef CHAISCRIPT_PROXY_FUNCTIONS_DETAIL_HPP_ #define CHAISCRIPT_PROXY_FUNCTIONS_DETAIL_HPP_ +#include #include #include #include -#include #include "../chaiscript_defines.hpp" #include "boxed_cast.hpp" #include "boxed_value.hpp" +#include "function_params.hpp" #include "handle_return.hpp" #include "type_info.hpp" -#include "function_params.hpp" namespace chaiscript { -class Type_Conversions_State; -namespace exception { -class bad_boxed_cast; -} // namespace exception -} // namespace chaiscript + class Type_Conversions_State; + namespace exception { + class bad_boxed_cast; + } // namespace exception +} // namespace chaiscript -namespace chaiscript -{ - namespace exception - { +namespace chaiscript { + namespace exception { /** - * Exception thrown when there is a mismatch in number of - * parameters during Proxy_Function execution - */ - struct arity_error : std::range_error - { + * Exception thrown when there is a mismatch in number of + * parameters during Proxy_Function execution + */ + struct arity_error : std::range_error { arity_error(int t_got, int t_expected) - : std::range_error("Function dispatch arity mismatch"), - got(t_got), expected(t_expected) - { + : std::range_error("Function dispatch arity mismatch") + , got(t_got) + , expected(t_expected) { } arity_error(const arity_error &) = default; @@ -53,73 +49,63 @@ namespace chaiscript int got; int expected; }; - } + } // namespace exception - namespace dispatch - { - namespace detail - { + namespace dispatch { + namespace detail { /** - * Used by Proxy_Function_Impl to return a list of all param types - * it contains. - */ - template - std::vector build_param_type_list(Ret (*)(Params...)) - { - /// \note somehow this is responsible for a large part of the code generation - return { user_type(), user_type()... }; - } - + * Used by Proxy_Function_Impl to return a list of all param types + * it contains. + */ + template + std::vector build_param_type_list(Ret (*)(Params...)) { + /// \note somehow this is responsible for a large part of the code generation + return {user_type(), user_type()...}; + } /** - * Used by Proxy_Function_Impl to determine if it is equivalent to another - * Proxy_Function_Impl object. This function is primarily used to prevent - * registration of two functions with the exact same signatures - */ - template - bool compare_types_cast(Ret (*)(Params...), - const chaiscript::Function_Params ¶ms, const Type_Conversions_State &t_conversions) noexcept - { - try { - std::vector::size_type i = 0; - ( boxed_cast(params[i++], &t_conversions), ... ); - return true; - } catch (const exception::bad_boxed_cast &) { - return false; - } - } - - - template - Ret call_func(Ret (*)(Params...), - std::index_sequence, const Callable &f, - [[maybe_unused]] const chaiscript::Function_Params ¶ms, - [[maybe_unused]] const Type_Conversions_State &t_conversions) - { - return f(boxed_cast(params[I], &t_conversions)...); + * Used by Proxy_Function_Impl to determine if it is equivalent to another + * Proxy_Function_Impl object. This function is primarily used to prevent + * registration of two functions with the exact same signatures + */ + template + bool compare_types_cast(Ret (*)(Params...), const chaiscript::Function_Params ¶ms, const Type_Conversions_State &t_conversions) noexcept { + try { + std::vector::size_type i = 0; + (boxed_cast(params[i++], &t_conversions), ...); + return true; + } catch (const exception::bad_boxed_cast &) { + return false; } + } + template + Ret call_func(Ret (*)(Params...), + std::index_sequence, + const Callable &f, + [[maybe_unused]] const chaiscript::Function_Params ¶ms, + [[maybe_unused]] const Type_Conversions_State &t_conversions) { + return f(boxed_cast(params[I], &t_conversions)...); + } /// Used by Proxy_Function_Impl to perform typesafe execution of a function. /// The function attempts to unbox each parameter to the expected type. /// if any unboxing fails the execution of the function fails and /// the bad_boxed_cast is passed up to the caller. - template - Boxed_Value call_func(Ret (*sig)(Params...), const Callable &f, - const chaiscript::Function_Params ¶ms, const Type_Conversions_State &t_conversions) - { - if constexpr (std::is_same_v) { - call_func(sig, std::index_sequence_for{}, f, params, t_conversions); - return Handle_Return::handle(); - } else { - return Handle_Return::handle(call_func(sig, std::index_sequence_for{}, f, params, t_conversions)); - } + template + Boxed_Value + call_func(Ret (*sig)(Params...), const Callable &f, const chaiscript::Function_Params ¶ms, const Type_Conversions_State &t_conversions) { + if constexpr (std::is_same_v) { + call_func(sig, std::index_sequence_for{}, f, params, t_conversions); + return Handle_Return::handle(); + } else { + return Handle_Return::handle(call_func(sig, std::index_sequence_for{}, f, params, t_conversions)); } + } - } - } - -} + } // namespace detail + } // namespace dispatch +} // namespace chaiscript #endif diff --git a/include/chaiscript/dispatchkit/register_function.hpp b/include/chaiscript/dispatchkit/register_function.hpp index 1faf59f6..a22280a9 100644 --- a/include/chaiscript/dispatchkit/register_function.hpp +++ b/include/chaiscript/dispatchkit/register_function.hpp @@ -7,63 +7,55 @@ // This is an open source non-commercial project. Dear PVS-Studio, please check it. // PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com - #ifndef CHAISCRIPT_REGISTER_FUNCTION_HPP_ #define CHAISCRIPT_REGISTER_FUNCTION_HPP_ #include #include "bind_first.hpp" -#include "proxy_functions.hpp" #include "function_signature.hpp" +#include "proxy_functions.hpp" -namespace chaiscript -{ - namespace dispatch::detail - { - template - Param1 get_first_param(Function_Params, Obj &&obj) - { - return static_cast(std::forward(obj)); - } +namespace chaiscript { + namespace dispatch::detail { + template + Param1 get_first_param(Function_Params, Obj &&obj) { + return static_cast(std::forward(obj)); + } - template - auto make_callable_impl(Func &&func, Function_Signature, Is_Noexcept, Is_Member, Is_MemberObject, Is_Object>) - { - if constexpr (Is_MemberObject) { - // we now that the Param pack will have only one element, so we are safe expanding it here - return Proxy_Function(chaiscript::make_shared...>>(std::forward(func))); - } else if constexpr (Is_Member) { - // TODO some kind of bug is preventing forwarding of this noexcept for the lambda - auto call = [func = std::forward(func)](auto && obj, auto && ... param) /* noexcept(Is_Noexcept) */ -> decltype(auto) { - return (( get_first_param(Function_Params{}, obj).*func )(std::forward(param)...)); - }; - return Proxy_Function( - chaiscript::make_shared>(std::move(call)) - ); - } else { - return Proxy_Function( - chaiscript::make_shared>>(std::forward(func)) - ); - } + template + auto make_callable_impl(Func &&func, Function_Signature, Is_Noexcept, Is_Member, Is_MemberObject, Is_Object>) { + if constexpr (Is_MemberObject) { + // we now that the Param pack will have only one element, so we are safe expanding it here + return Proxy_Function(chaiscript::make_shared...>>( + std::forward(func))); + } else if constexpr (Is_Member) { + // TODO some kind of bug is preventing forwarding of this noexcept for the lambda + auto call = [func = std::forward(func)](auto &&obj, auto &&...param) /* noexcept(Is_Noexcept) */ -> decltype(auto) { + return ((get_first_param(Function_Params{}, obj).*func)(std::forward(param)...)); + }; + return Proxy_Function( + chaiscript::make_shared>( + std::move(call))); + } else { + return Proxy_Function( + chaiscript::make_shared>>( + std::forward(func))); } + } // this version peels off the function object itself from the function signature, when used // on a callable object - template - auto make_callable(Func &&func, Function_Signature, Is_Noexcept, false, false, true>) - { - return make_callable_impl(std::forward(func), Function_Signature, Is_Noexcept, false, false, true>{}); - } + template + auto make_callable(Func &&func, Function_Signature, Is_Noexcept, false, false, true>) { + return make_callable_impl(std::forward(func), Function_Signature, Is_Noexcept, false, false, true>{}); + } - template - auto make_callable(Func &&func, Function_Signature, Is_Noexcept, Is_Member, Is_MemberObject, false> fs) - { - return make_callable_impl(std::forward(func), fs); - } - } + template + auto make_callable(Func &&func, Function_Signature, Is_Noexcept, Is_Member, Is_MemberObject, false> fs) { + return make_callable_impl(std::forward(func), fs); + } + } // namespace dispatch::detail /// \brief Creates a new Proxy_Function object from a free function, member function or data member /// \param[in] t Function / member to expose @@ -77,22 +69,19 @@ namespace chaiscript /// void memberfunction(); /// int memberdata; /// }; - /// + /// /// chaiscript::ChaiScript chai; /// chai.add(fun(&myfunction), "myfunction"); /// chai.add(fun(&MyClass::memberfunction), "memberfunction"); /// chai.add(fun(&MyClass::memberdata), "memberdata"); /// \endcode - /// + /// /// \sa \ref adding_functions template - Proxy_Function fun(T &&t) - { - return dispatch::detail::make_callable(std::forward(t), dispatch::detail::function_signature(t)); - } + Proxy_Function fun(T &&t) { + return dispatch::detail::make_callable(std::forward(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 /// \param[in] t Function / member to expose /// \param[in] q Value to bind to first parameter @@ -103,24 +92,19 @@ namespace chaiscript /// { /// void memberfunction(int); /// }; - /// + /// /// MyClass obj; /// chaiscript::ChaiScript chai; /// // Add function taking only one argument, an int, and permanently bound to "obj" - /// chai.add(fun(&MyClass::memberfunction, std::ref(obj)), "memberfunction"); + /// chai.add(fun(&MyClass::memberfunction, std::ref(obj)), "memberfunction"); /// \endcode - /// + /// /// \sa \ref adding_functions template - Proxy_Function fun(T &&t, const Q &q) - { - return fun(detail::bind_first(std::forward(t), q)); - } - - - -} + Proxy_Function fun(T &&t, const Q &q) { + return fun(detail::bind_first(std::forward(t), q)); + } +} // namespace chaiscript #endif - diff --git a/include/chaiscript/dispatchkit/short_alloc.hpp b/include/chaiscript/dispatchkit/short_alloc.hpp index e1cc9a96..64f57446 100644 --- a/include/chaiscript/dispatchkit/short_alloc.hpp +++ b/include/chaiscript/dispatchkit/short_alloc.hpp @@ -2,19 +2,19 @@ #define SHORT_ALLOC_H // The MIT License (MIT) -// +// // Copyright (c) 2015 Howard Hinnant -// +// // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: -// +// // The above copyright notice and this permission notice shall be included in all // copies or substantial portions of the Software. -// +// // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -23,137 +23,115 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -#include #include +#include -template -class arena -{ - alignas(alignment) char buf_[N]; - char* ptr_; +template +class arena { + alignas(alignment) char buf_[N]; + char *ptr_; public: - ~arena() {ptr_ = nullptr;} - arena() noexcept : ptr_(buf_) {} - arena(const arena&) = delete; - arena& operator=(const arena&) = delete; + ~arena() { ptr_ = nullptr; } + arena() noexcept + : ptr_(buf_) { + } + arena(const arena &) = delete; + arena &operator=(const arena &) = delete; - template char* allocate(std::size_t n); - void deallocate(char* p, std::size_t n) noexcept; + template + char *allocate(std::size_t n); + void deallocate(char *p, std::size_t n) noexcept; - static constexpr std::size_t size() noexcept {return N;} - std::size_t used() const noexcept {return static_cast(ptr_ - buf_);} - void reset() noexcept {ptr_ = buf_;} + static constexpr std::size_t size() noexcept { return N; } + std::size_t used() const noexcept { return static_cast(ptr_ - buf_); } + void reset() noexcept { ptr_ = buf_; } private: - static - std::size_t - align_up(std::size_t n) noexcept - {return (n + (alignment-1)) & ~(alignment-1);} + static std::size_t align_up(std::size_t n) noexcept { return (n + (alignment - 1)) & ~(alignment - 1); } - bool - pointer_in_buffer(char* p) noexcept - {return buf_ <= p && p <= buf_ + N;} + bool pointer_in_buffer(char *p) noexcept { return buf_ <= p && p <= buf_ + N; } }; -template -template -char* -arena::allocate(std::size_t n) -{ - static_assert(ReqAlign <= alignment, "alignment is too small for this arena"); - assert(pointer_in_buffer(ptr_) && "short_alloc has outlived arena"); - auto const aligned_n = align_up(n); - if (static_cast(buf_ + N - ptr_) >= aligned_n) - { - char* r = ptr_; - ptr_ += aligned_n; - return r; - } +template +template +char *arena::allocate(std::size_t n) { + static_assert(ReqAlign <= alignment, "alignment is too small for this arena"); + assert(pointer_in_buffer(ptr_) && "short_alloc has outlived arena"); + auto const aligned_n = align_up(n); + if (static_cast(buf_ + N - ptr_) >= aligned_n) { + char *r = ptr_; + ptr_ += aligned_n; + return r; + } - static_assert(alignment <= alignof(std::max_align_t), "you've chosen an " - "alignment that is larger than alignof(std::max_align_t), and " - "cannot be guaranteed by normal operator new"); - return static_cast(::operator new(n)); + static_assert(alignment <= alignof(std::max_align_t), + "you've chosen an " + "alignment that is larger than alignof(std::max_align_t), and " + "cannot be guaranteed by normal operator new"); + return static_cast(::operator new(n)); } -template -void -arena::deallocate(char* p, std::size_t n) noexcept -{ - assert(pointer_in_buffer(ptr_) && "short_alloc has outlived arena"); - if (pointer_in_buffer(p)) - { - n = align_up(n); - if (p + n == ptr_) { - ptr_ = p; - } - } - else { - ::operator delete(p); +template +void arena::deallocate(char *p, std::size_t n) noexcept { + assert(pointer_in_buffer(ptr_) && "short_alloc has outlived arena"); + if (pointer_in_buffer(p)) { + n = align_up(n); + if (p + n == ptr_) { + ptr_ = p; } + } else { + ::operator delete(p); + } } -template -class short_alloc -{ +template +class short_alloc { public: - using value_type = T; - static auto constexpr alignment = Align; - static auto constexpr size = N; - using arena_type = arena; + using value_type = T; + static auto constexpr alignment = Align; + static auto constexpr size = N; + using arena_type = arena; private: - arena_type& a_; + arena_type &a_; public: - short_alloc(const short_alloc&) = default; - short_alloc& operator=(const short_alloc&) = delete; + short_alloc(const short_alloc &) = default; + short_alloc &operator=(const short_alloc &) = delete; - explicit short_alloc(arena_type& a) noexcept : a_(a) - { - static_assert(size % alignment == 0, - "size N needs to be a multiple of alignment Align"); - } - template - explicit short_alloc(const short_alloc& a) noexcept - : a_(a.a_) {} + explicit short_alloc(arena_type &a) noexcept + : a_(a) { + static_assert(size % alignment == 0, "size N needs to be a multiple of alignment Align"); + } + template + explicit short_alloc(const short_alloc &a) noexcept + : a_(a.a_) { + } - template struct rebind {using other = short_alloc<_Up, N, alignment>;}; + template + struct rebind { + using other = short_alloc<_Up, N, alignment>; + }; - T* allocate(std::size_t n) - { - return reinterpret_cast(a_.template allocate(n*sizeof(T))); - } - void deallocate(T* p, std::size_t n) noexcept - { - a_.deallocate(reinterpret_cast(p), n*sizeof(T)); - } + T *allocate(std::size_t n) { return reinterpret_cast(a_.template allocate(n * sizeof(T))); } + void deallocate(T *p, std::size_t n) noexcept { a_.deallocate(reinterpret_cast(p), n * sizeof(T)); } - template - friend - bool - operator==(const short_alloc& x, const short_alloc& y) noexcept; + template + friend bool operator==(const short_alloc &x, const short_alloc &y) noexcept; - template friend class short_alloc; + template + friend class short_alloc; }; -template -inline -bool -operator==(const short_alloc& x, const short_alloc& y) noexcept -{ - return N == M && A1 == A2 && &x.a_ == &y.a_; +template +inline bool operator==(const short_alloc &x, const short_alloc &y) noexcept { + return N == M && A1 == A2 && &x.a_ == &y.a_; } -template -inline -bool -operator!=(const short_alloc& x, const short_alloc& y) noexcept -{ - return !(x == y); +template +inline bool operator!=(const short_alloc &x, const short_alloc &y) noexcept { + return !(x == y); } -#endif // SHORT_ALLOC_HPP - +#endif // SHORT_ALLOC_HPP diff --git a/include/chaiscript/dispatchkit/type_conversions.hpp b/include/chaiscript/dispatchkit/type_conversions.hpp index b4ad2177..e47afbf7 100644 --- a/include/chaiscript/dispatchkit/type_conversions.hpp +++ b/include/chaiscript/dispatchkit/type_conversions.hpp @@ -7,10 +7,10 @@ // This is an open source non-commercial project. Dear PVS-Studio, please check it. // PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com - #ifndef CHAISCRIPT_DYNAMIC_CAST_CONVERSION_HPP_ #define CHAISCRIPT_DYNAMIC_CAST_CONVERSION_HPP_ +#include #include #include #include @@ -26,530 +26,410 @@ #include "boxed_value.hpp" #include "type_info.hpp" -namespace chaiscript -{ - namespace exception - { +namespace chaiscript { + namespace exception { /// \brief Error thrown when there's a problem with type conversion - class conversion_error: public bad_boxed_cast - { - public: - 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) {} + class conversion_error : public bad_boxed_cast { + public: + 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) { + } - Type_Info type_to; + Type_Info type_to; }; - class bad_boxed_dynamic_cast : public bad_boxed_cast - { - public: - bad_boxed_dynamic_cast(const Type_Info &t_from, const std::type_info &t_to, - const utility::Static_String &t_what) noexcept - : bad_boxed_cast(t_from, t_to, t_what) - { - } + class bad_boxed_dynamic_cast : public bad_boxed_cast { + public: + bad_boxed_dynamic_cast(const Type_Info &t_from, const std::type_info &t_to, const utility::Static_String &t_what) noexcept + : bad_boxed_cast(t_from, t_to, t_what) { + } - bad_boxed_dynamic_cast(const Type_Info &t_from, const std::type_info &t_to) noexcept - : bad_boxed_cast(t_from, t_to) - { - } + bad_boxed_dynamic_cast(const Type_Info &t_from, const std::type_info &t_to) noexcept + : bad_boxed_cast(t_from, t_to) { + } - explicit bad_boxed_dynamic_cast(const utility::Static_String &w) noexcept - : bad_boxed_cast(w) - { - } + explicit bad_boxed_dynamic_cast(const utility::Static_String &w) noexcept + : bad_boxed_cast(w) { + } - bad_boxed_dynamic_cast(const bad_boxed_dynamic_cast &) = default; + bad_boxed_dynamic_cast(const bad_boxed_dynamic_cast &) = default; - ~bad_boxed_dynamic_cast() noexcept override = default; + ~bad_boxed_dynamic_cast() noexcept override = default; }; - class bad_boxed_type_cast : public bad_boxed_cast - { - public: - bad_boxed_type_cast(const Type_Info &t_from, const std::type_info &t_to, - const utility::Static_String &t_what) noexcept - : bad_boxed_cast(t_from, t_to, t_what) - { - } + class bad_boxed_type_cast : public bad_boxed_cast { + public: + bad_boxed_type_cast(const Type_Info &t_from, const std::type_info &t_to, const utility::Static_String &t_what) noexcept + : bad_boxed_cast(t_from, t_to, t_what) { + } - bad_boxed_type_cast(const Type_Info &t_from, const std::type_info &t_to) noexcept - : bad_boxed_cast(t_from, t_to) - { - } + bad_boxed_type_cast(const Type_Info &t_from, const std::type_info &t_to) noexcept + : bad_boxed_cast(t_from, t_to) { + } - explicit bad_boxed_type_cast(const utility::Static_String &w) noexcept - : bad_boxed_cast(w) - { - } + explicit bad_boxed_type_cast(const utility::Static_String &w) noexcept + : 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 { + class Type_Conversion_Base { + public: + virtual Boxed_Value convert(const Boxed_Value &from) const = 0; + virtual Boxed_Value convert_down(const Boxed_Value &to) const = 0; - namespace detail - { - class Type_Conversion_Base - { - public: - virtual Boxed_Value convert(const Boxed_Value &from) const = 0; - virtual Boxed_Value convert_down(const Boxed_Value &to) const = 0; + const Type_Info &to() const noexcept { return m_to; } + const Type_Info &from() const noexcept { return m_from; } - const Type_Info &to() const noexcept - { - return m_to; - } - const Type_Info &from() const noexcept - { - return m_from; - } + virtual bool bidir() const noexcept { return true; } - virtual bool bidir() const noexcept - { - return true; - } + virtual ~Type_Conversion_Base() = default; - virtual ~Type_Conversion_Base() = default; - - protected: - Type_Conversion_Base(Type_Info t_to, Type_Info t_from) - : m_to(std::move(t_to)), m_from(std::move(t_from)) - { - } - - - private: - const Type_Info m_to; - const Type_Info m_from; + protected: + Type_Conversion_Base(Type_Info t_to, Type_Info t_from) + : m_to(std::move(t_to)) + , m_from(std::move(t_from)) { + } + private: + const Type_Info m_to; + const Type_Info m_from; }; - template - class Static_Caster - { - public: - static Boxed_Value cast(const Boxed_Value &t_from) - { - - if (t_from.get_type_info().bare_equal(chaiscript::user_type())) - { - if (t_from.is_pointer()) - { - // Dynamic cast out the contained boxed value, which we know is the type we want - if (t_from.is_const()) - { - return Boxed_Value( - [&](){ - if (auto data = std::static_pointer_cast(detail::Cast_Helper >::cast(t_from, nullptr))) - { - return data; - } else { - throw std::bad_cast(); - } - }() - ); + template + class Static_Caster { + public: + static Boxed_Value cast(const Boxed_Value &t_from) { + if (t_from.get_type_info().bare_equal(chaiscript::user_type())) { + if (t_from.is_pointer()) { + // Dynamic cast out the contained boxed value, which we know is the type we want + if (t_from.is_const()) { + return Boxed_Value([&]() { + if (auto data + = std::static_pointer_cast(detail::Cast_Helper>::cast(t_from, nullptr))) { + return data; } else { - return Boxed_Value( - [&](){ - if (auto data = std::static_pointer_cast(detail::Cast_Helper >::cast(t_from, nullptr))) - { - return data; - } else { - throw std::bad_cast(); - } - }() - ); + throw std::bad_cast(); } - } else { - // Pull the reference out of the contained boxed value, which we know is the type we want - if (t_from.is_const()) - { - const From &d = detail::Cast_Helper::cast(t_from, nullptr); - const To &data = static_cast(d); - return Boxed_Value(std::cref(data)); - } else { - From &d = detail::Cast_Helper::cast(t_from, nullptr); - To &data = static_cast(d); - return Boxed_Value(std::ref(data)); - } - } + }()); } else { - throw chaiscript::exception::bad_boxed_dynamic_cast(t_from.get_type_info(), typeid(To), "Unknown dynamic_cast_conversion"); + return Boxed_Value([&]() { + if (auto data = std::static_pointer_cast(detail::Cast_Helper>::cast(t_from, nullptr))) { + return data; + } else { + throw std::bad_cast(); + } + }()); + } + } else { + // Pull the reference out of the contained boxed value, which we know is the type we want + if (t_from.is_const()) { + const From &d = detail::Cast_Helper::cast(t_from, nullptr); + const To &data = static_cast(d); + return Boxed_Value(std::cref(data)); + } else { + From &d = detail::Cast_Helper::cast(t_from, nullptr); + To &data = static_cast(d); + return Boxed_Value(std::ref(data)); } } - - }; + } else { + throw chaiscript::exception::bad_boxed_dynamic_cast(t_from.get_type_info(), typeid(To), "Unknown dynamic_cast_conversion"); + } + } + }; - - template - class Dynamic_Caster - { - public: - static Boxed_Value cast(const Boxed_Value &t_from) - { - if (t_from.get_type_info().bare_equal(chaiscript::user_type())) - { - if (t_from.is_pointer()) - { - // Dynamic cast out the contained boxed value, which we know is the type we want - if (t_from.is_const()) - { - return Boxed_Value( - [&](){ - if (auto data = std::dynamic_pointer_cast(detail::Cast_Helper >::cast(t_from, nullptr))) - { - return data; - } else { - throw std::bad_cast(); - } - }() - ); + template + class Dynamic_Caster { + public: + static Boxed_Value cast(const Boxed_Value &t_from) { + if (t_from.get_type_info().bare_equal(chaiscript::user_type())) { + if (t_from.is_pointer()) { + // Dynamic cast out the contained boxed value, which we know is the type we want + if (t_from.is_const()) { + return Boxed_Value([&]() { + if (auto data + = std::dynamic_pointer_cast(detail::Cast_Helper>::cast(t_from, nullptr))) { + return data; + } else { + throw std::bad_cast(); + } + }()); + } else { + return Boxed_Value([&]() { + if (auto data = std::dynamic_pointer_cast(detail::Cast_Helper>::cast(t_from, nullptr))) { + return data; } else { - return Boxed_Value( - [&](){ - if (auto data = std::dynamic_pointer_cast(detail::Cast_Helper >::cast(t_from, nullptr))) - { - return data; - } else { #ifdef CHAISCRIPT_LIBCPP - /// \todo fix this someday after libc++ is fixed. - if (std::string(typeid(To).name()).find("Assignable_Proxy_Function") != std::string::npos) { - auto from = detail::Cast_Helper >::cast(t_from, nullptr); - if (std::string(typeid(*from).name()).find("Assignable_Proxy_Function_Impl") != std::string::npos) { - return std::static_pointer_cast(from); - } - } + /// \todo fix this someday after libc++ is fixed. + if (std::string(typeid(To).name()).find("Assignable_Proxy_Function") != std::string::npos) { + auto from = detail::Cast_Helper>::cast(t_from, nullptr); + if (std::string(typeid(*from).name()).find("Assignable_Proxy_Function_Impl") != std::string::npos) { + return std::static_pointer_cast(from); + } + } #endif - throw std::bad_cast(); - } - }() - ); + throw std::bad_cast(); } - } else { - // Pull the reference out of the contained boxed value, which we know is the type we want - if (t_from.is_const()) - { - const From &d = detail::Cast_Helper::cast(t_from, nullptr); - const To &data = dynamic_cast(d); - return Boxed_Value(std::cref(data)); - } else { - From &d = detail::Cast_Helper::cast(t_from, nullptr); - To &data = dynamic_cast(d); - return Boxed_Value(std::ref(data)); - } - } + }()); + } + } else { + // Pull the reference out of the contained boxed value, which we know is the type we want + if (t_from.is_const()) { + const From &d = detail::Cast_Helper::cast(t_from, nullptr); + const To &data = dynamic_cast(d); + return Boxed_Value(std::cref(data)); } else { - throw chaiscript::exception::bad_boxed_dynamic_cast(t_from.get_type_info(), typeid(To), "Unknown dynamic_cast_conversion"); + From &d = detail::Cast_Helper::cast(t_from, nullptr); + To &data = dynamic_cast(d); + return Boxed_Value(std::ref(data)); } } - - }; - - - template - class Dynamic_Conversion_Impl : public Type_Conversion_Base - { - public: - Dynamic_Conversion_Impl() - : Type_Conversion_Base(chaiscript::user_type(), chaiscript::user_type()) - { - } - - Boxed_Value convert_down(const Boxed_Value &t_base) const override - { - return Dynamic_Caster::cast(t_base); - } - - Boxed_Value convert(const Boxed_Value &t_derived) const override - { - return Static_Caster::cast(t_derived); + } else { + throw chaiscript::exception::bad_boxed_dynamic_cast(t_from.get_type_info(), typeid(To), "Unknown dynamic_cast_conversion"); } + } }; template - class Static_Conversion_Impl : public Type_Conversion_Base - { - public: - Static_Conversion_Impl() - : Type_Conversion_Base(chaiscript::user_type(), chaiscript::user_type()) - { - } + class Dynamic_Conversion_Impl : public Type_Conversion_Base { + public: + Dynamic_Conversion_Impl() + : Type_Conversion_Base(chaiscript::user_type(), chaiscript::user_type()) { + } - Boxed_Value convert_down(const Boxed_Value &t_base) const override - { - throw chaiscript::exception::bad_boxed_dynamic_cast(t_base.get_type_info(), typeid(Derived), - "Unable to cast down inheritance hierarchy with non-polymorphic types"); - } + Boxed_Value convert_down(const Boxed_Value &t_base) const override { return Dynamic_Caster::cast(t_base); } - bool bidir() const noexcept override - { - return false; - } - - Boxed_Value convert(const Boxed_Value &t_derived) const override - { - return Static_Caster::cast(t_derived); - } + Boxed_Value convert(const Boxed_Value &t_derived) const override { return Static_Caster::cast(t_derived); } }; + template + class Static_Conversion_Impl : public Type_Conversion_Base { + public: + Static_Conversion_Impl() + : Type_Conversion_Base(chaiscript::user_type(), chaiscript::user_type()) { + } + Boxed_Value convert_down(const Boxed_Value &t_base) const override { + throw chaiscript::exception::bad_boxed_dynamic_cast(t_base.get_type_info(), + typeid(Derived), + "Unable to cast down inheritance hierarchy with non-polymorphic types"); + } + + bool bidir() const noexcept override { return false; } + + Boxed_Value convert(const Boxed_Value &t_derived) const override { return Static_Caster::cast(t_derived); } + }; template - class Type_Conversion_Impl : public Type_Conversion_Base - { - public: - Type_Conversion_Impl(Type_Info t_from, Type_Info t_to, Callable t_func) - : Type_Conversion_Base(t_to, t_from), - m_func(std::move(t_func)) - { - } - - Boxed_Value convert_down(const Boxed_Value &) const override - { - throw chaiscript::exception::bad_boxed_type_cast("No conversion exists"); - } - - Boxed_Value convert(const Boxed_Value &t_from) const override - { - /// \todo better handling of errors from the conversion function - return m_func(t_from); - } - - bool bidir() const noexcept override - { - return false; - } - - - private: - Callable m_func; - }; - } - - class Type_Conversions - { + class Type_Conversion_Impl : public Type_Conversion_Base { public: - struct Conversion_Saves - { - bool enabled = false; - std::vector saves; - }; - - struct Less_Than - { - 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); - } - }; - - Type_Conversions() - : m_mutex(), - m_conversions(), - m_convertableTypes(), - m_num_types(0) - { + Type_Conversion_Impl(Type_Info t_from, Type_Info t_to, Callable t_func) + : Type_Conversion_Base(t_to, t_from) + , m_func(std::move(t_func)) { } - Type_Conversions(const Type_Conversions &t_other) = delete; - Type_Conversions(Type_Conversions &&) = delete; - - Type_Conversions &operator=(const Type_Conversions &) = delete; - Type_Conversions &operator=(Type_Conversions &&) = delete; - - const std::set &thread_cache() const - { - auto &cache = *m_thread_cache; - if (cache.size() != m_num_types) - { - chaiscript::detail::threading::shared_lock l(m_mutex); - cache = m_convertableTypes; - } - - return cache; + Boxed_Value convert_down(const Boxed_Value &) const override { + throw chaiscript::exception::bad_boxed_type_cast("No conversion exists"); } - - void add_conversion(const std::shared_ptr &conversion) - { - chaiscript::detail::threading::unique_lock l(m_mutex); - if (find_bidir(conversion->to(), conversion->from()) != m_conversions.end()) { - throw exception::conversion_error(conversion->to(), conversion->from(), - "Trying to re-insert an existing conversion!"); - } - m_conversions.insert(conversion); - m_convertableTypes.insert({conversion->to().bare_type_info(), conversion->from().bare_type_info()}); - m_num_types = m_convertableTypes.size(); + Boxed_Value convert(const Boxed_Value &t_from) const override { + /// \todo better handling of errors from the conversion function + return m_func(t_from); } - template - bool convertable_type() const noexcept - { - const auto type = user_type().bare_type_info(); - return thread_cache().count(type) != 0; - } - - template - bool converts() const noexcept - { - return converts(user_type(), user_type()); - } - - bool converts(const Type_Info &to, const Type_Info &from) const noexcept - { - const auto &types = thread_cache(); - if (types.count(to.bare_type_info()) != 0 && types.count(from.bare_type_info()) != 0) - { - return has_conversion(to, from); - } else { - return false; - } - } - - template - Boxed_Value boxed_type_conversion(Conversion_Saves &t_saves, const Boxed_Value &from) const - { - return boxed_type_conversion(user_type(), t_saves, from); - } - - template - Boxed_Value boxed_type_down_conversion(Conversion_Saves &t_saves, const Boxed_Value &to) const - { - return boxed_type_down_conversion(user_type(), t_saves, to); - } - - - Boxed_Value boxed_type_conversion(const Type_Info &to, Conversion_Saves &t_saves, const Boxed_Value &from) const - { - try { - Boxed_Value ret = get_conversion(to, from.get_type_info())->convert(from); - if (t_saves.enabled) { t_saves.saves.push_back(ret); } - return ret; - } catch (const std::out_of_range &) { - throw exception::bad_boxed_dynamic_cast(from.get_type_info(), *to.bare_type_info(), "No known conversion"); - } catch (const std::bad_cast &) { - throw exception::bad_boxed_dynamic_cast(from.get_type_info(), *to.bare_type_info(), "Unable to perform dynamic_cast operation"); - } - } - - Boxed_Value boxed_type_down_conversion(const Type_Info &from, Conversion_Saves &t_saves, const Boxed_Value &to) const - { - try { - Boxed_Value ret = get_conversion(to.get_type_info(), from)->convert_down(to); - if (t_saves.enabled) { t_saves.saves.push_back(ret); } - return ret; - } catch (const std::out_of_range &) { - throw exception::bad_boxed_dynamic_cast(to.get_type_info(), *from.bare_type_info(), "No known conversion"); - } catch (const std::bad_cast &) { - throw exception::bad_boxed_dynamic_cast(to.get_type_info(), *from.bare_type_info(), "Unable to perform dynamic_cast operation"); - } - } - - static void enable_conversion_saves(Conversion_Saves &t_saves, bool t_val) - { - t_saves.enabled = t_val; - } - - std::vector take_saves(Conversion_Saves &t_saves) - { - std::vector ret; - std::swap(ret, t_saves.saves); - return ret; - } - - bool has_conversion(const Type_Info &to, const Type_Info &from) const - { - chaiscript::detail::threading::shared_lock l(m_mutex); - return find_bidir(to, from) != m_conversions.end(); - } - - std::shared_ptr get_conversion(const Type_Info &to, const Type_Info &from) const - { - chaiscript::detail::threading::shared_lock l(m_mutex); - - const auto itr = find(to, from); - - if (itr != m_conversions.end()) - { - return *itr; - } else { - 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 { - return *m_conversion_saves; - } + bool bidir() const noexcept override { return false; } private: - std::set >::const_iterator find_bidir( - const Type_Info &to, const Type_Info &from) const - { - return std::find_if(m_conversions.begin(), m_conversions.end(), - [&to, &from](const std::shared_ptr &conversion) -> bool - { - return (conversion->to().bare_equal(to) && conversion->from().bare_equal(from)) - || (conversion->bidir() && conversion->from().bare_equal(to) && conversion->to().bare_equal(from)); - } - ); - } + Callable m_func; + }; + } // namespace detail - std::set >::const_iterator find( - const Type_Info &to, const Type_Info &from) const - { - return std::find_if(m_conversions.begin(), m_conversions.end(), - [&to, &from](const std::shared_ptr &conversion) - { - return conversion->to().bare_equal(to) && conversion->from().bare_equal(from); - } - ); - } + class Type_Conversions { + public: + struct Conversion_Saves { + bool enabled = false; + std::vector saves; + }; - std::set> get_conversions() const - { + struct Less_Than { + 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); + } + }; + + Type_Conversions() + : m_mutex() + , m_conversions() + , m_convertableTypes() + , m_num_types(0) { + } + + Type_Conversions(const Type_Conversions &t_other) = delete; + Type_Conversions(Type_Conversions &&) = delete; + + Type_Conversions &operator=(const Type_Conversions &) = delete; + Type_Conversions &operator=(Type_Conversions &&) = delete; + + const std::set &thread_cache() const { + auto &cache = *m_thread_cache; + if (cache.size() != m_num_types) { chaiscript::detail::threading::shared_lock l(m_mutex); - - return m_conversions; + cache = m_convertableTypes; } + return cache; + } + void add_conversion(const std::shared_ptr &conversion) { + chaiscript::detail::threading::unique_lock l(m_mutex); + if (find_bidir(conversion->to(), conversion->from()) != m_conversions.end()) { + throw exception::conversion_error(conversion->to(), conversion->from(), "Trying to re-insert an existing conversion!"); + } + m_conversions.insert(conversion); + m_convertableTypes.insert({conversion->to().bare_type_info(), conversion->from().bare_type_info()}); + m_num_types = m_convertableTypes.size(); + } - mutable chaiscript::detail::threading::shared_mutex m_mutex; - std::set> m_conversions; - std::set m_convertableTypes; - std::atomic_size_t m_num_types; - mutable chaiscript::detail::threading::Thread_Storage> m_thread_cache; - mutable chaiscript::detail::threading::Thread_Storage m_conversion_saves; + template + bool convertable_type() const noexcept { + const auto type = user_type().bare_type_info(); + return thread_cache().count(type) != 0; + } + + template + bool converts() const noexcept { + return converts(user_type(), user_type()); + } + + bool converts(const Type_Info &to, const Type_Info &from) const noexcept { + const auto &types = thread_cache(); + if (types.count(to.bare_type_info()) != 0 && types.count(from.bare_type_info()) != 0) { + return has_conversion(to, from); + } else { + return false; + } + } + + template + Boxed_Value boxed_type_conversion(Conversion_Saves &t_saves, const Boxed_Value &from) const { + return boxed_type_conversion(user_type(), t_saves, from); + } + + template + Boxed_Value boxed_type_down_conversion(Conversion_Saves &t_saves, const Boxed_Value &to) const { + return boxed_type_down_conversion(user_type(), t_saves, to); + } + + Boxed_Value boxed_type_conversion(const Type_Info &to, Conversion_Saves &t_saves, const Boxed_Value &from) const { + try { + Boxed_Value ret = get_conversion(to, from.get_type_info())->convert(from); + if (t_saves.enabled) { + t_saves.saves.push_back(ret); + } + return ret; + } catch (const std::out_of_range &) { + throw exception::bad_boxed_dynamic_cast(from.get_type_info(), *to.bare_type_info(), "No known conversion"); + } catch (const std::bad_cast &) { + throw exception::bad_boxed_dynamic_cast(from.get_type_info(), *to.bare_type_info(), "Unable to perform dynamic_cast operation"); + } + } + + Boxed_Value boxed_type_down_conversion(const Type_Info &from, Conversion_Saves &t_saves, const Boxed_Value &to) const { + try { + Boxed_Value ret = get_conversion(to.get_type_info(), from)->convert_down(to); + if (t_saves.enabled) { + t_saves.saves.push_back(ret); + } + return ret; + } catch (const std::out_of_range &) { + throw exception::bad_boxed_dynamic_cast(to.get_type_info(), *from.bare_type_info(), "No known conversion"); + } catch (const std::bad_cast &) { + throw exception::bad_boxed_dynamic_cast(to.get_type_info(), *from.bare_type_info(), "Unable to perform dynamic_cast operation"); + } + } + + static void enable_conversion_saves(Conversion_Saves &t_saves, bool t_val) { t_saves.enabled = t_val; } + + std::vector take_saves(Conversion_Saves &t_saves) { + std::vector ret; + std::swap(ret, t_saves.saves); + return ret; + } + + bool has_conversion(const Type_Info &to, const Type_Info &from) const { + chaiscript::detail::threading::shared_lock l(m_mutex); + return find_bidir(to, from) != m_conversions.end(); + } + + std::shared_ptr get_conversion(const Type_Info &to, const Type_Info &from) const { + chaiscript::detail::threading::shared_lock l(m_mutex); + + const auto itr = find(to, from); + + if (itr != m_conversions.end()) { + return *itr; + } else { + 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 { return *m_conversion_saves; } + + private: + std::set>::const_iterator find_bidir(const Type_Info &to, const Type_Info &from) const { + return std::find_if(m_conversions.begin(), + m_conversions.end(), + [&to, &from](const std::shared_ptr &conversion) -> bool { + return (conversion->to().bare_equal(to) && conversion->from().bare_equal(from)) + || (conversion->bidir() && conversion->from().bare_equal(to) && conversion->to().bare_equal(from)); + }); + } + + std::set>::const_iterator find(const Type_Info &to, const Type_Info &from) const { + return std::find_if(m_conversions.begin(), + m_conversions.end(), + [&to, &from](const std::shared_ptr &conversion) { + return conversion->to().bare_equal(to) && conversion->from().bare_equal(from); + }); + } + + std::set> get_conversions() const { + chaiscript::detail::threading::shared_lock l(m_mutex); + + return m_conversions; + } + + mutable chaiscript::detail::threading::shared_mutex m_mutex; + std::set> m_conversions; + std::set m_convertableTypes; + std::atomic_size_t m_num_types; + mutable chaiscript::detail::threading::Thread_Storage> m_thread_cache; + mutable chaiscript::detail::threading::Thread_Storage m_conversion_saves; }; - class Type_Conversions_State - { - public: - Type_Conversions_State(const Type_Conversions &t_conversions, - Type_Conversions::Conversion_Saves &t_saves) - : m_conversions(t_conversions), - m_saves(t_saves) - { - } + class Type_Conversions_State { + public: + Type_Conversions_State(const Type_Conversions &t_conversions, Type_Conversions::Conversion_Saves &t_saves) + : m_conversions(t_conversions) + , m_saves(t_saves) { + } - const Type_Conversions *operator->() const noexcept { - return &m_conversions.get(); - } + const Type_Conversions *operator->() const noexcept { return &m_conversions.get(); } - const Type_Conversions *get() const noexcept { - return &m_conversions.get(); - } + const Type_Conversions *get() const noexcept { return &m_conversions.get(); } - Type_Conversions::Conversion_Saves &saves() const noexcept { - return m_saves; - } + Type_Conversions::Conversion_Saves &saves() const noexcept { return m_saves; } - private: - std::reference_wrapper m_conversions; - std::reference_wrapper m_saves; + private: + std::reference_wrapper m_conversions; + std::reference_wrapper m_saves; }; using Type_Conversion = std::shared_ptr; @@ -574,87 +454,86 @@ namespace chaiscript /// chaiscript::ChaiScript chai; /// chai.add(chaiscript::to_class()); /// \endcode - /// + /// template - Type_Conversion base_class() - { - //Can only be used with related polymorphic types - //may be expanded some day to support conversions other than child -> parent - static_assert(std::is_base_of::value, "Classes are not related by inheritance"); + Type_Conversion base_class() { + // Can only be used with related polymorphic types + // may be expanded some day to support conversions other than child -> parent + static_assert(std::is_base_of::value, "Classes are not related by inheritance"); - if constexpr(std::is_polymorphic::value && std::is_polymorphic::value) { + if constexpr (std::is_polymorphic::value && std::is_polymorphic::value) { return chaiscript::make_shared>(); } else { return chaiscript::make_shared>(); } } - template - Type_Conversion type_conversion(const Type_Info &t_from, const Type_Info &t_to, - const Callable &t_func) - { - return chaiscript::make_shared>(t_from, t_to, t_func); - } + Type_Conversion type_conversion(const Type_Info &t_from, const Type_Info &t_to, const Callable &t_func) { + return chaiscript::make_shared>(t_from, t_to, t_func); + } template - Type_Conversion type_conversion(const Callable &t_function) - { - auto func = [t_function](const Boxed_Value &t_bv) -> Boxed_Value { - // not even attempting to call boxed_cast so that we don't get caught in some call recursion - return chaiscript::Boxed_Value(t_function(detail::Cast_Helper::cast(t_bv, nullptr))); - }; + Type_Conversion type_conversion(const Callable &t_function) { + auto func = [t_function](const Boxed_Value &t_bv) -> Boxed_Value { + // not even attempting to call boxed_cast so that we don't get caught in some call recursion + return chaiscript::Boxed_Value(t_function(detail::Cast_Helper::cast(t_bv, nullptr))); + }; - return chaiscript::make_shared>(user_type(), user_type(), func); - } + return chaiscript::make_shared>(user_type(), + user_type(), + func); + } template - Type_Conversion type_conversion() - { - static_assert(std::is_convertible::value, "Types are not automatically convertible"); - auto func = [](const Boxed_Value &t_bv) -> Boxed_Value { - // not even attempting to call boxed_cast so that we don't get caught in some call recursion - return chaiscript::Boxed_Value(To(detail::Cast_Helper::cast(t_bv, nullptr))); - }; + Type_Conversion type_conversion() { + static_assert(std::is_convertible::value, "Types are not automatically convertible"); + auto func = [](const Boxed_Value &t_bv) -> Boxed_Value { + // not even attempting to call boxed_cast so that we don't get caught in some call recursion + return chaiscript::Boxed_Value(To(detail::Cast_Helper::cast(t_bv, nullptr))); + }; - return chaiscript::make_shared>(user_type(), user_type(), func); - } + return chaiscript::make_shared>(user_type(), + user_type(), + func); + } template - Type_Conversion vector_conversion() - { - auto func = [](const Boxed_Value &t_bv) -> Boxed_Value { - const std::vector &from_vec = detail::Cast_Helper &>::cast(t_bv, nullptr); + Type_Conversion vector_conversion() { + auto func = [](const Boxed_Value &t_bv) -> Boxed_Value { + const std::vector &from_vec = detail::Cast_Helper &>::cast(t_bv, nullptr); - To vec; - vec.reserve(from_vec.size()); - for (const Boxed_Value &bv : from_vec) { - vec.push_back(detail::Cast_Helper::cast(bv, nullptr)); - } + To vec; + vec.reserve(from_vec.size()); + for (const Boxed_Value &bv : from_vec) { + vec.push_back(detail::Cast_Helper::cast(bv, nullptr)); + } - return Boxed_Value(std::move(vec)); - }; + return Boxed_Value(std::move(vec)); + }; - return chaiscript::make_shared>(user_type>(), user_type(), func); - } + return chaiscript::make_shared>(user_type>(), + user_type(), + func); + } template - Type_Conversion map_conversion() - { - auto func = [](const Boxed_Value &t_bv) -> Boxed_Value { - const std::map &from_map = detail::Cast_Helper &>::cast(t_bv, nullptr); + Type_Conversion map_conversion() { + auto func = [](const Boxed_Value &t_bv) -> Boxed_Value { + const std::map &from_map + = detail::Cast_Helper &>::cast(t_bv, nullptr); - To map; - for (const std::pair &p : from_map) { - map.insert(std::make_pair(p.first, detail::Cast_Helper::cast(p.second, nullptr))); - } + To map; + for (const std::pair &p : from_map) { + map.insert(std::make_pair(p.first, detail::Cast_Helper::cast(p.second, nullptr))); + } - return Boxed_Value(std::move(map)); - }; - - return chaiscript::make_shared>(user_type>(), user_type(), func); - } -} + return Boxed_Value(std::move(map)); + }; + return chaiscript::make_shared>( + user_type>(), user_type(), func); + } +} // namespace chaiscript #endif diff --git a/include/chaiscript/dispatchkit/type_info.hpp b/include/chaiscript/dispatchkit/type_info.hpp index 7479d9fa..2f21ee58 100644 --- a/include/chaiscript/dispatchkit/type_info.hpp +++ b/include/chaiscript/dispatchkit/type_info.hpp @@ -7,236 +7,204 @@ // This is an open source non-commercial project. Dear PVS-Studio, please check it. // PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com - #ifndef CHAISCRIPT_TYPE_INFO_HPP_ #define CHAISCRIPT_TYPE_INFO_HPP_ #include +#include #include #include -#include -namespace chaiscript -{ - - namespace detail - { +namespace chaiscript { + namespace detail { template - struct Bare_Type - { - using type = typename std::remove_cv::type>::type>::type; - }; - } - + struct Bare_Type { + using type = typename std::remove_cv::type>::type>::type; + }; + } // namespace detail /// \brief Compile time deduced information about a type - class Type_Info - { - public: - constexpr Type_Info(const bool t_is_const, const bool t_is_reference, const bool t_is_pointer, const bool t_is_void, - const bool t_is_arithmetic, const std::type_info *t_ti, const std::type_info *t_bare_ti) noexcept - : m_type_info(t_ti), m_bare_type_info(t_bare_ti), - m_flags((static_cast(t_is_const) << is_const_flag) - + (static_cast(t_is_reference) << is_reference_flag) - + (static_cast(t_is_pointer) << is_pointer_flag) - + (static_cast(t_is_void) << is_void_flag) - + (static_cast(t_is_arithmetic) << is_arithmetic_flag)) - { + class Type_Info { + public: + constexpr Type_Info(const bool t_is_const, + const bool t_is_reference, + const bool t_is_pointer, + const bool t_is_void, + const bool t_is_arithmetic, + const std::type_info *t_ti, + const std::type_info *t_bare_ti) noexcept + : m_type_info(t_ti) + , m_bare_type_info(t_bare_ti) + , m_flags((static_cast(t_is_const) << is_const_flag) + (static_cast(t_is_reference) << is_reference_flag) + + (static_cast(t_is_pointer) << is_pointer_flag) + (static_cast(t_is_void) << is_void_flag) + + (static_cast(t_is_arithmetic) << is_arithmetic_flag)) { + } + + constexpr Type_Info() noexcept = default; + + bool operator<(const Type_Info &ti) const noexcept { 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 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_reference() const noexcept { return (m_flags & (1 << is_reference_flag)) != 0; } + constexpr bool is_void() const noexcept { return (m_flags & (1 << is_void_flag)) != 0; } + constexpr bool is_arithmetic() const noexcept { return (m_flags & (1 << is_arithmetic_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; } + + const char *name() const noexcept { + if (!is_undef()) { + return m_type_info->name(); + } else { + return ""; } + } - constexpr Type_Info() noexcept = default; - - bool operator<(const Type_Info &ti) const noexcept - { - return m_type_info->before(*ti.m_type_info); + const char *bare_name() const noexcept { + if (!is_undef()) { + return m_bare_type_info->name(); + } else { + return ""; } + } - constexpr bool operator!=(const Type_Info &ti) const noexcept - { - return !(operator==(ti)); - } + constexpr const std::type_info *bare_type_info() const noexcept { return m_bare_type_info; } - constexpr bool operator!=(const std::type_info &ti) const noexcept - { - return !(operator==(ti)); - } + private: + struct Unknown_Type { + }; - 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_reference() const noexcept { return (m_flags & (1 << is_reference_flag)) != 0; } - constexpr bool is_void() const noexcept { return (m_flags & (1 << is_void_flag)) != 0; } - constexpr bool is_arithmetic() const noexcept { return (m_flags & (1 << is_arithmetic_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; } - - const char * name() const noexcept - { - if (!is_undef()) - { - return m_type_info->name(); - } else { - return ""; - } - } - - const char * bare_name() const noexcept - { - if (!is_undef()) - { - return m_bare_type_info->name(); - } else { - return ""; - } - } - - constexpr const std::type_info *bare_type_info() const noexcept - { - return m_bare_type_info; - } - - private: - struct Unknown_Type {}; - - const std::type_info *m_type_info = &typeid(Unknown_Type); - const std::type_info *m_bare_type_info = &typeid(Unknown_Type); - static const int is_const_flag = 0; - static const int is_reference_flag = 1; - static const int is_pointer_flag = 2; - static const int is_void_flag = 3; - static const int is_arithmetic_flag = 4; - static const int is_undef_flag = 5; - unsigned int m_flags = (1 << is_undef_flag); + const std::type_info *m_type_info = &typeid(Unknown_Type); + const std::type_info *m_bare_type_info = &typeid(Unknown_Type); + static const int is_const_flag = 0; + static const int is_reference_flag = 1; + static const int is_pointer_flag = 2; + static const int is_void_flag = 3; + static const int is_arithmetic_flag = 4; + static const int is_undef_flag = 5; + unsigned int m_flags = (1 << is_undef_flag); }; - namespace detail - { + namespace detail { /// Helper used to create a Type_Info object template - struct Get_Type_Info - { - constexpr static Type_Info get() noexcept - { - return Type_Info(std::is_const::type>::type>::value, - std::is_reference::value, std::is_pointer::value, - std::is_void::value, - (std::is_arithmetic::value || std::is_arithmetic::type>::value) - && !std::is_same::type>::type, bool>::value, - &typeid(T), - &typeid(typename Bare_Type::type)); - } - }; + struct Get_Type_Info { + constexpr static Type_Info get() noexcept { + return Type_Info(std::is_const::type>::type>::value, + std::is_reference::value, + std::is_pointer::value, + std::is_void::value, + (std::is_arithmetic::value || std::is_arithmetic::type>::value) + && !std::is_same::type>::type, bool>::value, + &typeid(T), + &typeid(typename Bare_Type::type)); + } + }; template - struct Get_Type_Info > - { - constexpr static Type_Info get() noexcept - { - return Type_Info(std::is_const::value, std::is_reference::value, std::is_pointer::value, - std::is_void::value, - std::is_arithmetic::value && !std::is_same::type>::type, bool>::value, - &typeid(std::shared_ptr ), - &typeid(typename Bare_Type::type)); - } - }; + struct Get_Type_Info> { + constexpr static Type_Info get() noexcept { + return Type_Info(std::is_const::value, + std::is_reference::value, + std::is_pointer::value, + std::is_void::value, + std::is_arithmetic::value + && !std::is_same::type>::type, bool>::value, + &typeid(std::shared_ptr), + &typeid(typename Bare_Type::type)); + } + }; template - struct Get_Type_Info &> : Get_Type_Info> - { - }; + struct Get_Type_Info &> : Get_Type_Info> { + }; template - struct Get_Type_Info &> - { - constexpr static Type_Info get() noexcept - { - return Type_Info(std::is_const::value, std::is_reference::value, std::is_pointer::value, - std::is_void::value, - std::is_arithmetic::value && !std::is_same::type>::type, bool>::value, - &typeid(const std::shared_ptr &), - &typeid(typename Bare_Type::type)); - } - }; + struct Get_Type_Info &> { + constexpr static Type_Info get() noexcept { + return Type_Info(std::is_const::value, + std::is_reference::value, + std::is_pointer::value, + std::is_void::value, + std::is_arithmetic::value + && !std::is_same::type>::type, bool>::value, + &typeid(const std::shared_ptr &), + &typeid(typename Bare_Type::type)); + } + }; template - struct Get_Type_Info > - { - constexpr static Type_Info get() noexcept - { - return Type_Info(std::is_const::value, std::is_reference::value, std::is_pointer::value, - std::is_void::value, - std::is_arithmetic::value && !std::is_same::type>::type, bool>::value, - &typeid(std::reference_wrapper ), - &typeid(typename Bare_Type::type)); - } - }; + struct Get_Type_Info> { + constexpr static Type_Info get() noexcept { + return Type_Info(std::is_const::value, + std::is_reference::value, + std::is_pointer::value, + std::is_void::value, + std::is_arithmetic::value + && !std::is_same::type>::type, bool>::value, + &typeid(std::reference_wrapper), + &typeid(typename Bare_Type::type)); + } + }; template - struct Get_Type_Info &> - { - constexpr static Type_Info get() noexcept - { - return Type_Info(std::is_const::value, std::is_reference::value, std::is_pointer::value, - std::is_void::value, - std::is_arithmetic::value && !std::is_same::type>::type, bool>::value, - &typeid(const std::reference_wrapper &), - &typeid(typename Bare_Type::type)); - } - }; + struct Get_Type_Info &> { + constexpr static Type_Info get() noexcept { + return Type_Info(std::is_const::value, + std::is_reference::value, + std::is_pointer::value, + std::is_void::value, + std::is_arithmetic::value + && !std::is_same::type>::type, bool>::value, + &typeid(const std::reference_wrapper &), + &typeid(typename Bare_Type::type)); + } + }; - } + } // namespace detail /// \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 /// \return Type_Info for T - /// + /// /// \b Example: /// \code /// int i; /// chaiscript::Type_Info ti = chaiscript::user_type(i); /// \endcode template - constexpr Type_Info user_type(const T &/*t*/) noexcept - { + constexpr Type_Info user_type(const T & /*t*/) noexcept { return detail::Get_Type_Info::get(); } - /// \brief Creates a Type_Info object representing the templated type /// \tparam T Type of object to get a Type_Info for /// \return Type_Info for T - /// + /// /// \b Example: /// \code /// chaiscript::Type_Info ti = chaiscript::user_type(); /// \endcode template - constexpr Type_Info user_type() noexcept - { + constexpr Type_Info user_type() noexcept { return detail::Get_Type_Info::get(); } -} +} // namespace chaiscript #endif - diff --git a/include/chaiscript/language/chaiscript_algebraic.hpp b/include/chaiscript/language/chaiscript_algebraic.hpp index b75144a1..08592802 100644 --- a/include/chaiscript/language/chaiscript_algebraic.hpp +++ b/include/chaiscript/language/chaiscript_algebraic.hpp @@ -7,7 +7,6 @@ // This is an open source non-commercial project. Dear PVS-Studio, please check it. // PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com - #ifndef CHAISCRIPT_ALGEBRAIC_HPP_ #define CHAISCRIPT_ALGEBRAIC_HPP_ @@ -15,43 +14,51 @@ #include -namespace chaiscript -{ - +namespace chaiscript { struct Operators { - enum class Opers - { - equals, less_than, greater_than, less_than_equal, greater_than_equal, not_equal, - assign, 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, + enum class Opers { + equals, + less_than, + greater_than, + less_than_equal, + greater_than_equal, + not_equal, + assign, + 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 }; constexpr static const char *to_string(Opers t_oper) noexcept { - constexpr const char *opers[] = { - "", - "==", "<", ">", "<=", ">=", "!=", - "", - "=", "++", "--", "*=", "+=", - "/=", "-=", - "", - "&=", "|=", "<<=", ">>=", - "%=", "^=", - "", - "<<", ">>", "%", "&", "|", "^", "~", - "", - "+", "/", "*", "-", "+", "-", - "" - }; + constexpr const char *opers[] + = {"", "==", "<", ">", "<=", ">=", "!=", "", "=", "++", "--", "*=", "+=", "/=", "-=", "", "&=", "|=", "<<=", ">>=", "%=", "^=", "", "<<", ">>", "%", "&", "|", "^", "~", "", "+", "/", "*", "-", "+", "-", ""}; return opers[static_cast(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 #pragma warning(push) #pragma warning(disable : 4307) @@ -59,45 +66,102 @@ namespace chaiscript const auto op_hash = utility::hash(t_str); switch (op_hash) { - case utility::hash("=="): { return Opers::equals; } - case utility::hash("<"): { return Opers::less_than; } - case utility::hash(">"): { return Opers::greater_than; } - case utility::hash("<="): { return Opers::less_than_equal; } - case utility::hash(">="): { return Opers::greater_than_equal; } - case utility::hash("!="): { return Opers::not_equal; } - case utility::hash("="): { return Opers::assign; } - case utility::hash("++"): { return Opers::pre_increment; } - case utility::hash("--"): { return Opers::pre_decrement; } - case utility::hash("*="): { return Opers::assign_product; } - case utility::hash("+="): { return Opers::assign_sum; } - case utility::hash("-="): { return Opers::assign_difference; } - case utility::hash("&="): { return Opers::assign_bitwise_and; } - case utility::hash("|="): { return Opers::assign_bitwise_or; } - case utility::hash("<<="): { return Opers::assign_shift_left; } - case utility::hash(">>="): { return Opers::assign_shift_right; } - case utility::hash("%="): { return Opers::assign_remainder; } - case utility::hash("^="): { return Opers::assign_bitwise_xor; } - case utility::hash("<<"): { return Opers::shift_left; } - case utility::hash(">>"): { return Opers::shift_right; } - case utility::hash("%"): { return Opers::remainder; } - case utility::hash("&"): { return Opers::bitwise_and; } - case utility::hash("|"): { return Opers::bitwise_or; } - case utility::hash("^"): { return Opers::bitwise_xor; } - case utility::hash("~"): { return Opers::bitwise_complement; } - case utility::hash("+"): { return t_is_unary ? Opers::unary_plus : Opers::sum; } - case utility::hash("-"): { return t_is_unary ? Opers::unary_minus : Opers::difference; } - case utility::hash("/"): { return Opers::quotient; } - case utility::hash("*"): { return Opers::product; } - default: { return Opers::invalid; } + case utility::hash("=="): { + return Opers::equals; + } + case utility::hash("<"): { + return Opers::less_than; + } + case utility::hash(">"): { + return Opers::greater_than; + } + case utility::hash("<="): { + return Opers::less_than_equal; + } + case utility::hash(">="): { + return Opers::greater_than_equal; + } + case utility::hash("!="): { + return Opers::not_equal; + } + case utility::hash("="): { + return Opers::assign; + } + case utility::hash("++"): { + return Opers::pre_increment; + } + case utility::hash("--"): { + return Opers::pre_decrement; + } + case utility::hash("*="): { + return Opers::assign_product; + } + case utility::hash("+="): { + return Opers::assign_sum; + } + case utility::hash("-="): { + return Opers::assign_difference; + } + case utility::hash("&="): { + return Opers::assign_bitwise_and; + } + case utility::hash("|="): { + return Opers::assign_bitwise_or; + } + case utility::hash("<<="): { + return Opers::assign_shift_left; + } + case utility::hash(">>="): { + return Opers::assign_shift_right; + } + case utility::hash("%="): { + return Opers::assign_remainder; + } + case utility::hash("^="): { + return Opers::assign_bitwise_xor; + } + case utility::hash("<<"): { + return Opers::shift_left; + } + case utility::hash(">>"): { + return Opers::shift_right; + } + case utility::hash("%"): { + return Opers::remainder; + } + case utility::hash("&"): { + return Opers::bitwise_and; + } + case utility::hash("|"): { + return Opers::bitwise_or; + } + case utility::hash("^"): { + return Opers::bitwise_xor; + } + case utility::hash("~"): { + return Opers::bitwise_complement; + } + case utility::hash("+"): { + return t_is_unary ? Opers::unary_plus : Opers::sum; + } + case utility::hash("-"): { + return t_is_unary ? Opers::unary_minus : Opers::difference; + } + case utility::hash("/"): { + return Opers::quotient; + } + case utility::hash("*"): { + return Opers::product; + } + default: { + return Opers::invalid; + } } #ifdef CHAISCRIPT_MSVC #pragma warning(pop) #endif - } - }; -} +} // namespace chaiscript #endif /* _CHAISCRIPT_ALGEBRAIC_HPP */ - diff --git a/include/chaiscript/language/chaiscript_common.hpp b/include/chaiscript/language/chaiscript_common.hpp index acbd87e8..f4d51a19 100644 --- a/include/chaiscript/language/chaiscript_common.hpp +++ b/include/chaiscript/language/chaiscript_common.hpp @@ -7,7 +7,6 @@ // This is an open source non-commercial project. Dear PVS-Studio, please check it. // PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com - #ifndef CHAISCRIPT_COMMON_HPP_ #define CHAISCRIPT_COMMON_HPP_ @@ -26,53 +25,26 @@ #include namespace chaiscript { -struct AST_Node; -} // namespace chaiscript + struct AST_Node; +} // namespace chaiscript -namespace chaiscript -{ +namespace chaiscript { struct Name_Validator { template - static bool is_reserved_word(const T &s) noexcept - { - const static std::unordered_set 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__")}; + static bool is_reserved_word(const T &s) noexcept { + const static std::unordered_set + words{utility::hash("def"), utility::hash("fun"), utility::hash("while"), utility::hash("for"), utility::hash("if"), utility::hash("else"), utility::hash("&&"), utility::hash("||"), utility::hash(","), utility::hash("auto"), utility::hash("return"), utility::hash("break"), utility::hash("true"), utility::hash("false"), utility::hash("class"), utility::hash("attr"), utility::hash("var"), utility::hash("global"), utility::hash("GLOBAL"), utility::hash("_"), utility::hash("__LINE__"), utility::hash("__FILE__"), utility::hash("__FUNC__"), utility::hash("__CLASS__")}; return words.count(utility::hash(s)) == 1; } template - 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); } template - static void validate_object_name(const T &name) - { + static void validate_object_name(const T &name) { if (is_reserved_word(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. using Create_Module_Func = ModulePtr (*)(); - /// 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, - 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 AST_Node_Type { + 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 }; - enum class Operator_Precedence { Ternary_Cond, Logical_Or, - Logical_And, Bitwise_Or, Bitwise_Xor, Bitwise_And, - Equality, Comparison, Shift, Addition, Multiplication, Prefix }; + enum class Operator_Precedence { + Ternary_Cond, + 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 constexpr const char *ast_node_type_to_string(AST_Node_Type ast_node_type) noexcept { - constexpr const char * const ast_node_types[] = { "Id", "Fun_Call", "Unused_Return_Fun_Call", "Arg_List", "Equation", "Var_Decl", "Assign_Decl", - "Array_Call", "Dot_Access", - "Lambda", "Block", "Scopeless_Block", "Def", "While", "If", "For", "Ranged_For", "Inline_Array", "Inline_Map", "Return", "File", "Prefix", "Break", "Continue", "Map_Pair", "Value_Range", - "Inline_Range", "Try", "Catch", "Finally", "Method", "Attr_Decl", - "Logical_And", "Logical_Or", "Reference", "Switch", "Case", "Default", "Noop", "Class", "Binary", "Arg", "Global_Decl", "Constant", "Compiled"}; + 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"}; return ast_node_types[static_cast(ast_node_type)]; } - } + } // namespace /// \brief Convenience type for file positions struct File_Position { @@ -119,64 +137,57 @@ namespace chaiscript int column = 0; 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; }; struct Parse_Location { - 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) - : start(t_start_line, t_start_col), - end(t_end_line, t_end_col), - filename(std::make_shared(std::move(t_fname))) - { + 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) + : start(t_start_line, t_start_col) + , end(t_end_line, t_end_col) + , filename(std::make_shared(std::move(t_fname))) { } - Parse_Location(std::shared_ptr 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) - : start(t_start_line, t_start_col), - end(t_end_line, t_end_col), - filename(std::move(t_fname)) - { + Parse_Location(std::shared_ptr 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) + : start(t_start_line, t_start_col) + , end(t_end_line, t_end_col) + , filename(std::move(t_fname)) { } - - File_Position start; File_Position end; std::shared_ptr filename; }; - /// \brief Typedef for pointers to AST_Node objects. Used in building of the AST_Node tree using AST_NodePtr = std::unique_ptr; using AST_NodePtr_Const = std::unique_ptr; struct AST_Node_Trace; - /// \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 - struct load_module_error : std::runtime_error - { + struct load_module_error : std::runtime_error { 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 &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() noexcept override = default; - static std::string format_error(const std::string &t_name, const std::vector &t_errors) - { + static std::string format_error(const std::string &t_name, const std::vector &t_errors) { std::stringstream ss; ss << "Error loading module '" << t_name << "'\n" << " The following locations were searched:\n"; @@ -189,7 +200,6 @@ namespace chaiscript } }; - /// Errors generated during parsing or evaluation struct eval_error : std::runtime_error { std::string reason; @@ -198,48 +208,55 @@ namespace chaiscript std::string detail; std::vector call_stack; - eval_error(const std::string &t_why, const File_Position &t_where, const std::string &t_fname, - const std::vector &t_parameters, const std::vector &t_functions, - bool t_dot_notation, - 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)), - 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, + const File_Position &t_where, + const std::string &t_fname, + const std::vector &t_parameters, + const std::vector &t_functions, + bool t_dot_notation, + 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)) + , 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, - const std::vector &t_parameters, const std::vector &t_functions, - bool t_dot_notation, - const chaiscript::detail::Dispatch_Engine &t_ss) noexcept : - 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)) - {} + eval_error(const std::string &t_why, + const std::vector &t_parameters, + const std::vector &t_functions, + bool t_dot_notation, + const chaiscript::detail::Dispatch_Engine &t_ss) noexcept + : 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)) { + } - - 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)), - reason(t_why), start_position(t_where), filename(t_fname) - {} + 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)) + , reason(t_why) + , start_position(t_where) + , filename(t_fname) { + } explicit eval_error(const std::string &t_why) noexcept - : std::runtime_error("Error: \"" + t_why + "\" "), - reason(t_why) - {} + : std::runtime_error("Error: \"" + t_why + "\" ") + , reason(t_why) { + } eval_error(const eval_error &) = default; - std::string pretty_print() const - { + std::string pretty_print() const { std::ostringstream ss; ss << what(); if (!call_stack.empty()) { 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]) << "'"; for (size_t j = 1; j < call_stack.size(); ++j) { - if (id(call_stack[j]) != chaiscript::AST_Node_Type::Block - && id(call_stack[j]) != chaiscript::AST_Node_Type::File) - { + if (id(call_stack[j]) != chaiscript::AST_Node_Type::Block && id(call_stack[j]) != chaiscript::AST_Node_Type::File) { ss << '\n'; 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; private: - template - static AST_Node_Type id(const T& t) noexcept - { - return t.identifier; - } - - template - static std::string pretty(const T& t) - { - return t.pretty_print(); - } - - template - static const std::string &fname(const T& t) noexcept - { - return t.filename(); - } - - template - static std::string startpos(const T& t) - { - std::ostringstream oss; - oss << t.start().line << ", " << t.start().column; - return oss.str(); - } - - static std::string format_why(const std::string &t_why) - { - return "Error: \"" + t_why + "\""; + static AST_Node_Type id(const T &t) noexcept { + return t.identifier; } - static std::string format_types(const Const_Proxy_Function &t_func, - bool t_dot_notation, - const chaiscript::detail::Dispatch_Engine &t_ss) - { + template + static std::string pretty(const T &t) { + return t.pretty_print(); + } + + template + static const std::string &fname(const T &t) noexcept { + return t.filename(); + } + + template + static std::string startpos(const T &t) { + std::ostringstream oss; + oss << t.start().line << ", " << t.start().column; + return oss.str(); + } + + static std::string format_why(const std::string &t_why) { return "Error: \"" + t_why + "\""; } + + static std::string format_types(const Const_Proxy_Function &t_func, bool t_dot_notation, const chaiscript::detail::Dispatch_Engine &t_ss) { assert(t_func); int arity = t_func->get_arity(); std::vector types = t_func->get_param_types(); std::string retval; - if (arity == -1) - { + if (arity == -1) { retval = "(...)"; - if (t_dot_notation) - { + if (t_dot_notation) { retval = "(Object)." + retval; } } else if (types.size() <= 1) { @@ -308,18 +312,13 @@ namespace chaiscript std::string paramstr; - for (size_t index = 1; - index != types.size(); - ++index) - { - paramstr += (types[index].is_const()?"const ":""); + for (size_t index = 1; index != types.size(); ++index) { + paramstr += (types[index].is_const() ? "const " : ""); paramstr += t_ss.get_type_name(types[index]); - if (index == 1 && t_dot_notation) - { + if (index == 1 && t_dot_notation) { paramstr += ").("; - if (types.size() == 2) - { + if (types.size() == 2) { paramstr += ", "; } } else { @@ -333,19 +332,15 @@ namespace chaiscript retval = ss.str(); } + std::shared_ptr dynfun + = std::dynamic_pointer_cast(t_func); - std::shared_ptr dynfun - = std::dynamic_pointer_cast(t_func); - - if (dynfun && dynfun->has_parse_tree()) - { + if (dynfun && dynfun->has_parse_tree()) { Proxy_Function f = dynfun->get_guard(); - if (f) - { + if (f) { auto dynfunguard = std::dynamic_pointer_cast(f); - if (dynfunguard && dynfunguard->has_parse_tree()) - { + if (dynfunguard && dynfunguard->has_parse_tree()) { retval += " : " + format_guard(dynfunguard->get_parse_tree()); } } @@ -357,65 +352,50 @@ namespace chaiscript } template - static std::string format_guard(const T &t) - { - return t.pretty_print(); - } + static std::string format_guard(const T &t) { + return t.pretty_print(); + } template - static std::string format_location(const T &t) - { - std::ostringstream oss; - oss << "(" << t.filename() << " " << t.start().line << ", " << t.start().column << ")"; - return oss.str(); - } + static std::string format_location(const T &t) { + std::ostringstream oss; + oss << "(" << t.filename() << " " << t.start().line << ", " << t.start().column << ")"; + return oss.str(); + } static std::string format_detail(const std::vector &t_functions, - bool t_dot_notation, - const chaiscript::detail::Dispatch_Engine &t_ss) - { + bool t_dot_notation, + const chaiscript::detail::Dispatch_Engine &t_ss) { std::stringstream ss; - if (t_functions.size() == 1) - { + if (t_functions.size() == 1) { assert(t_functions[0]); ss << " Expected: " << format_types(t_functions[0], t_dot_notation, t_ss) << '\n'; } else { 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'; } - } return ss.str(); - } - static std::string format_parameters(const std::vector &t_parameters, - bool t_dot_notation, - const chaiscript::detail::Dispatch_Engine &t_ss) - { + static std::string + format_parameters(const std::vector &t_parameters, bool t_dot_notation, const chaiscript::detail::Dispatch_Engine &t_ss) { std::stringstream ss; ss << "("; - if (!t_parameters.empty()) - { + if (!t_parameters.empty()) { std::string paramstr; - for (auto itr = t_parameters.begin(); - itr != t_parameters.end(); - ++itr) - { - paramstr += (itr->is_const()?"const ":""); + for (auto itr = t_parameters.begin(); itr != t_parameters.end(); ++itr) { + paramstr += (itr->is_const() ? "const " : ""); paramstr += t_ss.type_name(*itr); - if (itr == t_parameters.begin() && t_dot_notation) - { + if (itr == t_parameters.begin() && t_dot_notation) { paramstr += ").("; - if (t_parameters.size() == 1) - { + if (t_parameters.size() == 1) { paramstr += ", "; } } else { @@ -430,12 +410,10 @@ namespace chaiscript 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; - if (t_fname != "__EVAL__") - { + if (t_fname != "__EVAL__") { ss << "in '" << t_fname << "' "; } else { ss << "during evaluation "; @@ -444,16 +422,18 @@ namespace chaiscript 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; ss << "at (" << t_where.line << ", " << t_where.column << ")"; return ss.str(); } - static std::string format(const std::string &t_why, const File_Position &t_where, const std::string &t_fname, - const std::vector &t_parameters, bool t_dot_notation, const chaiscript::detail::Dispatch_Engine &t_ss) - { + static std::string format(const std::string &t_why, + const File_Position &t_where, + const std::string &t_fname, + const std::vector &t_parameters, + bool t_dot_notation, + const chaiscript::detail::Dispatch_Engine &t_ss) { std::stringstream ss; ss << format_why(t_why); @@ -470,11 +450,10 @@ namespace chaiscript return ss.str(); } - static std::string format(const std::string &t_why, - const std::vector &t_parameters, - bool t_dot_notation, - const chaiscript::detail::Dispatch_Engine &t_ss) - { + static std::string format(const std::string &t_why, + const std::vector &t_parameters, + bool t_dot_notation, + const chaiscript::detail::Dispatch_Engine &t_ss) { std::stringstream ss; ss << format_why(t_why); @@ -486,8 +465,7 @@ namespace chaiscript 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; ss << format_why(t_why); @@ -502,13 +480,12 @@ namespace chaiscript } }; - /// Errors generated when loading a file struct file_not_found_error : std::runtime_error { explicit file_not_found_error(const std::string &t_filename) - : std::runtime_error("File Not Found: " + t_filename), - filename(t_filename) - { } + : std::runtime_error("File Not Found: " + t_filename) + , filename(t_filename) { + } file_not_found_error(const file_not_found_error &) = default; ~file_not_found_error() noexcept override = default; @@ -516,258 +493,204 @@ namespace chaiscript std::string filename; }; - } + } // namespace exception - /// \brief Struct that doubles as both a parser ast_node and an AST node. struct AST_Node { - public: - const AST_Node_Type identifier; - const std::string text; - Parse_Location location; - - const std::string &filename() const noexcept { - return *location.filename; - } - - const File_Position &start() const noexcept { - return location.start; - } - - const File_Position &end() const noexcept { - return location.end; - } - - std::string pretty_print() const - { - std::ostringstream oss; - - oss << text; - - for (auto & elem : get_children()) { - oss << elem.get().pretty_print() << ' '; - } - - return oss.str(); - } - - virtual std::vector> get_children() 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 - std::string to_string(const std::string &t_prepend = "") const { - std::ostringstream oss; - - oss << t_prepend << "(" << ast_node_type_to_string(this->identifier) << ") " - << this->text << " : " << this->location.start.line << ", " << this->location.start.column << '\n'; - - for (auto & elem : get_children()) { - oss << elem.get().to_string(t_prepend + " "); - } - return oss.str(); - } - - - static bool get_bool_condition(const Boxed_Value &t_bv, const chaiscript::detail::Dispatch_State &t_ss) { - try { - return t_ss->boxed_cast(t_bv); - } - catch (const exception::bad_boxed_cast &) { - throw exception::eval_error("Condition not boolean"); - } - } - - - virtual ~AST_Node() noexcept = default; - AST_Node(AST_Node &&) = default; - AST_Node &operator=(AST_Node &&) = delete; - AST_Node(const AST_Node &) = delete; - AST_Node& operator=(const AST_Node &) = delete; - - - protected: - 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)), - location(std::move(t_loc)) - { - } - - - }; - - struct AST_Node_Trace - { + public: const AST_Node_Type identifier; const std::string text; Parse_Location location; - const std::string &filename() const noexcept { - return *location.filename; - } + const std::string &filename() const noexcept { return *location.filename; } - const File_Position &start() const noexcept { - return location.start; - } + const File_Position &start() const noexcept { return location.start; } - const File_Position &end() const noexcept { - return location.end; - } + const File_Position &end() const noexcept { return location.end; } - std::string pretty_print() const - { + std::string pretty_print() const { std::ostringstream oss; oss << text; - for (const auto & elem : children) { + for (auto &elem : get_children()) { + oss << elem.get().pretty_print() << ' '; + } + + return oss.str(); + } + + virtual std::vector> get_children() 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 + std::string to_string(const std::string &t_prepend = "") const { + std::ostringstream oss; + + oss << t_prepend << "(" << ast_node_type_to_string(this->identifier) << ") " << this->text << " : " << this->location.start.line + << ", " << this->location.start.column << '\n'; + + for (auto &elem : get_children()) { + oss << elem.get().to_string(t_prepend + " "); + } + return oss.str(); + } + + static bool get_bool_condition(const Boxed_Value &t_bv, const chaiscript::detail::Dispatch_State &t_ss) { + try { + return t_ss->boxed_cast(t_bv); + } catch (const exception::bad_boxed_cast &) { + throw exception::eval_error("Condition not boolean"); + } + } + + virtual ~AST_Node() noexcept = default; + AST_Node(AST_Node &&) = default; + AST_Node &operator=(AST_Node &&) = delete; + AST_Node(const AST_Node &) = delete; + AST_Node &operator=(const AST_Node &) = delete; + + protected: + 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)) + , location(std::move(t_loc)) { + } + }; + + struct AST_Node_Trace { + const AST_Node_Type identifier; + const std::string text; + Parse_Location location; + + const std::string &filename() const noexcept { return *location.filename; } + + const File_Position &start() const noexcept { return location.start; } + + const File_Position &end() const noexcept { return location.end; } + + std::string pretty_print() const { + std::ostringstream oss; + + oss << text; + + for (const auto &elem : children) { oss << elem.pretty_print() << ' '; } return oss.str(); } - std::vector get_children(const AST_Node &node) - { + std::vector get_children(const AST_Node &node) { const auto node_children = node.get_children(); return std::vector(node_children.begin(), node_children.end()); } AST_Node_Trace(const AST_Node &node) - : identifier(node.identifier), text(node.text), - location(node.location), children(get_children(node)) - { + : identifier(node.identifier) + , text(node.text) + , location(node.location) + , children(get_children(node)) { } - std::vector children; - }; namespace parser { - class ChaiScript_Parser_Base - { - public: - 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 *get_tracer_ptr() = 0; - virtual ~ChaiScript_Parser_Base() = default; - ChaiScript_Parser_Base() = default; - ChaiScript_Parser_Base(ChaiScript_Parser_Base &&) = default; - ChaiScript_Parser_Base &operator=(ChaiScript_Parser_Base &&) = delete; - ChaiScript_Parser_Base &operator=(const ChaiScript_Parser_Base &&) = delete; + class ChaiScript_Parser_Base { + public: + 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 *get_tracer_ptr() = 0; + virtual ~ChaiScript_Parser_Base() = default; + ChaiScript_Parser_Base() = default; + ChaiScript_Parser_Base(ChaiScript_Parser_Base &&) = default; + ChaiScript_Parser_Base &operator=(ChaiScript_Parser_Base &&) = delete; + ChaiScript_Parser_Base &operator=(const ChaiScript_Parser_Base &&) = delete; - template - T &get_tracer() noexcept - { - // to do type check this somehow? - return *static_cast(get_tracer_ptr()); - } + template + T &get_tracer() noexcept { + // to do type check this somehow? + return *static_cast(get_tracer_ptr()); + } - protected: - ChaiScript_Parser_Base(const ChaiScript_Parser_Base &) = default; + protected: + ChaiScript_Parser_Base(const ChaiScript_Parser_Base &) = default; }; - } + } // namespace parser - namespace eval - { - namespace detail - { + namespace eval { + namespace detail { /// Special type for returned values struct Return_Value { Boxed_Value retval; }; - /// Special type indicating a call to 'break' struct Break_Loop { }; - /// Special type indicating a call to 'continue' struct Continue_Loop { }; - /// 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& operator=(Scope_Push_Pop &&) = delete; + Scope_Push_Pop &operator=(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) - : m_ds(t_ds) - { + : m_ds(t_ds) { m_ds->new_scope(m_ds.stack_holder()); } - ~Scope_Push_Pop() - { - m_ds->pop_scope(m_ds.stack_holder()); - } + ~Scope_Push_Pop() { m_ds->pop_scope(m_ds.stack_holder()); } - - private: - const chaiscript::detail::Dispatch_State &m_ds; + private: + const chaiscript::detail::Dispatch_State &m_ds; }; /// 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& operator=(Function_Push_Pop &&) = delete; + Function_Push_Pop &operator=(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) - : m_ds(t_ds) - { + : m_ds(t_ds) { m_ds->new_function_call(m_ds.stack_holder(), m_ds.conversion_saves()); } - ~Function_Push_Pop() - { - m_ds->pop_function_call(m_ds.stack_holder(), m_ds.conversion_saves()); - } + ~Function_Push_Pop() { 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: - const chaiscript::detail::Dispatch_State &m_ds; + private: + const chaiscript::detail::Dispatch_State &m_ds; }; /// 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& operator=(Stack_Push_Pop &&) = delete; + Stack_Push_Pop &operator=(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) - : m_ds(t_ds) - { + : m_ds(t_ds) { m_ds->new_stack(m_ds.stack_holder()); } - ~Stack_Push_Pop() - { - m_ds->pop_stack(m_ds.stack_holder()); - } + ~Stack_Push_Pop() { m_ds->pop_stack(m_ds.stack_holder()); } - - private: - const chaiscript::detail::Dispatch_State &m_ds; + private: + const chaiscript::detail::Dispatch_State &m_ds; }; - } - } -} + } // namespace detail + } // namespace eval +} // namespace chaiscript #endif /* _CHAISCRIPT_COMMON_HPP */ - diff --git a/include/chaiscript/language/chaiscript_engine.hpp b/include/chaiscript/language/chaiscript_engine.hpp index 6fc74334..9950ec50 100644 --- a/include/chaiscript/language/chaiscript_engine.hpp +++ b/include/chaiscript/language/chaiscript_engine.hpp @@ -7,11 +7,11 @@ // This is an open source non-commercial project. Dear PVS-Studio, please check it. // PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com - #ifndef CHAISCRIPT_ENGINE_HPP_ #define CHAISCRIPT_ENGINE_HPP_ #include +#include #include #include #include @@ -21,15 +21,15 @@ #include #include #include -#include #include "../chaiscript_defines.hpp" #include "../chaiscript_threading.hpp" #include "../dispatchkit/boxed_cast_helper.hpp" #include "../dispatchkit/boxed_value.hpp" #include "../dispatchkit/dispatchkit.hpp" -#include "../dispatchkit/type_conversions.hpp" #include "../dispatchkit/proxy_functions.hpp" +#include "../dispatchkit/register_function.hpp" +#include "../dispatchkit/type_conversions.hpp" #include "chaiscript_common.hpp" #if defined(__linux__) || defined(__unix__) || defined(__APPLE__) || defined(__HAIKU__) @@ -50,23 +50,18 @@ #include "chaiscript_unknown.hpp" #endif - #include "../dispatchkit/exception_specification.hpp" -namespace chaiscript -{ - /// Namespace alias to provide cleaner and more explicit syntax to users. - using Namespace = dispatch::Dynamic_Object; +namespace chaiscript { + /// Namespace alias to provide cleaner and more explicit syntax to users. + using Namespace = dispatch::Dynamic_Object; - namespace detail - { + namespace detail { using Loadable_Module_Ptr = std::shared_ptr; } - /// \brief The main object that the ChaiScript user will use. class ChaiScript_Basic { - mutable chaiscript::detail::threading::shared_mutex m_mutex; mutable chaiscript::detail::threading::recursive_mutex m_use_mutex; @@ -81,26 +76,21 @@ namespace chaiscript chaiscript::detail::Dispatch_Engine m_engine; - std::map> m_namespace_generators; + std::map> m_namespace_generators; /// 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 { const auto p = m_parser->parse(t_input, t_filename); 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; } } - - /// Evaluates the given file and looks in the 'use' paths 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 { const auto appendedpath = path + t_filename; return do_eval(load_file(appendedpath), appendedpath, true); @@ -113,11 +103,8 @@ namespace chaiscript // failed to load by any name throw exception::file_not_found_error(t_filename); - } - - /// Evaluates the given string, used during eval() inside of a script Boxed_Value internal_eval(const std::string &t_e) { try { @@ -128,108 +115,94 @@ namespace chaiscript } /// Returns the current evaluation m_engine - chaiscript::detail::Dispatch_Engine &get_eval_engine() noexcept { - return m_engine; - } + chaiscript::detail::Dispatch_Engine &get_eval_engine() noexcept { return m_engine; } /// 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 &t_opts) { - if (t_lib) - { + if (t_lib) { add(t_lib); } - 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, 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 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_scripting_objects(); }), "get_objects"); + 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, 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 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_scripting_objects(); }), "get_objects"); - m_engine.add( - dispatch::make_dynamic_proxy_function( - [this](const Function_Params &t_params) { - return m_engine.call_exists(t_params); - }) - , "call_exists"); + m_engine.add(dispatch::make_dynamic_proxy_function([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 &t_params) -> Boxed_Value { + Type_Conversions_State s(this->m_engine.conversions(), this->m_engine.conversions().conversion_saves()); + return t_fun(Function_Params{t_params}, s); + }), + "call"); - m_engine.add(fun( - [this](const dispatch::Proxy_Function_Base &t_fun, const std::vector &t_params) -> Boxed_Value { - Type_Conversions_State s(this->m_engine.conversions(), this->m_engine.conversions().conversion_saves()); - return t_fun(Function_Params{t_params}, s); - }), "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 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 Type_Info &t_from, const Type_Info &t_to, const std::function &t_func) { - m_engine.add(chaiscript::type_conversion(t_from, t_to, t_func)); - } - ), "add_type_conversion"); + 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 Type_Info &t_from, const Type_Info &t_to, const std::function &t_func) { + m_engine.add(chaiscript::type_conversion(t_from, t_to, t_func)); + }), + "add_type_conversion"); 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()) - { - 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"); + && 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) { return load_module(t_module); }), "load_module"); } 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()) - { - 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"); + && 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 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 AST_Node &t_ast){ return eval(t_ast); }), "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 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, 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 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){ set_global(t_bv, t_name); }), "set_global"); + 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) { set_global(t_bv, t_name); }), "set_global"); // why this unused parameter to Namespace? - m_engine.add(fun([this](const std::string& t_namespace_name) { register_namespace([] (Namespace& /*space*/) 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"); + 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) { import(t_namespace_name); }), "import"); } /// Skip BOM at the beginning of file static bool skip_bom(std::ifstream &infile) { - size_t bytes_needed = 3; - char buffer[3]; + size_t bytes_needed = 3; + char buffer[3]; - memset(buffer, '\0', bytes_needed); + memset(buffer, '\0', bytes_needed); - infile.read(buffer, static_cast(bytes_needed)); + infile.read(buffer, static_cast(bytes_needed)); - if ((buffer[0] == '\xef') - && (buffer[1] == '\xbb') - && (buffer[2] == '\xbf')) { + if ((buffer[0] == '\xef') && (buffer[1] == '\xbb') && (buffer[2] == '\xbf')) { + infile.seekg(3); + return true; + } - infile.seekg(3); - return true; - } + infile.seekg(0); - infile.seekg(0); - - return false; + return false; } /// Helper function for loading a file 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()) { throw chaiscript::exception::file_not_found_error(t_filename); @@ -241,12 +214,11 @@ namespace chaiscript assert(size >= 0); if (skip_bom(infile)) { - 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 + 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 } - if (size == std::streampos(0)) - { + if (size == std::streampos(0)) { return std::string(); } else { std::vector v(static_cast(size)); @@ -255,14 +227,15 @@ namespace chaiscript } } - std::vector ensure_minimum_path_vec(std::vector paths) - { - if (paths.empty()) { return {""}; } - else { return paths; } + std::vector ensure_minimum_path_vec(std::vector paths) { + if (paths.empty()) { + return {""}; + } else { + return paths; + } } public: - /// \brief Constructor for ChaiScript /// \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 @@ -272,42 +245,38 @@ namespace chaiscript std::vector t_module_paths = {}, std::vector t_use_paths = {}, const std::vector &t_opts = chaiscript::default_options()) - : 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_parser(std::move(parser)), - m_engine(*m_parser) - { + : 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_parser(std::move(parser)) + , m_engine(*m_parser) { #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 // as windows would do - union cast_union - { - Boxed_Value (ChaiScript_Basic::*in_ptr)(const std::string&); + union cast_union { + Boxed_Value (ChaiScript_Basic::*in_ptr)(const std::string &); void *out_ptr; }; - Dl_info rInfo; - memset( &rInfo, 0, sizeof(rInfo) ); + Dl_info rInfo; + memset(&rInfo, 0, sizeof(rInfo)); cast_union u; u.in_ptr = &ChaiScript_Basic::use; - if ( (dladdr(static_cast(u.out_ptr), &rInfo) != 0) && (rInfo.dli_fname != nullptr) ) { + if ((dladdr(static_cast(u.out_ptr), &rInfo) != 0) && (rInfo.dli_fname != nullptr)) { std::string dllpath(rInfo.dli_fname); const size_t lastslash = dllpath.rfind('/'); - if (lastslash != std::string::npos) - { + if (lastslash != std::string::npos) { dllpath.erase(lastslash); } // Let's see if this is a link that we should expand std::vector buf(2048); const auto pathlen = readlink(dllpath.c_str(), &buf.front(), buf.size()); - if (pathlen > 0 && static_cast(pathlen) < buf.size()) - { + if (pathlen > 0 && static_cast(pathlen) < buf.size()) { dllpath = std::string(&buf.front(), static_cast(pathlen)); } - m_module_paths.insert(m_module_paths.begin(), dllpath+"/"); + m_module_paths.insert(m_module_paths.begin(), dllpath + "/"); } #endif build_eval_system(t_lib, t_opts); @@ -315,30 +284,28 @@ namespace chaiscript #ifndef CHAISCRIPT_NO_DYNLOAD /// \brief Constructor for ChaiScript. - /// + /// /// This version of the ChaiScript constructor attempts to find the stdlib module to load /// at runtime generates an error if it cannot be found. /// /// \param[in] t_modulepaths Vector of paths to search when attempting to load a binary module /// \param[in] t_usepaths Vector of paths to search when attempting to "use" an included ChaiScript file explicit ChaiScript_Basic(std::unique_ptr &&parser, - std::vector t_module_paths = {}, - std::vector t_use_paths = {}, - const std::vector &t_opts = chaiscript::default_options()) - : ChaiScript_Basic({}, std::move(parser), t_module_paths, t_use_paths, t_opts) - { + std::vector t_module_paths = {}, + std::vector t_use_paths = {}, + const std::vector &t_opts = chaiscript::default_options()) + : ChaiScript_Basic({}, std::move(parser), t_module_paths, t_use_paths, t_opts) { try { // attempt to load the stdlib load_module("chaiscript_stdlib-" + Build_Info::version()); } catch (const exception::load_module_error &t_err) { - std::cout << "An error occured while trying to load the chaiscript standard library.\n" - << "\n" - << "You must either provide a standard library, or compile it in.\n" - << "For an example of compiling the standard library in,\n" - << "see: https://gist.github.com/lefticus/9456197\n" - << "Compiling the stdlib in is the recommended and MOST SUPPORTED method.\n" - << "\n" - << "\n" + std::cout << "An error occurred while trying to load the chaiscript standard library.\n" + "\n" + "You must either provide a standard library, or compile it in.\n" + "For an example of compiling the standard library in,\n" + "see: https://gist.github.com/lefticus/9456197\n" + "Compiling the stdlib in is the recommended and MOST SUPPORTED method.\n" + "\n\n" << t_err.what(); throw; } @@ -347,16 +314,15 @@ namespace chaiscript explicit ChaiScript_Basic(std::unique_ptr &&parser, std::vector t_module_paths = {}, std::vector t_use_paths = {}, - const std::vector &t_opts = chaiscript::default_options()) = delete; + const std::vector &t_opts = chaiscript::default_options()) + = delete; #endif - parser::ChaiScript_Parser_Base &get_parser() noexcept - { + parser::ChaiScript_Parser_Base &get_parser() noexcept { return *m_parser; } - const Boxed_Value eval(const AST_Node &t_ast) - { + const Boxed_Value eval(const AST_Node &t_ast) { try { return t_ast.eval(chaiscript::detail::Dispatch_State(m_engine)); } 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"); if (t_debug_print) { m_parser->debug_print(*ast); @@ -373,38 +338,28 @@ namespace chaiscript 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 - std::string get_type_name() const - { + std::string get_type_name() const { return get_type_name(user_type()); } - /// \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. /// /// \param[in] t_filename Filename to load and evaluate - Boxed_Value use(const std::string &t_filename) - { - for (const auto &path : m_use_paths) - { + Boxed_Value use(const std::string &t_filename) { + for (const auto &path : m_use_paths) { const auto appendedpath = path + t_filename; try { - chaiscript::detail::threading::unique_lock l(m_use_mutex); chaiscript::detail::threading::unique_lock l2(m_mutex); Boxed_Value retval; - if (m_used_files.count(appendedpath) == 0) - { + if (m_used_files.count(appendedpath) == 0) { l2.unlock(); retval = eval_file(appendedpath); l2.lock(); @@ -430,8 +385,7 @@ namespace chaiscript /// \param[in] t_name Name of the value to add /// \throw chaiscript::exception::global_non_const If t_bv is not a constant object /// \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); m_engine.add_global_const(t_bv, t_name); return *this; @@ -442,15 +396,13 @@ namespace chaiscript /// \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 /// 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); m_engine.add_global(t_bv, t_name); 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); m_engine.set_global(t_bv, t_name); return *this; @@ -461,8 +413,7 @@ namespace chaiscript /// are left out due to performance considerations involved in tracking the state /// \sa ChaiScript::get_state /// \sa ChaiScript::set_state - struct State - { + struct State { std::set used_files; chaiscript::detail::Dispatch_Engine::State engine_state; std::set active_loaded_modules; @@ -481,8 +432,7 @@ namespace chaiscript /// chaiscript::ChaiScript chai; /// chaiscript::ChaiScript::State s = chai.get_state(); // represents bootstrapped initial state /// \endcode - State get_state() const - { + State get_state() const { chaiscript::detail::threading::lock_guard l(m_use_mutex); chaiscript::detail::threading::shared_lock l2(m_mutex); @@ -507,8 +457,7 @@ namespace chaiscript /// chai.add(chaiscript::fun(&somefunction), "somefunction"); /// chai.set_state(s); // restore initial state, which does not have the recently added "somefunction" /// \endcode - void set_state(const State &t_state) - { + void set_state(const State &t_state) { chaiscript::detail::threading::lock_guard l(m_use_mutex); chaiscript::detail::threading::shared_lock l2(m_mutex); @@ -518,26 +467,20 @@ namespace chaiscript } /// \returns All values in the local thread state, added through the add() function - std::map get_locals() const - { - return m_engine.get_locals(); - } + std::map get_locals() const { return m_engine.get_locals(); } /// \brief Sets all of the locals for the current thread state. /// /// \param[in] t_locals The map set of variables to replace the current state with /// /// Any existing locals are removed and the given set of variables is added - void set_locals(const std::map &t_locals) - { - m_engine.set_locals(t_locals); - } + void set_locals(const std::map &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. /// \param[in] t_t Item to add /// \param[in] t_name Name of item to add /// \returns Reference to current ChaiScript object - /// + /// /// \b Examples: /// \code /// chaiscript::ChaiScript chai; @@ -549,8 +492,7 @@ namespace chaiscript /// /// \sa \ref adding_items template - 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); m_engine.add(t_t, t_name); return *this; @@ -558,15 +500,14 @@ namespace chaiscript /// \brief Add a new conversion for upcasting to a base class /// \sa chaiscript::base_class - /// \param[in] d Base class / parent class + /// \param[in] d Base class / parent class /// /// \b Example: /// \code /// chaiscript::ChaiScript chai; /// chai.add(chaiscript::base_class()); /// \endcode - ChaiScript_Basic &add(const Type_Conversion &d) - { + ChaiScript_Basic &add(const Type_Conversion &d) { m_engine.add(d); return *this; } @@ -574,8 +515,7 @@ namespace chaiscript /// \brief Adds all elements of a module to ChaiScript runtime /// \param[in] t_p The module to add. /// \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()); return *this; } @@ -588,20 +528,18 @@ namespace chaiscript /// and with standard prefixes and postfixes: ("lib"|"")\(".dll"|".so"|".bundle"|""). /// /// Once the file is located, the system looks for the symbol "create_chaiscript_module_\". - /// If no file can be found matching the search criteria and containing the appropriate entry point + /// If no file can be found matching the search criteria and containing the appropriate entry point /// (the symbol mentioned above), an exception is thrown. /// /// \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 throw chaiscript::exception::load_module_error("Loadable module support was disabled (CHAISCRIPT_NO_DYNLOAD)"); #else std::vector errors; std::string version_stripped_name = t_module_name; 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); } @@ -609,12 +547,9 @@ namespace chaiscript std::vector postfixes{".dll", ".so", ".bundle", ""}; - for (auto & elem : m_module_paths) - { - for (auto & prefix : prefixes) - { - for (auto & postfix : postfixes) - { + for (auto &elem : m_module_paths) { + for (auto &prefix : prefixes) { + for (auto &postfix : postfixes) { try { const auto name = elem + prefix + t_module_name + postfix; // 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 /// /// \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 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)); m_loaded_modules[t_module_name] = lm; m_active_loaded_modules.insert(t_module_name); @@ -653,20 +586,18 @@ namespace chaiscript } else if (m_active_loaded_modules.count(t_module_name) == 0) { m_active_loaded_modules.insert(t_module_name); add(m_loaded_modules[t_module_name]->m_moduleptr); - } + } } - /// \brief Evaluates a string. Equivalent to ChaiScript::eval. /// /// \param[in] t_script Script to execute /// \param[in] t_handler Optional Exception_Handler used for automatic unboxing of script thrown exceptions /// /// \return result of the script execution - /// + /// /// \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); } @@ -679,23 +610,20 @@ namespace chaiscript /// in special cases where you are loading a file internally instead of using eval_file /// /// \return result of the script execution - /// + /// /// \throw chaiscript::exception::eval_error In the case that evaluation fails. /// \throw chaiscript::exception::bad_boxed_cast In the case that evaluation succeeds but the result value cannot be converted /// to the requested type. template - 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(eval(t_input, t_handler, t_filename)); } /// \brief casts an object while applying any Dynamic_Conversion available template - decltype(auto) boxed_cast(const Boxed_Value &bv) const - { - return(m_engine.boxed_cast(bv)); - } - + decltype(auto) boxed_cast(const Boxed_Value &bv) const { + return (m_engine.boxed_cast(bv)); + } /// \brief Evaluates a string. /// @@ -705,10 +633,10 @@ namespace chaiscript /// in special cases where you are loading a file internally instead of using eval_file /// /// \return result of the script execution - /// + /// /// \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 { return do_eval(t_input, t_filename); } catch (Boxed_Value &bv) { @@ -744,39 +672,35 @@ namespace chaiscript /// \brief Imports a namespace object into the global scope of this ChaiScript instance. /// \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. - void import(const std::string& t_namespace_name) - { - chaiscript::detail::threading::unique_lock l(m_use_mutex); + void import(const std::string &t_namespace_name) { + chaiscript::detail::threading::unique_lock l(m_use_mutex); - if (m_engine.get_scripting_objects().count(t_namespace_name)) { - throw std::runtime_error("Namespace: " + t_namespace_name + " was already defined"); - } - 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); - } - else { - throw std::runtime_error("No registered namespace: " + t_namespace_name); - } + if (m_engine.get_scripting_objects().count(t_namespace_name)) { + throw std::runtime_error("Namespace: " + t_namespace_name + " was already defined"); + } 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); + } else { + 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. - /// \param[in] t_namespace_generator Namespace generator function. - /// \param[in] t_namespace_name Name of the Namespace function being registered. - /// \throw std::runtime_error In the case that the namespace name was already registered. - void register_namespace(const std::function& t_namespace_generator, const std::string& t_namespace_name) - { - chaiscript::detail::threading::unique_lock l(m_use_mutex); + /// \brief Registers a namespace generator, which delays generation of the namespace until it is imported, saving memory if it is never + /// used. \param[in] t_namespace_generator Namespace generator function. \param[in] t_namespace_name Name of the Namespace function + /// being registered. \throw std::runtime_error In the case that the namespace name was already registered. + void register_namespace(const std::function &t_namespace_generator, const std::string &t_namespace_name) { + chaiscript::detail::threading::unique_lock l(m_use_mutex); - if (!m_namespace_generators.count(t_namespace_name)) { - // 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; })); - } - else { - throw std::runtime_error("Namespace: " + t_namespace_name + " was already registered."); - } + if (!m_namespace_generators.count(t_namespace_name)) { + // 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; + })); + } else { + throw std::runtime_error("Namespace: " + t_namespace_name + " was already registered."); + } } }; -} +} // namespace chaiscript #endif /* CHAISCRIPT_ENGINE_HPP_ */ - diff --git a/include/chaiscript/language/chaiscript_eval.hpp b/include/chaiscript/language/chaiscript_eval.hpp index 97069944..4997d667 100644 --- a/include/chaiscript/language/chaiscript_eval.hpp +++ b/include/chaiscript/language/chaiscript_eval.hpp @@ -7,7 +7,6 @@ // This is an open source non-commercial project. Dear PVS-Studio, please check it. // PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com - #ifndef CHAISCRIPT_EVAL_HPP_ #define CHAISCRIPT_EVAL_HPP_ @@ -35,29 +34,31 @@ #include "chaiscript_common.hpp" namespace chaiscript::exception { -class bad_boxed_cast; -} // namespace chaiscript::exception + class bad_boxed_cast; +} // namespace chaiscript::exception -namespace chaiscript -{ +namespace chaiscript { /// \brief Classes and functions that are part of the runtime eval system - namespace eval - { - template struct AST_Node_Impl; + namespace eval { + template + struct AST_Node_Impl; - template using AST_Node_Impl_Ptr = typename std::unique_ptr>; + template + using AST_Node_Impl_Ptr = typename std::unique_ptr>; - namespace detail - { + namespace detail { /// Helper function that will set up the scope around a function call, including handling the named function parameters template - Boxed_Value eval_function(chaiscript::detail::Dispatch_Engine &t_ss, const AST_Node_Impl &t_node, const std::vector &t_param_names, const Function_Params &t_vals, const std::map *t_locals=nullptr, bool has_this_capture = false) { + Boxed_Value eval_function(chaiscript::detail::Dispatch_Engine &t_ss, + const AST_Node_Impl &t_node, + const std::vector &t_param_names, + const Function_Params &t_vals, + const std::map *t_locals = nullptr, + bool has_this_capture = false) { chaiscript::detail::Dispatch_State state(t_ss); - const Boxed_Value *thisobj = [&]() -> const Boxed_Value *{ - if (auto &stack = t_ss.get_stack_data(state.stack_holder()).back(); - !stack.empty() && stack.back().first == "__this") - { + const Boxed_Value *thisobj = [&]() -> const Boxed_Value * { + if (auto &stack = t_ss.get_stack_data(state.stack_holder()).back(); !stack.empty() && stack.back().first == "__this") { return &stack.back().second; } else if (!t_vals.empty()) { return &t_vals[0]; @@ -67,7 +68,9 @@ namespace chaiscript }(); chaiscript::eval::detail::Stack_Push_Pop tpp(state); - if (thisobj && !has_this_capture) { state.add_object("this", *thisobj); } + if (thisobj && !has_this_capture) { + state.add_object("this", *thisobj); + } if (t_locals) { for (const auto &[name, value] : *t_locals) { @@ -88,14 +91,12 @@ namespace chaiscript } } - inline Boxed_Value clone_if_necessary(Boxed_Value incoming, std::atomic_uint_fast32_t &t_loc, const chaiscript::detail::Dispatch_State &t_ss) - { - if (!incoming.is_return_value()) - { + inline Boxed_Value clone_if_necessary(Boxed_Value incoming, std::atomic_uint_fast32_t &t_loc, const chaiscript::detail::Dispatch_State &t_ss) { + if (!incoming.is_return_value()) { if (incoming.get_type_info().is_arithmetic()) { return Boxed_Number::clone(incoming); } else if (incoming.get_type_info().bare_equal_type_info(typeid(bool))) { - return Boxed_Value(*static_cast(incoming.get_const_ptr())); + return Boxed_Value(*static_cast(incoming.get_const_ptr())); } else if (incoming.get_type_info().bare_equal_type_info(typeid(std::string))) { return Boxed_Value(*static_cast(incoming.get_const_ptr())); } else { @@ -107,16 +108,16 @@ namespace chaiscript return incoming; } } - } + } // namespace detail template - struct AST_Node_Impl : AST_Node - { - AST_Node_Impl(std::string t_ast_node_text, AST_Node_Type t_id, Parse_Location t_loc, - std::vector> t_children = std::vector>()) - : AST_Node(std::move(t_ast_node_text), t_id, std::move(t_loc)), - children(std::move(t_children)) - { + struct AST_Node_Impl : AST_Node { + AST_Node_Impl(std::string t_ast_node_text, + AST_Node_Type t_id, + Parse_Location t_loc, + std::vector> t_children = std::vector>()) + : AST_Node(std::move(t_ast_node_text), t_id, std::move(t_loc)) + , children(std::move(t_children)) { } static bool get_scoped_bool_condition(const AST_Node_Impl &node, const chaiscript::detail::Dispatch_State &t_ss) { @@ -124,7 +125,6 @@ namespace chaiscript return get_bool_condition(node.eval(t_ss), t_ss); } - std::vector> get_children() const final { std::vector> retval; retval.reserve(children.size()); @@ -135,8 +135,7 @@ namespace chaiscript return retval; } - Boxed_Value eval(const chaiscript::detail::Dispatch_State &t_e) const final - { + Boxed_Value eval(const chaiscript::detail::Dispatch_State &t_e) const final { try { T::trace(t_e, this); return eval_internal(t_e); @@ -148,1416 +147,1348 @@ namespace chaiscript std::vector> children; - protected: - virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &) const - { - throw std::runtime_error("Undispatched ast_node (internal error)"); - } + protected: + virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &) const { + throw std::runtime_error("Undispatched ast_node (internal error)"); + } }; - template struct Compiled_AST_Node : AST_Node_Impl { - Compiled_AST_Node(AST_Node_Impl_Ptr t_original_node, std::vector> t_children, - std::function> &, const chaiscript::detail::Dispatch_State &t_ss)> t_func) : - AST_Node_Impl(t_original_node->text, AST_Node_Type::Compiled, t_original_node->location, std::move(t_children)), - m_func(std::move(t_func)), - m_original_node(std::move(t_original_node)) - { } + Compiled_AST_Node(AST_Node_Impl_Ptr t_original_node, + std::vector> t_children, + std::function> &, const chaiscript::detail::Dispatch_State &t_ss)> t_func) + : AST_Node_Impl(t_original_node->text, AST_Node_Type::Compiled, t_original_node->location, std::move(t_children)) + , m_func(std::move(t_func)) + , m_original_node(std::move(t_original_node)) { + } - Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override { - return m_func(this->children, t_ss); - } + Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override { return m_func(this->children, t_ss); } - std::function> &, const chaiscript::detail::Dispatch_State &t_ss)> m_func; - AST_Node_Impl_Ptr m_original_node; + std::function> &, const chaiscript::detail::Dispatch_State &t_ss)> m_func; + AST_Node_Impl_Ptr m_original_node; }; - template struct Fold_Right_Binary_Operator_AST_Node : AST_Node_Impl { - Fold_Right_Binary_Operator_AST_Node(const std::string &t_oper, Parse_Location t_loc, std::vector> t_children, Boxed_Value t_rhs) : - AST_Node_Impl(t_oper, AST_Node_Type::Binary, std::move(t_loc), std::move(t_children)), - m_oper(Operators::to_operator(t_oper)), - m_rhs(std::move(t_rhs)) - { } + Fold_Right_Binary_Operator_AST_Node(const std::string &t_oper, Parse_Location t_loc, std::vector> t_children, Boxed_Value t_rhs) + : AST_Node_Impl(t_oper, AST_Node_Type::Binary, std::move(t_loc), std::move(t_children)) + , m_oper(Operators::to_operator(t_oper)) + , m_rhs(std::move(t_rhs)) { + } - Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override { - return do_oper(t_ss, this->text, this->children[0]->eval(t_ss)); - } + Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override { + return do_oper(t_ss, this->text, this->children[0]->eval(t_ss)); + } - protected: - Boxed_Value do_oper(const chaiscript::detail::Dispatch_State &t_ss, - const std::string &t_oper_string, const Boxed_Value &t_lhs) const - { - try { - if (t_lhs.get_type_info().is_arithmetic()) - { - // If it's an arithmetic operation we want to short circuit dispatch - try{ - return Boxed_Number::do_oper(m_oper, t_lhs, m_rhs); - } catch (const chaiscript::exception::arithmetic_error &) { - throw; - } catch (...) { - throw exception::eval_error("Error with numeric operator calling: " + t_oper_string); - } - } else { - chaiscript::eval::detail::Function_Push_Pop fpp(t_ss); - std::array params{t_lhs, m_rhs}; - fpp.save_params(Function_Params{params}); - return t_ss->call_function(t_oper_string, m_loc, Function_Params{params}, t_ss.conversions()); + protected: + Boxed_Value do_oper(const chaiscript::detail::Dispatch_State &t_ss, const std::string &t_oper_string, const Boxed_Value &t_lhs) const { + try { + if (t_lhs.get_type_info().is_arithmetic()) { + // If it's an arithmetic operation we want to short circuit dispatch + try { + return Boxed_Number::do_oper(m_oper, t_lhs, m_rhs); + } catch (const chaiscript::exception::arithmetic_error &) { + throw; + } catch (...) { + throw exception::eval_error("Error with numeric operator calling: " + t_oper_string); } + } else { + chaiscript::eval::detail::Function_Push_Pop fpp(t_ss); + std::array params{t_lhs, m_rhs}; + fpp.save_params(Function_Params{params}); + return t_ss->call_function(t_oper_string, m_loc, Function_Params{params}, t_ss.conversions()); } - catch(const exception::dispatch_error &e){ - throw exception::eval_error("Can not find appropriate '" + t_oper_string + "' operator.", e.parameters, e.functions, false, *t_ss); - } + } catch (const exception::dispatch_error &e) { + throw exception::eval_error("Can not find appropriate '" + t_oper_string + "' operator.", e.parameters, e.functions, false, *t_ss); } + } - private: - Operators::Opers m_oper; - Boxed_Value m_rhs; - mutable std::atomic_uint_fast32_t m_loc = {0}; + private: + Operators::Opers m_oper; + Boxed_Value m_rhs; + mutable std::atomic_uint_fast32_t m_loc = {0}; }; - template struct Binary_Operator_AST_Node : AST_Node_Impl { - Binary_Operator_AST_Node(const std::string &t_oper, Parse_Location t_loc, std::vector> t_children) : - AST_Node_Impl(t_oper, AST_Node_Type::Binary, std::move(t_loc), std::move(t_children)), - m_oper(Operators::to_operator(t_oper)) - { } + Binary_Operator_AST_Node(const std::string &t_oper, Parse_Location t_loc, std::vector> t_children) + : AST_Node_Impl(t_oper, AST_Node_Type::Binary, std::move(t_loc), std::move(t_children)) + , m_oper(Operators::to_operator(t_oper)) { + } - Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override { - auto lhs = this->children[0]->eval(t_ss); - auto rhs = this->children[1]->eval(t_ss); - return do_oper(t_ss, m_oper, this->text, lhs, rhs); - } + Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override { + auto lhs = this->children[0]->eval(t_ss); + auto rhs = this->children[1]->eval(t_ss); + return do_oper(t_ss, m_oper, this->text, lhs, rhs); + } - protected: - Boxed_Value do_oper(const chaiscript::detail::Dispatch_State &t_ss, - Operators::Opers t_oper, const std::string &t_oper_string, const Boxed_Value &t_lhs, const Boxed_Value &t_rhs) const - { - try { - if (t_oper != Operators::Opers::invalid && t_lhs.get_type_info().is_arithmetic() && t_rhs.get_type_info().is_arithmetic()) - { - // If it's an arithmetic operation we want to short circuit dispatch - try{ - return Boxed_Number::do_oper(t_oper, t_lhs, t_rhs); - } catch (const chaiscript::exception::arithmetic_error &) { - throw; - } catch (...) { - throw exception::eval_error("Error with numeric operator calling: " + t_oper_string); - } - } else { - chaiscript::eval::detail::Function_Push_Pop fpp(t_ss); - std::array params{t_lhs, t_rhs}; - fpp.save_params(Function_Params(params)); - return t_ss->call_function(t_oper_string, m_loc, Function_Params(params), t_ss.conversions()); + protected: + Boxed_Value do_oper(const chaiscript::detail::Dispatch_State &t_ss, + Operators::Opers t_oper, + const std::string &t_oper_string, + const Boxed_Value &t_lhs, + const Boxed_Value &t_rhs) const { + try { + if (t_oper != Operators::Opers::invalid && t_lhs.get_type_info().is_arithmetic() && t_rhs.get_type_info().is_arithmetic()) { + // If it's an arithmetic operation we want to short circuit dispatch + try { + return Boxed_Number::do_oper(t_oper, t_lhs, t_rhs); + } catch (const chaiscript::exception::arithmetic_error &) { + throw; + } catch (...) { + throw exception::eval_error("Error with numeric operator calling: " + t_oper_string); } + } else { + chaiscript::eval::detail::Function_Push_Pop fpp(t_ss); + std::array params{t_lhs, t_rhs}; + fpp.save_params(Function_Params(params)); + return t_ss->call_function(t_oper_string, m_loc, Function_Params(params), t_ss.conversions()); } - catch(const exception::dispatch_error &e){ - throw exception::eval_error("Can not find appropriate '" + t_oper_string + "' operator.", e.parameters, e.functions, false, *t_ss); - } + } catch (const exception::dispatch_error &e) { + throw exception::eval_error("Can not find appropriate '" + t_oper_string + "' operator.", e.parameters, e.functions, false, *t_ss); } + } - private: - Operators::Opers m_oper; - mutable std::atomic_uint_fast32_t m_loc = {0}; + private: + Operators::Opers m_oper; + mutable std::atomic_uint_fast32_t m_loc = {0}; }; - template struct Constant_AST_Node final : AST_Node_Impl { Constant_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, Boxed_Value t_value) - : AST_Node_Impl(t_ast_node_text, AST_Node_Type::Constant, std::move(t_loc)), - m_value(std::move(t_value)) - { + : AST_Node_Impl(t_ast_node_text, AST_Node_Type::Constant, std::move(t_loc)) + , m_value(std::move(t_value)) { } explicit Constant_AST_Node(Boxed_Value t_value) - : AST_Node_Impl("", AST_Node_Type::Constant, Parse_Location()), - m_value(std::move(t_value)) - { + : AST_Node_Impl("", AST_Node_Type::Constant, Parse_Location()) + , m_value(std::move(t_value)) { } - Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &) const override { - return m_value; - } + Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &) const override { return m_value; } Boxed_Value m_value; }; template struct Id_AST_Node final : AST_Node_Impl { - Id_AST_Node(const std::string &t_ast_node_text, Parse_Location t_loc) : - AST_Node_Impl(t_ast_node_text, AST_Node_Type::Id, std::move(t_loc)) - { } + Id_AST_Node(const std::string &t_ast_node_text, Parse_Location t_loc) + : AST_Node_Impl(t_ast_node_text, AST_Node_Type::Id, std::move(t_loc)) { + } - Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override { - try { - return t_ss.get_object(this->text, m_loc); - } - catch (std::exception &) { - throw exception::eval_error("Can not find object: " + this->text); - } + Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override { + try { + return t_ss.get_object(this->text, m_loc); + } catch (std::exception &) { + throw exception::eval_error("Can not find object: " + this->text); } + } - private: - mutable std::atomic_uint_fast32_t m_loc = {0}; + private: + mutable std::atomic_uint_fast32_t m_loc = {0}; }; template struct Fun_Call_AST_Node : AST_Node_Impl { - Fun_Call_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector> t_children) : - AST_Node_Impl(std::move(t_ast_node_text), AST_Node_Type::Fun_Call, std::move(t_loc), std::move(t_children)) { - assert(!this->children.empty()); - } + Fun_Call_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector> t_children) + : AST_Node_Impl(std::move(t_ast_node_text), AST_Node_Type::Fun_Call, std::move(t_loc), std::move(t_children)) { + assert(!this->children.empty()); + } - template - Boxed_Value do_eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const - { - chaiscript::eval::detail::Function_Push_Pop fpp(t_ss); + template + Boxed_Value do_eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const { + chaiscript::eval::detail::Function_Push_Pop fpp(t_ss); - std::vector params; + std::vector params; - params.reserve(this->children[1]->children.size()); - for (const auto &child : this->children[1]->children) { - params.push_back(child->eval(t_ss)); - } + params.reserve(this->children[1]->children.size()); + for (const auto &child : this->children[1]->children) { + params.push_back(child->eval(t_ss)); + } - if (Save_Params) { - fpp.save_params(Function_Params{params}); - } + if (Save_Params) { + fpp.save_params(Function_Params{params}); + } - Boxed_Value fn(this->children[0]->eval(t_ss)); + Boxed_Value fn(this->children[0]->eval(t_ss)); + try { + return (*t_ss->boxed_cast(fn))(Function_Params{params}, t_ss.conversions()); + } catch (const exception::dispatch_error &e) { + throw exception::eval_error(std::string(e.what()) + " with function '" + this->children[0]->text + "'", + e.parameters, + e.functions, + false, + *t_ss); + } catch (const exception::bad_boxed_cast &) { try { - return (*t_ss->boxed_cast(fn))(Function_Params{params}, t_ss.conversions()); - } - catch(const exception::dispatch_error &e){ - throw exception::eval_error(std::string(e.what()) + " with function '" + this->children[0]->text + "'", e.parameters, e.functions, false, *t_ss); - } - catch(const exception::bad_boxed_cast &){ - try { - using ConstFunctionTypeRef = const Const_Proxy_Function &; - Const_Proxy_Function f = t_ss->boxed_cast(fn); - // handle the case where there is only 1 function to try to call and dispatch fails on it - throw exception::eval_error("Error calling function '" + this->children[0]->text + "'", params, make_vector(f), false, *t_ss); - } catch (const exception::bad_boxed_cast &) { - throw exception::eval_error("'" + this->children[0]->pretty_print() + "' does not evaluate to a function."); - } - } - catch(const exception::arity_error &e){ - throw exception::eval_error(std::string(e.what()) + " with function '" + this->children[0]->text + "'"); - } - catch(const exception::guard_error &e){ - throw exception::eval_error(std::string(e.what()) + " with function '" + this->children[0]->text + "'"); - } - catch(detail::Return_Value &rv) { - return rv.retval; + using ConstFunctionTypeRef = const Const_Proxy_Function &; + Const_Proxy_Function f = t_ss->boxed_cast(fn); + // handle the case where there is only 1 function to try to call and dispatch fails on it + throw exception::eval_error("Error calling function '" + this->children[0]->text + "'", params, make_vector(f), false, *t_ss); + } catch (const exception::bad_boxed_cast &) { + throw exception::eval_error("'" + this->children[0]->pretty_print() + "' does not evaluate to a function."); } + } catch (const exception::arity_error &e) { + throw exception::eval_error(std::string(e.what()) + " with function '" + this->children[0]->text + "'"); + } catch (const exception::guard_error &e) { + throw exception::eval_error(std::string(e.what()) + " with function '" + this->children[0]->text + "'"); + } catch (detail::Return_Value &rv) { + return rv.retval; } + } - Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override - { - return do_eval_internal(t_ss); - } - + Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override { return do_eval_internal(t_ss); } }; - template struct Unused_Return_Fun_Call_AST_Node final : Fun_Call_AST_Node { - Unused_Return_Fun_Call_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector> t_children) : - Fun_Call_AST_Node(std::move(t_ast_node_text), std::move(t_loc), std::move(t_children)) { } + Unused_Return_Fun_Call_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector> t_children) + : Fun_Call_AST_Node(std::move(t_ast_node_text), std::move(t_loc), std::move(t_children)) { + } - Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override - { - return this->template do_eval_internal(t_ss); - } + Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override { + return this->template do_eval_internal(t_ss); + } }; - - - - template struct Arg_AST_Node final : AST_Node_Impl { - Arg_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector> t_children) : - AST_Node_Impl(std::move(t_ast_node_text), AST_Node_Type::Arg_List, std::move(t_loc), std::move(t_children)) { } - + Arg_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector> t_children) + : AST_Node_Impl(std::move(t_ast_node_text), AST_Node_Type::Arg_List, std::move(t_loc), std::move(t_children)) { + } }; template struct Arg_List_AST_Node final : AST_Node_Impl { - Arg_List_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector> t_children) : - AST_Node_Impl(std::move(t_ast_node_text), AST_Node_Type::Arg_List, std::move(t_loc), std::move(t_children)) { } + Arg_List_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector> t_children) + : AST_Node_Impl(std::move(t_ast_node_text), AST_Node_Type::Arg_List, std::move(t_loc), std::move(t_children)) { + } + static std::string get_arg_name(const AST_Node_Impl &t_node) { + if (t_node.children.empty()) { + return t_node.text; + } else if (t_node.children.size() == 1) { + return t_node.children[0]->text; + } else { + return t_node.children[1]->text; + } + } - static std::string get_arg_name(const AST_Node_Impl &t_node) { - if (t_node.children.empty()) - { - return t_node.text; - } else if (t_node.children.size() == 1) { - return t_node.children[0]->text; - } else { - return t_node.children[1]->text; - } + static std::vector get_arg_names(const AST_Node_Impl &t_node) { + std::vector retval; + + for (const auto &node : t_node.children) { + retval.push_back(get_arg_name(*node)); } - static std::vector get_arg_names(const AST_Node_Impl &t_node) { - std::vector retval; + return retval; + } - for (const auto &node : t_node.children) - { - retval.push_back(get_arg_name(*node)); - } + static std::pair get_arg_type(const AST_Node_Impl &t_node, const chaiscript::detail::Dispatch_State &t_ss) { + if (t_node.children.size() < 2) { + return {}; + } else { + return {t_node.children[0]->text, t_ss->get_type(t_node.children[0]->text, false)}; + } + } - return retval; + static dispatch::Param_Types get_arg_types(const AST_Node_Impl &t_node, const chaiscript::detail::Dispatch_State &t_ss) { + std::vector> retval; + + for (const auto &child : t_node.children) { + retval.push_back(get_arg_type(*child, t_ss)); } - static std::pair get_arg_type(const AST_Node_Impl &t_node, const chaiscript::detail::Dispatch_State &t_ss) - { - if (t_node.children.size() < 2) - { - return {}; - } else { - return {t_node.children[0]->text, t_ss->get_type(t_node.children[0]->text, false)}; - } - } - - static dispatch::Param_Types get_arg_types(const AST_Node_Impl &t_node, const chaiscript::detail::Dispatch_State &t_ss) { - std::vector> retval; - - for (const auto &child : t_node.children) - { - retval.push_back(get_arg_type(*child, t_ss)); - } - - return dispatch::Param_Types(std::move(retval)); - } + return dispatch::Param_Types(std::move(retval)); + } }; template struct Equation_AST_Node final : AST_Node_Impl { - Equation_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector> t_children) : - AST_Node_Impl(std::move(t_ast_node_text), AST_Node_Type::Equation, std::move(t_loc), std::move(t_children)), - m_oper(Operators::to_operator(this->text)) - { assert(this->children.size() == 2); } + Equation_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector> t_children) + : AST_Node_Impl(std::move(t_ast_node_text), AST_Node_Type::Equation, std::move(t_loc), std::move(t_children)) + , m_oper(Operators::to_operator(this->text)) { + assert(this->children.size() == 2); + } + Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override { + chaiscript::eval::detail::Function_Push_Pop fpp(t_ss); - Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override { - chaiscript::eval::detail::Function_Push_Pop fpp(t_ss); + auto params = [&]() { + // The RHS *must* be evaluated before the LHS + // consider `var range = range(x)` + // if we declare the variable in scope first, then the name lookup fails + // for the RHS + auto rhs = this->children[1]->eval(t_ss); + auto lhs = this->children[0]->eval(t_ss); + std::array p{std::move(lhs), std::move(rhs)}; + return p; + }(); - auto params = [&](){ - // The RHS *must* be evaluated before the LHS - // consider `var range = range(x)` - // if we declare the variable in scope first, then the name lookup fails - // for the RHS - auto rhs = this->children[1]->eval(t_ss); - auto lhs = this->children[0]->eval(t_ss); - std::array p{std::move(lhs), std::move(rhs)}; - return p; - }(); - - if (params[0].is_return_value()) { - throw exception::eval_error("Error, cannot assign to temporary value."); - } else if (params[0].is_const()) { - throw exception::eval_error("Error, cannot assign to constant value."); - } - - - if (m_oper != Operators::Opers::invalid && params[0].get_type_info().is_arithmetic() && - params[1].get_type_info().is_arithmetic()) - { - try { - return Boxed_Number::do_oper(m_oper, params[0], params[1]); - } catch (const std::exception &) { - throw exception::eval_error("Error with unsupported arithmetic assignment operation."); - } - } else if (m_oper == Operators::Opers::assign) { - try { - - if (params[0].is_undef()) { - if (!this->children.empty() - && ((this->children[0]->identifier == AST_Node_Type::Reference) - || (!this->children[0]->children.empty() - && this->children[0]->children[0]->identifier == AST_Node_Type::Reference) - ) - ) - - { - /// \todo This does not handle the case of an unassigned reference variable - /// being assigned outside of its declaration - params[0].assign(params[1]); - params[0].reset_return_value(); - return params[1]; - } else { - params[1] = detail::clone_if_necessary(std::move(params[1]), m_clone_loc, t_ss); - } - } - - try { - return t_ss->call_function(this->text, m_loc, Function_Params{params}, t_ss.conversions()); - } - catch(const exception::dispatch_error &e){ - throw exception::eval_error("Unable to find appropriate'" + this->text + "' operator.", e.parameters, e.functions, false, *t_ss); - } - } - catch(const exception::dispatch_error &e){ - throw exception::eval_error("Missing clone or copy constructor for right hand side of equation", e.parameters, e.functions, false, *t_ss); - } - } - else if (this->text == ":=") { - if (params[0].is_undef() || Boxed_Value::type_match(params[0], params[1])) { - params[0].assign(params[1]); - params[0].reset_return_value(); - } else { - throw exception::eval_error("Mismatched types in equation"); - } - } - else { - try { - return t_ss->call_function(this->text, m_loc, Function_Params{params}, t_ss.conversions()); - } catch(const exception::dispatch_error &e){ - throw exception::eval_error("Unable to find appropriate'" + this->text + "' operator.", e.parameters, e.functions, false, *t_ss); - } - } - - return params[1]; + if (params[0].is_return_value()) { + throw exception::eval_error("Error, cannot assign to temporary value."); + } else if (params[0].is_const()) { + throw exception::eval_error("Error, cannot assign to constant value."); } - private: - Operators::Opers m_oper; - mutable std::atomic_uint_fast32_t m_loc = {0}; - mutable std::atomic_uint_fast32_t m_clone_loc = {0}; + if (m_oper != Operators::Opers::invalid && params[0].get_type_info().is_arithmetic() && params[1].get_type_info().is_arithmetic()) { + try { + return Boxed_Number::do_oper(m_oper, params[0], params[1]); + } catch (const std::exception &) { + throw exception::eval_error("Error with unsupported arithmetic assignment operation."); + } + } else if (m_oper == Operators::Opers::assign) { + try { + if (params[0].is_undef()) { + if (!this->children.empty() + && ((this->children[0]->identifier == AST_Node_Type::Reference) + || (!this->children[0]->children.empty() && this->children[0]->children[0]->identifier == AST_Node_Type::Reference))) + + { + /// \todo This does not handle the case of an unassigned reference variable + /// being assigned outside of its declaration + params[0].assign(params[1]); + params[0].reset_return_value(); + return params[1]; + } else { + params[1] = detail::clone_if_necessary(std::move(params[1]), m_clone_loc, t_ss); + } + } + + try { + return t_ss->call_function(this->text, m_loc, Function_Params{params}, t_ss.conversions()); + } catch (const exception::dispatch_error &e) { + throw exception::eval_error("Unable to find appropriate'" + this->text + "' operator.", e.parameters, e.functions, false, *t_ss); + } + } catch (const exception::dispatch_error &e) { + throw exception::eval_error("Missing clone or copy constructor for right hand side of equation", + e.parameters, + e.functions, + false, + *t_ss); + } + } else if (this->text == ":=") { + if (params[0].is_undef() || Boxed_Value::type_match(params[0], params[1])) { + params[0].assign(params[1]); + params[0].reset_return_value(); + } else { + throw exception::eval_error("Mismatched types in equation"); + } + } else { + try { + return t_ss->call_function(this->text, m_loc, Function_Params{params}, t_ss.conversions()); + } catch (const exception::dispatch_error &e) { + throw exception::eval_error("Unable to find appropriate'" + this->text + "' operator.", e.parameters, e.functions, false, *t_ss); + } + } + + return params[1]; + } + + private: + Operators::Opers m_oper; + mutable std::atomic_uint_fast32_t m_loc = {0}; + mutable std::atomic_uint_fast32_t m_clone_loc = {0}; }; template struct Global_Decl_AST_Node final : AST_Node_Impl { - Global_Decl_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector> t_children) : - AST_Node_Impl(std::move(t_ast_node_text), AST_Node_Type::Global_Decl, std::move(t_loc), std::move(t_children)) { } + Global_Decl_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector> t_children) + : AST_Node_Impl(std::move(t_ast_node_text), AST_Node_Type::Global_Decl, std::move(t_loc), std::move(t_children)) { + } - Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override { - const std::string &idname = - [&]()->const std::string & { - if (this->children[0]->identifier == AST_Node_Type::Reference) { - return this->children[0]->children[0]->text; - } else { - return this->children[0]->text; - } - }(); + Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override { + const std::string &idname = [&]() -> const std::string & { + if (this->children[0]->identifier == AST_Node_Type::Reference) { + return this->children[0]->children[0]->text; + } else { + return this->children[0]->text; + } + }(); - return t_ss->add_global_no_throw(Boxed_Value(), idname); - - } + return t_ss->add_global_no_throw(Boxed_Value(), idname); + } }; - template struct Var_Decl_AST_Node final : AST_Node_Impl { - Var_Decl_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector> t_children) : - AST_Node_Impl(std::move(t_ast_node_text), AST_Node_Type::Var_Decl, std::move(t_loc), std::move(t_children)) { } + Var_Decl_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector> t_children) + : AST_Node_Impl(std::move(t_ast_node_text), AST_Node_Type::Var_Decl, std::move(t_loc), std::move(t_children)) { + } - Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override { - const std::string &idname = this->children[0]->text; + Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override { + const std::string &idname = this->children[0]->text; - try { - Boxed_Value bv; - t_ss.add_object(idname, bv); - return bv; - } catch (const exception::name_conflict_error &e) { - throw exception::eval_error("Variable redefined '" + e.name() + "'"); - } + try { + Boxed_Value bv; + t_ss.add_object(idname, bv); + return bv; + } catch (const exception::name_conflict_error &e) { + throw exception::eval_error("Variable redefined '" + e.name() + "'"); } + } }; template struct Assign_Decl_AST_Node final : AST_Node_Impl { - Assign_Decl_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector> t_children) : - AST_Node_Impl(std::move(t_ast_node_text), AST_Node_Type::Assign_Decl, std::move(t_loc), std::move(t_children)) { } + Assign_Decl_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector> t_children) + : AST_Node_Impl(std::move(t_ast_node_text), AST_Node_Type::Assign_Decl, std::move(t_loc), std::move(t_children)) { + } - Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override { - const std::string &idname = this->children[0]->text; + Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override { + const std::string &idname = this->children[0]->text; - try { - Boxed_Value bv(detail::clone_if_necessary(this->children[1]->eval(t_ss), m_loc, t_ss)); - bv.reset_return_value(); - t_ss.add_object(idname, bv); - return bv; - } catch (const exception::name_conflict_error &e) { - throw exception::eval_error("Variable redefined '" + e.name() + "'"); - } + try { + Boxed_Value bv(detail::clone_if_necessary(this->children[1]->eval(t_ss), m_loc, t_ss)); + bv.reset_return_value(); + t_ss.add_object(idname, bv); + return bv; + } catch (const exception::name_conflict_error &e) { + throw exception::eval_error("Variable redefined '" + e.name() + "'"); } - private: - mutable std::atomic_uint_fast32_t m_loc = {0}; - }; + } + private: + mutable std::atomic_uint_fast32_t m_loc = {0}; + }; template struct Array_Call_AST_Node final : AST_Node_Impl { - Array_Call_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector> t_children) : - AST_Node_Impl(std::move(t_ast_node_text), AST_Node_Type::Array_Call, std::move(t_loc), std::move(t_children)) { } + Array_Call_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector> t_children) + : AST_Node_Impl(std::move(t_ast_node_text), AST_Node_Type::Array_Call, std::move(t_loc), std::move(t_children)) { + } - Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override { - chaiscript::eval::detail::Function_Push_Pop fpp(t_ss); + Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override { + chaiscript::eval::detail::Function_Push_Pop fpp(t_ss); - std::array params{this->children[0]->eval(t_ss), this->children[1]->eval(t_ss)}; + std::array params{this->children[0]->eval(t_ss), this->children[1]->eval(t_ss)}; - try { - fpp.save_params(Function_Params{params}); - return t_ss->call_function("[]", m_loc, Function_Params{params}, t_ss.conversions()); - } - catch(const exception::dispatch_error &e){ - throw exception::eval_error("Can not find appropriate array lookup operator '[]'.", e.parameters, e.functions, false, *t_ss ); - } + try { + fpp.save_params(Function_Params{params}); + return t_ss->call_function("[]", m_loc, Function_Params{params}, t_ss.conversions()); + } catch (const exception::dispatch_error &e) { + throw exception::eval_error("Can not find appropriate array lookup operator '[]'.", e.parameters, e.functions, false, *t_ss); } + } - - private: - mutable std::atomic_uint_fast32_t m_loc = {0}; + private: + mutable std::atomic_uint_fast32_t m_loc = {0}; }; template struct Dot_Access_AST_Node final : AST_Node_Impl { - Dot_Access_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector> t_children) : - AST_Node_Impl(std::move(t_ast_node_text), AST_Node_Type::Dot_Access, std::move(t_loc), std::move(t_children)), - m_fun_name( - ((this->children[1]->identifier == AST_Node_Type::Fun_Call) || (this->children[1]->identifier == AST_Node_Type::Array_Call))? - this->children[1]->children[0]->text:this->children[1]->text) { } + Dot_Access_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector> t_children) + : AST_Node_Impl(std::move(t_ast_node_text), AST_Node_Type::Dot_Access, std::move(t_loc), std::move(t_children)) + , m_fun_name(((this->children[1]->identifier == AST_Node_Type::Fun_Call) || (this->children[1]->identifier == AST_Node_Type::Array_Call)) + ? this->children[1]->children[0]->text + : this->children[1]->text) { + } - Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override { - chaiscript::eval::detail::Function_Push_Pop fpp(t_ss); + Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override { + chaiscript::eval::detail::Function_Push_Pop fpp(t_ss); + Boxed_Value retval = this->children[0]->eval(t_ss); + auto params = make_vector(retval); - Boxed_Value retval = this->children[0]->eval(t_ss); - auto params = make_vector(retval); - - bool has_function_params = false; - if (this->children[1]->children.size() > 1) { - has_function_params = true; - for (const auto &child : this->children[1]->children[1]->children) { - params.push_back(child->eval(t_ss)); - } + bool has_function_params = false; + if (this->children[1]->children.size() > 1) { + has_function_params = true; + for (const auto &child : this->children[1]->children[1]->children) { + params.push_back(child->eval(t_ss)); } - - fpp.save_params(Function_Params{params}); - - try { - retval = t_ss->call_member(m_fun_name, m_loc, Function_Params{params}, has_function_params, t_ss.conversions()); - } - catch(const exception::dispatch_error &e){ - if (e.functions.empty()) - { - throw exception::eval_error("'" + m_fun_name + "' is not a function."); - } else { - throw exception::eval_error(std::string(e.what()) + " for function '" + m_fun_name + "'", e.parameters, e.functions, true, *t_ss); - } - } - catch(detail::Return_Value &rv) { - retval = std::move(rv.retval); - } - - if (this->children[1]->identifier == AST_Node_Type::Array_Call) { - try { - std::array p{retval, this->children[1]->children[1]->eval(t_ss)}; - retval = t_ss->call_function("[]", m_array_loc, Function_Params{p}, t_ss.conversions()); - } - catch(const exception::dispatch_error &e){ - throw exception::eval_error("Can not find appropriate array lookup operator '[]'.", e.parameters, e.functions, true, *t_ss); - } - } - - return retval; } - private: - mutable std::atomic_uint_fast32_t m_loc = {0}; - mutable std::atomic_uint_fast32_t m_array_loc = {0}; - const std::string m_fun_name; - }; + fpp.save_params(Function_Params{params}); + try { + retval = t_ss->call_member(m_fun_name, m_loc, Function_Params{params}, has_function_params, t_ss.conversions()); + } catch (const exception::dispatch_error &e) { + if (e.functions.empty()) { + throw exception::eval_error("'" + m_fun_name + "' is not a function."); + } else { + throw exception::eval_error(std::string(e.what()) + " for function '" + m_fun_name + "'", e.parameters, e.functions, true, *t_ss); + } + } catch (detail::Return_Value &rv) { + retval = std::move(rv.retval); + } + + if (this->children[1]->identifier == AST_Node_Type::Array_Call) { + try { + std::array p{retval, this->children[1]->children[1]->eval(t_ss)}; + retval = t_ss->call_function("[]", m_array_loc, Function_Params{p}, t_ss.conversions()); + } catch (const exception::dispatch_error &e) { + throw exception::eval_error("Can not find appropriate array lookup operator '[]'.", e.parameters, e.functions, true, *t_ss); + } + } + + return retval; + } + + private: + mutable std::atomic_uint_fast32_t m_loc = {0}; + mutable std::atomic_uint_fast32_t m_array_loc = {0}; + const std::string m_fun_name; + }; template struct Lambda_AST_Node final : AST_Node_Impl { - Lambda_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector> t_children) : - AST_Node_Impl(t_ast_node_text, - AST_Node_Type::Lambda, - std::move(t_loc), - std::vector>(std::make_move_iterator(t_children.begin()), - std::make_move_iterator(std::prev(t_children.end()))) - ), - m_param_names(Arg_List_AST_Node::get_arg_names(*this->children[1])), - m_this_capture(has_this_capture(this->children[0]->children)), - m_lambda_node(std::move(t_children.back())) - { } + Lambda_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector> t_children) + : AST_Node_Impl(t_ast_node_text, + AST_Node_Type::Lambda, + std::move(t_loc), + std::vector>(std::make_move_iterator(t_children.begin()), + std::make_move_iterator(std::prev(t_children.end())))) + , m_param_names(Arg_List_AST_Node::get_arg_names(*this->children[1])) + , m_this_capture(has_this_capture(this->children[0]->children)) + , m_lambda_node(std::move(t_children.back())) { + } - Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override { + Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override { + const auto captures = [&]() -> std::map { + std::map named_captures; + for (const auto &capture : this->children[0]->children) { + named_captures.insert(std::make_pair(capture->children[0]->text, capture->children[0]->eval(t_ss))); + } + return named_captures; + }(); - const auto captures = [&]()->std::map{ - std::map named_captures; - for (const auto &capture : this->children[0]->children) { - named_captures.insert(std::make_pair(capture->children[0]->text, capture->children[0]->eval(t_ss))); - } - return named_captures; - }(); + const auto numparams = this->children[1]->children.size(); + const auto param_types = Arg_List_AST_Node::get_arg_types(*this->children[1], t_ss); - const auto numparams = this->children[1]->children.size(); - const auto param_types = Arg_List_AST_Node::get_arg_types(*this->children[1], t_ss); + std::reference_wrapper engine(*t_ss); - std::reference_wrapper engine(*t_ss); + return Boxed_Value(dispatch::make_dynamic_proxy_function( + [engine, lambda_node = this->m_lambda_node, param_names = this->m_param_names, captures, this_capture = this->m_this_capture]( + const Function_Params &t_params) { + return detail::eval_function(engine, *lambda_node, param_names, t_params, &captures, this_capture); + }, + static_cast(numparams), + m_lambda_node, + param_types)); + } - return Boxed_Value( - dispatch::make_dynamic_proxy_function( - [engine, lambda_node = this->m_lambda_node, param_names = this->m_param_names, captures, - this_capture = this->m_this_capture] (const Function_Params &t_params) - { - return detail::eval_function(engine, *lambda_node, param_names, t_params, &captures, this_capture); - }, - static_cast(numparams), m_lambda_node, param_types - ) - ); - } + static bool has_this_capture(const std::vector> &t_children) noexcept { + return std::any_of(std::begin(t_children), std::end(t_children), [](const auto &child) { return child->children[0]->text == "this"; }); + } - static bool has_this_capture(const std::vector> &t_children) noexcept { - return std::any_of(std::begin(t_children), std::end(t_children), - [](const auto &child){ - return child->children[0]->text == "this"; - } - ); - } - - private: - const std::vector m_param_names; - const bool m_this_capture = false; - const std::shared_ptr> m_lambda_node; + private: + const std::vector m_param_names; + const bool m_this_capture = false; + const std::shared_ptr> m_lambda_node; }; template struct Scopeless_Block_AST_Node final : AST_Node_Impl { - Scopeless_Block_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector> t_children) : - AST_Node_Impl(std::move(t_ast_node_text), AST_Node_Type::Scopeless_Block, std::move(t_loc), std::move(t_children)) { } + Scopeless_Block_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector> t_children) + : AST_Node_Impl(std::move(t_ast_node_text), AST_Node_Type::Scopeless_Block, std::move(t_loc), std::move(t_children)) { + } - Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override { - const auto num_children = this->children.size(); - for (size_t i = 0; i < num_children-1; ++i) { - this->children[i]->eval(t_ss); - } - return this->children.back()->eval(t_ss); + Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override { + const auto num_children = this->children.size(); + for (size_t i = 0; i < num_children - 1; ++i) { + this->children[i]->eval(t_ss); } + return this->children.back()->eval(t_ss); + } }; template struct Block_AST_Node final : AST_Node_Impl { - Block_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector> t_children) : - AST_Node_Impl(std::move(t_ast_node_text), AST_Node_Type::Block, std::move(t_loc), std::move(t_children)) { } + Block_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector> t_children) + : AST_Node_Impl(std::move(t_ast_node_text), AST_Node_Type::Block, std::move(t_loc), std::move(t_children)) { + } - Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override { - chaiscript::eval::detail::Scope_Push_Pop spp(t_ss); + Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override { + chaiscript::eval::detail::Scope_Push_Pop spp(t_ss); - const auto num_children = this->children.size(); - for (size_t i = 0; i < num_children-1; ++i) { - this->children[i]->eval(t_ss); - } - return this->children.back()->eval(t_ss); + const auto num_children = this->children.size(); + for (size_t i = 0; i < num_children - 1; ++i) { + this->children[i]->eval(t_ss); } + return this->children.back()->eval(t_ss); + } }; template struct Def_AST_Node final : AST_Node_Impl { + std::shared_ptr> m_body_node; + std::shared_ptr> m_guard_node; - std::shared_ptr> m_body_node; - std::shared_ptr> m_guard_node; + Def_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector> t_children) + : AST_Node_Impl(std::move(t_ast_node_text), + AST_Node_Type::Def, + std::move(t_loc), + std::vector>(std::make_move_iterator(t_children.begin()), + std::make_move_iterator( + std::prev(t_children.end(), has_guard(t_children, 1) ? 2 : 1)))) + , + // This apparent use after move is safe because we are only moving out the specific elements we need + // on each operation. + m_body_node(get_body_node(std::move(t_children))) + , m_guard_node(get_guard_node(std::move(t_children), t_children.size() - this->children.size() == 2)) - Def_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector> t_children) : - AST_Node_Impl(std::move(t_ast_node_text), AST_Node_Type::Def, std::move(t_loc), - std::vector>(std::make_move_iterator(t_children.begin()), - std::make_move_iterator(std::prev(t_children.end(), has_guard(t_children, 1)?2:1))) - ), - // This apparent use after move is safe because we are only moving out the specific elements we need - // on each operation. - m_body_node(get_body_node(std::move(t_children))), - m_guard_node(get_guard_node(std::move(t_children), t_children.size()-this->children.size()==2)) + { + } - { } + static std::shared_ptr> get_guard_node(std::vector> &&vec, bool has_guard) { + if (has_guard) { + return std::move(*std::prev(vec.end(), 2)); + } else { + return {}; + } + } - static std::shared_ptr> get_guard_node(std::vector> &&vec, bool has_guard) - { - if (has_guard) { - return std::move(*std::prev(vec.end(), 2)); - } else { - return {}; + static std::shared_ptr> get_body_node(std::vector> &&vec) { return std::move(vec.back()); } + + static bool has_guard(const std::vector> &t_children, const std::size_t offset) noexcept { + if ((t_children.size() > 2 + offset) && (t_children[1 + offset]->identifier == AST_Node_Type::Arg_List)) { + if (t_children.size() > 3 + offset) { + return true; + } + } else { + if (t_children.size() > 2 + offset) { + return true; } } + return false; + } - static std::shared_ptr> get_body_node(std::vector> &&vec) - { - return std::move(vec.back()); + Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override { + std::vector t_param_names; + size_t numparams = 0; + + dispatch::Param_Types param_types; + + if ((this->children.size() > 1) && (this->children[1]->identifier == AST_Node_Type::Arg_List)) { + numparams = this->children[1]->children.size(); + t_param_names = Arg_List_AST_Node::get_arg_names(*this->children[1]); + param_types = Arg_List_AST_Node::get_arg_types(*this->children[1], t_ss); } - static bool has_guard(const std::vector> &t_children, const std::size_t offset) noexcept - { - if ((t_children.size() > 2 + offset) && (t_children[1+offset]->identifier == AST_Node_Type::Arg_List)) { - if (t_children.size() > 3 + offset) { - return true; - } - } - else { - if (t_children.size() > 2 + offset) { - return true; - } - } - return false; + std::reference_wrapper engine(*t_ss); + std::shared_ptr guard; + if (m_guard_node) { + guard = dispatch::make_dynamic_proxy_function( + [engine, guardnode = m_guard_node, t_param_names](const Function_Params &t_params) { + return detail::eval_function(engine, *guardnode, t_param_names, t_params); + }, + static_cast(numparams), + m_guard_node); } - Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override{ - std::vector t_param_names; - size_t numparams = 0; - - dispatch::Param_Types param_types; - - if ((this->children.size() > 1) && (this->children[1]->identifier == AST_Node_Type::Arg_List)) { - numparams = this->children[1]->children.size(); - t_param_names = Arg_List_AST_Node::get_arg_names(*this->children[1]); - param_types = Arg_List_AST_Node::get_arg_types(*this->children[1], t_ss); - } - - std::reference_wrapper engine(*t_ss); - std::shared_ptr guard; - if (m_guard_node) { - guard = dispatch::make_dynamic_proxy_function( - [engine, guardnode = m_guard_node, t_param_names](const Function_Params &t_params) - { - return detail::eval_function(engine, *guardnode, t_param_names, t_params); - }, - static_cast(numparams), m_guard_node); - } - - try { - const std::string & l_function_name = this->children[0]->text; - t_ss->add( - dispatch::make_dynamic_proxy_function( - [engine, func_node = m_body_node, t_param_names](const Function_Params &t_params) - { - return detail::eval_function(engine, *func_node, t_param_names, t_params); - }, - static_cast(numparams), m_body_node, - param_types, guard), l_function_name); - } catch (const exception::name_conflict_error &e) { - throw exception::eval_error("Function redefined '" + e.name() + "'"); - } - return void_var(); + try { + const std::string &l_function_name = this->children[0]->text; + t_ss->add(dispatch::make_dynamic_proxy_function( + [engine, func_node = m_body_node, t_param_names](const Function_Params &t_params) { + return detail::eval_function(engine, *func_node, t_param_names, t_params); + }, + static_cast(numparams), + m_body_node, + param_types, + guard), + l_function_name); + } catch (const exception::name_conflict_error &e) { + throw exception::eval_error("Function redefined '" + e.name() + "'"); } - + return void_var(); + } }; template struct While_AST_Node final : AST_Node_Impl { - While_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector> t_children) : - AST_Node_Impl(std::move(t_ast_node_text), AST_Node_Type::While, std::move(t_loc), std::move(t_children)) { } + While_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector> t_children) + : AST_Node_Impl(std::move(t_ast_node_text), AST_Node_Type::While, std::move(t_loc), std::move(t_children)) { + } - Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override { - chaiscript::eval::detail::Scope_Push_Pop spp(t_ss); + Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override { + chaiscript::eval::detail::Scope_Push_Pop spp(t_ss); - try { - while (this->get_scoped_bool_condition(*this->children[0], t_ss)) { - try { - this->children[1]->eval(t_ss); - } catch (detail::Continue_Loop &) { - // we got a continue exception, which means all of the remaining - // loop implementation is skipped and we just need to continue to - // the next condition test - } + try { + while (this->get_scoped_bool_condition(*this->children[0], t_ss)) { + try { + this->children[1]->eval(t_ss); + } catch (detail::Continue_Loop &) { + // we got a continue exception, which means all of the remaining + // loop implementation is skipped and we just need to continue to + // the next condition test } - } catch (detail::Break_Loop &) { - // loop was broken intentionally } - - return void_var(); + } catch (detail::Break_Loop &) { + // loop was broken intentionally } + + return void_var(); + } }; template struct Class_AST_Node final : AST_Node_Impl { - Class_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector> t_children) : - AST_Node_Impl(std::move(t_ast_node_text), AST_Node_Type::Class, std::move(t_loc), std::move(t_children)) { } + Class_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector> t_children) + : AST_Node_Impl(std::move(t_ast_node_text), AST_Node_Type::Class, std::move(t_loc), std::move(t_children)) { + } - Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override { - chaiscript::eval::detail::Scope_Push_Pop spp(t_ss); + Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override { + chaiscript::eval::detail::Scope_Push_Pop spp(t_ss); - /// \todo do this better - // put class name in current scope so it can be looked up by the attrs and methods - t_ss.add_object("_current_class_name", const_var(this->children[0]->text)); + /// \todo do this better + // put class name in current scope so it can be looked up by the attrs and methods + t_ss.add_object("_current_class_name", const_var(this->children[0]->text)); - this->children[1]->eval(t_ss); + this->children[1]->eval(t_ss); - return void_var(); - } + return void_var(); + } }; - template struct If_AST_Node final : AST_Node_Impl { - If_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector> t_children) : - AST_Node_Impl(std::move(t_ast_node_text), AST_Node_Type::If, std::move(t_loc), std::move(t_children)) - { - assert(this->children.size() == 3); - } + If_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector> t_children) + : AST_Node_Impl(std::move(t_ast_node_text), AST_Node_Type::If, std::move(t_loc), std::move(t_children)) { + assert(this->children.size() == 3); + } - Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override { - if (this->get_bool_condition(this->children[0]->eval(t_ss), t_ss)) { - return this->children[1]->eval(t_ss); - } else { - return this->children[2]->eval(t_ss); - } + Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override { + if (this->get_bool_condition(this->children[0]->eval(t_ss), t_ss)) { + return this->children[1]->eval(t_ss); + } else { + return this->children[2]->eval(t_ss); } + } }; template struct Ranged_For_AST_Node final : AST_Node_Impl { - Ranged_For_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector> t_children) : - AST_Node_Impl(std::move(t_ast_node_text), AST_Node_Type::Ranged_For, std::move(t_loc), std::move(t_children)) - { assert(this->children.size() == 3); } + Ranged_For_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector> t_children) + : AST_Node_Impl(std::move(t_ast_node_text), AST_Node_Type::Ranged_For, std::move(t_loc), std::move(t_children)) { + assert(this->children.size() == 3); + } - Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override{ - const auto get_function = [&t_ss](const std::string &t_name, auto &t_hint){ - uint_fast32_t hint = t_hint; - auto [funs_loc, funs] = t_ss->get_function(t_name, hint); - if (funs_loc != hint) { t_hint = uint_fast32_t(funs_loc); } - return std::move(funs); - }; - - const auto call_function = [&t_ss](const auto &t_funcs, const Boxed_Value &t_param) { - return dispatch::dispatch(*t_funcs, Function_Params{t_param}, t_ss.conversions()); - }; - - - const std::string &loop_var_name = this->children[0]->text; - Boxed_Value range_expression_result = this->children[1]->eval(t_ss); - - - const auto do_loop = [&loop_var_name, &t_ss, this](const auto &ranged_thing){ - try { - for (auto &&loop_var : ranged_thing) { - // This scope push and pop might not be the best thing for perf - // but we know it's 100% correct - chaiscript::eval::detail::Scope_Push_Pop spp(t_ss); - /// to-do make this if-constexpr with C++17 branch - if (!std::is_same, Boxed_Value>::value) { - t_ss.add_get_object(loop_var_name, Boxed_Value(std::ref(loop_var))); - } else { - t_ss.add_get_object(loop_var_name, Boxed_Value(loop_var)); - } - try { - this->children[2]->eval(t_ss); - } catch (detail::Continue_Loop &) { - } - } - } catch (detail::Break_Loop &) { - // loop broken - } - return void_var(); - }; - - if (range_expression_result.get_type_info().bare_equal_type_info(typeid(std::vector))) { - return do_loop(boxed_cast &>(range_expression_result)); - } else if (range_expression_result.get_type_info().bare_equal_type_info(typeid(std::map))) { - return do_loop(boxed_cast &>(range_expression_result)); - } else { - const auto range_funcs = get_function("range", m_range_loc); - const auto empty_funcs = get_function("empty", m_empty_loc); - const auto front_funcs = get_function("front", m_front_loc); - const auto pop_front_funcs = get_function("pop_front", m_pop_front_loc); - - try { - const auto range_obj = call_function(range_funcs, range_expression_result); - while (!boxed_cast(call_function(empty_funcs, range_obj))) { - chaiscript::eval::detail::Scope_Push_Pop spp(t_ss); - t_ss.add_get_object(loop_var_name, call_function(front_funcs, range_obj)); - try { - this->children[2]->eval(t_ss); - } catch (detail::Continue_Loop &) { - // continue statement hit - } - call_function(pop_front_funcs, range_obj); - } - } catch (detail::Break_Loop &) { - // loop broken - } - return void_var(); + Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override { + const auto get_function = [&t_ss](const std::string &t_name, auto &t_hint) { + uint_fast32_t hint = t_hint; + auto [funs_loc, funs] = t_ss->get_function(t_name, hint); + if (funs_loc != hint) { + t_hint = uint_fast32_t(funs_loc); } + return std::move(funs); + }; - } + const auto call_function = [&t_ss](const auto &t_funcs, const Boxed_Value &t_param) { + return dispatch::dispatch(*t_funcs, Function_Params{t_param}, t_ss.conversions()); + }; - private: - mutable std::atomic_uint_fast32_t m_range_loc = {0}; - mutable std::atomic_uint_fast32_t m_empty_loc = {0}; - mutable std::atomic_uint_fast32_t m_front_loc = {0}; - mutable std::atomic_uint_fast32_t m_pop_front_loc = {0}; - }; - - - template - struct For_AST_Node final : AST_Node_Impl { - For_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector> t_children) : - AST_Node_Impl(std::move(t_ast_node_text), AST_Node_Type::For, std::move(t_loc), std::move(t_children)) - { assert(this->children.size() == 4); } - - Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override{ - chaiscript::eval::detail::Scope_Push_Pop spp(t_ss); + const std::string &loop_var_name = this->children[0]->text; + Boxed_Value range_expression_result = this->children[1]->eval(t_ss); + const auto do_loop = [&loop_var_name, &t_ss, this](const auto &ranged_thing) { try { - for ( - this->children[0]->eval(t_ss); - this->get_scoped_bool_condition(*this->children[1], t_ss); - this->children[2]->eval(t_ss) - ) { + for (auto &&loop_var : ranged_thing) { + // This scope push and pop might not be the best thing for perf + // but we know it's 100% correct + chaiscript::eval::detail::Scope_Push_Pop spp(t_ss); + /// to-do make this if-constexpr with C++17 branch + if (!std::is_same, Boxed_Value>::value) { + t_ss.add_get_object(loop_var_name, Boxed_Value(std::ref(loop_var))); + } else { + t_ss.add_get_object(loop_var_name, Boxed_Value(loop_var)); + } try { - // Body of Loop - this->children[3]->eval(t_ss); + this->children[2]->eval(t_ss); } catch (detail::Continue_Loop &) { - // we got a continue exception, which means all of the remaining - // loop implementation is skipped and we just need to continue to - // the next iteration step } } } catch (detail::Break_Loop &) { // loop broken } + return void_var(); + }; + if (range_expression_result.get_type_info().bare_equal_type_info(typeid(std::vector))) { + return do_loop(boxed_cast &>(range_expression_result)); + } else if (range_expression_result.get_type_info().bare_equal_type_info(typeid(std::map))) { + return do_loop(boxed_cast &>(range_expression_result)); + } else { + const auto range_funcs = get_function("range", m_range_loc); + const auto empty_funcs = get_function("empty", m_empty_loc); + const auto front_funcs = get_function("front", m_front_loc); + const auto pop_front_funcs = get_function("pop_front", m_pop_front_loc); + + try { + const auto range_obj = call_function(range_funcs, range_expression_result); + while (!boxed_cast(call_function(empty_funcs, range_obj))) { + chaiscript::eval::detail::Scope_Push_Pop spp(t_ss); + t_ss.add_get_object(loop_var_name, call_function(front_funcs, range_obj)); + try { + this->children[2]->eval(t_ss); + } catch (detail::Continue_Loop &) { + // continue statement hit + } + call_function(pop_front_funcs, range_obj); + } + } catch (detail::Break_Loop &) { + // loop broken + } return void_var(); } + } + private: + mutable std::atomic_uint_fast32_t m_range_loc = {0}; + mutable std::atomic_uint_fast32_t m_empty_loc = {0}; + mutable std::atomic_uint_fast32_t m_front_loc = {0}; + mutable std::atomic_uint_fast32_t m_pop_front_loc = {0}; + }; + + template + struct For_AST_Node final : AST_Node_Impl { + For_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector> t_children) + : AST_Node_Impl(std::move(t_ast_node_text), AST_Node_Type::For, std::move(t_loc), std::move(t_children)) { + assert(this->children.size() == 4); + } + + Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override { + chaiscript::eval::detail::Scope_Push_Pop spp(t_ss); + + try { + for (this->children[0]->eval(t_ss); this->get_scoped_bool_condition(*this->children[1], t_ss); this->children[2]->eval(t_ss)) { + try { + // Body of Loop + this->children[3]->eval(t_ss); + } catch (detail::Continue_Loop &) { + // we got a continue exception, which means all of the remaining + // loop implementation is skipped and we just need to continue to + // the next iteration step + } + } + } catch (detail::Break_Loop &) { + // loop broken + } + + return void_var(); + } }; template struct Switch_AST_Node final : AST_Node_Impl { - Switch_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector> t_children) : - AST_Node_Impl(std::move(t_ast_node_text), AST_Node_Type::Switch, std::move(t_loc), std::move(t_children)) { } + Switch_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector> t_children) + : AST_Node_Impl(std::move(t_ast_node_text), AST_Node_Type::Switch, std::move(t_loc), std::move(t_children)) { + } - Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override { - bool breaking = false; - size_t currentCase = 1; - bool hasMatched = false; + Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override { + bool breaking = false; + size_t currentCase = 1; + bool hasMatched = false; - chaiscript::eval::detail::Scope_Push_Pop spp(t_ss); + chaiscript::eval::detail::Scope_Push_Pop spp(t_ss); - Boxed_Value match_value(this->children[0]->eval(t_ss)); + Boxed_Value match_value(this->children[0]->eval(t_ss)); - while (!breaking && (currentCase < this->children.size())) { - try { - if (this->children[currentCase]->identifier == AST_Node_Type::Case) { - //This is a little odd, but because want to see both the switch and the case simultaneously, I do a downcast here. - try { - std::array p{match_value, this->children[currentCase]->children[0]->eval(t_ss)}; - if (hasMatched || boxed_cast(t_ss->call_function("==", m_loc, Function_Params{p}, t_ss.conversions()))) { - this->children[currentCase]->eval(t_ss); - hasMatched = true; - } - } - catch (const exception::bad_boxed_cast &) { - throw exception::eval_error("Internal error: case guard evaluation not boolean"); + while (!breaking && (currentCase < this->children.size())) { + try { + if (this->children[currentCase]->identifier == AST_Node_Type::Case) { + // This is a little odd, but because want to see both the switch and the case simultaneously, I do a downcast here. + try { + std::array p{match_value, this->children[currentCase]->children[0]->eval(t_ss)}; + if (hasMatched || boxed_cast(t_ss->call_function("==", m_loc, Function_Params{p}, t_ss.conversions()))) { + this->children[currentCase]->eval(t_ss); + hasMatched = true; } + } catch (const exception::bad_boxed_cast &) { + throw exception::eval_error("Internal error: case guard evaluation not boolean"); } - else if (this->children[currentCase]->identifier == AST_Node_Type::Default) { - this->children[currentCase]->eval(t_ss); - hasMatched = true; - } + } else if (this->children[currentCase]->identifier == AST_Node_Type::Default) { + this->children[currentCase]->eval(t_ss); + hasMatched = true; } - catch (detail::Break_Loop &) { - breaking = true; - } - ++currentCase; + } catch (detail::Break_Loop &) { + breaking = true; } - return void_var(); + ++currentCase; } + return void_var(); + } - mutable std::atomic_uint_fast32_t m_loc = {0}; + mutable std::atomic_uint_fast32_t m_loc = {0}; }; template struct Case_AST_Node final : AST_Node_Impl { - Case_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector> t_children) : - AST_Node_Impl(std::move(t_ast_node_text), AST_Node_Type::Case, std::move(t_loc), std::move(t_children)) - { assert(this->children.size() == 2); /* how many children does it have? */ } + Case_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector> t_children) + : AST_Node_Impl(std::move(t_ast_node_text), AST_Node_Type::Case, std::move(t_loc), std::move(t_children)) { + assert(this->children.size() == 2); /* how many children does it have? */ + } - Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override { - chaiscript::eval::detail::Scope_Push_Pop spp(t_ss); + Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override { + chaiscript::eval::detail::Scope_Push_Pop spp(t_ss); - this->children[1]->eval(t_ss); + this->children[1]->eval(t_ss); - return void_var(); - } + return void_var(); + } }; template struct Default_AST_Node final : AST_Node_Impl { - Default_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector> t_children) : - AST_Node_Impl(std::move(t_ast_node_text), AST_Node_Type::Default, std::move(t_loc), std::move(t_children)) - { assert(this->children.size() == 1); } + Default_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector> t_children) + : AST_Node_Impl(std::move(t_ast_node_text), AST_Node_Type::Default, std::move(t_loc), std::move(t_children)) { + assert(this->children.size() == 1); + } - Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override { - chaiscript::eval::detail::Scope_Push_Pop spp(t_ss); + Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override { + chaiscript::eval::detail::Scope_Push_Pop spp(t_ss); - this->children[0]->eval(t_ss); + this->children[0]->eval(t_ss); - return void_var(); - } + return void_var(); + } }; - template struct Inline_Array_AST_Node final : AST_Node_Impl { - Inline_Array_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector> t_children) : - AST_Node_Impl(std::move(t_ast_node_text), AST_Node_Type::Inline_Array, std::move(t_loc), std::move(t_children)) { } + Inline_Array_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector> t_children) + : AST_Node_Impl(std::move(t_ast_node_text), AST_Node_Type::Inline_Array, std::move(t_loc), std::move(t_children)) { + } - Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override { - try { - std::vector vec; - if (!this->children.empty()) { - vec.reserve(this->children[0]->children.size()); - for (const auto &child : this->children[0]->children) { - vec.push_back(detail::clone_if_necessary(child->eval(t_ss), m_loc, t_ss)); - } + Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override { + try { + std::vector vec; + if (!this->children.empty()) { + vec.reserve(this->children[0]->children.size()); + for (const auto &child : this->children[0]->children) { + vec.push_back(detail::clone_if_necessary(child->eval(t_ss), m_loc, t_ss)); } - return const_var(std::move(vec)); - } - catch (const exception::dispatch_error &) { - throw exception::eval_error("Can not find appropriate 'clone' or copy constructor for vector elements"); } + return const_var(std::move(vec)); + } catch (const exception::dispatch_error &) { + throw exception::eval_error("Can not find appropriate 'clone' or copy constructor for vector elements"); } + } - private: - mutable std::atomic_uint_fast32_t m_loc = {0}; + private: + mutable std::atomic_uint_fast32_t m_loc = {0}; }; template struct Inline_Map_AST_Node final : AST_Node_Impl { - Inline_Map_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector> t_children) : - AST_Node_Impl(std::move(t_ast_node_text), AST_Node_Type::Inline_Map, std::move(t_loc), std::move(t_children)) { } + Inline_Map_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector> t_children) + : AST_Node_Impl(std::move(t_ast_node_text), AST_Node_Type::Inline_Map, std::move(t_loc), std::move(t_children)) { + } - Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override - { - try { - std::map retval; + Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override { + try { + std::map retval; - for (const auto &child : this->children[0]->children) { - retval.insert(std::make_pair(t_ss->boxed_cast(child->children[0]->eval(t_ss)), - detail::clone_if_necessary(child->children[1]->eval(t_ss), m_loc, t_ss))); - } - - return const_var(std::move(retval)); - } - catch (const exception::dispatch_error &e) { - throw exception::eval_error("Can not find appropriate copy constructor or 'clone' while inserting into Map.", e.parameters, e.functions, false, *t_ss); + for (const auto &child : this->children[0]->children) { + retval.insert(std::make_pair(t_ss->boxed_cast(child->children[0]->eval(t_ss)), + detail::clone_if_necessary(child->children[1]->eval(t_ss), m_loc, t_ss))); } + + return const_var(std::move(retval)); + } catch (const exception::dispatch_error &e) { + throw exception::eval_error("Can not find appropriate copy constructor or 'clone' while inserting into Map.", + e.parameters, + e.functions, + false, + *t_ss); } + } - private: - mutable std::atomic_uint_fast32_t m_loc = {0}; + private: + mutable std::atomic_uint_fast32_t m_loc = {0}; }; template struct Return_AST_Node final : AST_Node_Impl { - Return_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector> t_children) : - AST_Node_Impl(std::move(t_ast_node_text), AST_Node_Type::Return, std::move(t_loc), std::move(t_children)) { } + Return_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector> t_children) + : AST_Node_Impl(std::move(t_ast_node_text), AST_Node_Type::Return, std::move(t_loc), std::move(t_children)) { + } - Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override{ - if (!this->children.empty()) { - throw detail::Return_Value{this->children[0]->eval(t_ss)}; - } - else { - throw detail::Return_Value{void_var()}; - } + Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override { + if (!this->children.empty()) { + throw detail::Return_Value{this->children[0]->eval(t_ss)}; + } else { + throw detail::Return_Value{void_var()}; } + } }; template struct File_AST_Node final : AST_Node_Impl { - File_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector> t_children) : - AST_Node_Impl(std::move(t_ast_node_text), AST_Node_Type::File, std::move(t_loc), std::move(t_children)) { } + File_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector> t_children) + : AST_Node_Impl(std::move(t_ast_node_text), AST_Node_Type::File, std::move(t_loc), std::move(t_children)) { + } - Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override { - try { - const auto num_children = this->children.size(); + Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override { + try { + const auto num_children = this->children.size(); - if (num_children > 0) { - for (size_t i = 0; i < num_children-1; ++i) { - this->children[i]->eval(t_ss); - } - return this->children.back()->eval(t_ss); - } else { - return void_var(); + if (num_children > 0) { + for (size_t i = 0; i < num_children - 1; ++i) { + this->children[i]->eval(t_ss); } - } catch (const detail::Continue_Loop &) { - throw exception::eval_error("Unexpected `continue` statement outside of a loop"); - } catch (const detail::Break_Loop &) { - throw exception::eval_error("Unexpected `break` statement outside of a loop"); + return this->children.back()->eval(t_ss); + } else { + return void_var(); } + } catch (const detail::Continue_Loop &) { + throw exception::eval_error("Unexpected `continue` statement outside of a loop"); + } catch (const detail::Break_Loop &) { + throw exception::eval_error("Unexpected `break` statement outside of a loop"); } + } }; template struct Reference_AST_Node final : AST_Node_Impl { - Reference_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector> t_children) : - AST_Node_Impl(std::move(t_ast_node_text), AST_Node_Type::Reference, std::move(t_loc), std::move(t_children)) - { assert(this->children.size() == 1); } + Reference_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector> t_children) + : AST_Node_Impl(std::move(t_ast_node_text), AST_Node_Type::Reference, std::move(t_loc), std::move(t_children)) { + assert(this->children.size() == 1); + } - Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override{ - Boxed_Value bv; - t_ss.add_object(this->children[0]->text, bv); - return bv; - } + Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override { + Boxed_Value bv; + t_ss.add_object(this->children[0]->text, bv); + return bv; + } }; template struct Prefix_AST_Node final : AST_Node_Impl { - Prefix_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector> t_children) : - AST_Node_Impl(std::move(t_ast_node_text), AST_Node_Type::Prefix, std::move(t_loc), std::move(t_children)), - m_oper(Operators::to_operator(this->text, true)) - { } + Prefix_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector> t_children) + : AST_Node_Impl(std::move(t_ast_node_text), AST_Node_Type::Prefix, std::move(t_loc), std::move(t_children)) + , m_oper(Operators::to_operator(this->text, true)) { + } - Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override{ - Boxed_Value bv(this->children[0]->eval(t_ss)); + Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override { + Boxed_Value bv(this->children[0]->eval(t_ss)); - try { - // short circuit arithmetic operations - if (m_oper != Operators::Opers::invalid && m_oper != Operators::Opers::bitwise_and && bv.get_type_info().is_arithmetic()) - { - if ((m_oper == Operators::Opers::pre_increment || m_oper == Operators::Opers::pre_decrement) && bv.is_const()) - { - throw exception::eval_error("Error with prefix operator evaluation: cannot modify constant value."); - } - return Boxed_Number::do_oper(m_oper, bv); - } else { - chaiscript::eval::detail::Function_Push_Pop fpp(t_ss); - fpp.save_params(Function_Params{bv}); - return t_ss->call_function(this->text, m_loc, Function_Params{bv}, t_ss.conversions()); + try { + // short circuit arithmetic operations + if (m_oper != Operators::Opers::invalid && m_oper != Operators::Opers::bitwise_and && bv.get_type_info().is_arithmetic()) { + if ((m_oper == Operators::Opers::pre_increment || m_oper == Operators::Opers::pre_decrement) && bv.is_const()) { + throw exception::eval_error("Error with prefix operator evaluation: cannot modify constant value."); } - } catch (const exception::dispatch_error &e) { - throw exception::eval_error("Error with prefix operator evaluation: '" + this->text + "'", e.parameters, e.functions, false, *t_ss); + return Boxed_Number::do_oper(m_oper, bv); + } else { + chaiscript::eval::detail::Function_Push_Pop fpp(t_ss); + fpp.save_params(Function_Params{bv}); + return t_ss->call_function(this->text, m_loc, Function_Params{bv}, t_ss.conversions()); } + } catch (const exception::dispatch_error &e) { + throw exception::eval_error("Error with prefix operator evaluation: '" + this->text + "'", e.parameters, e.functions, false, *t_ss); } + } - private: - Operators::Opers m_oper = Operators::Opers::invalid; - mutable std::atomic_uint_fast32_t m_loc = {0}; + private: + Operators::Opers m_oper = Operators::Opers::invalid; + mutable std::atomic_uint_fast32_t m_loc = {0}; }; template struct Break_AST_Node final : AST_Node_Impl { - Break_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector> t_children) : - AST_Node_Impl(std::move(t_ast_node_text), AST_Node_Type::Break, std::move(t_loc), std::move(t_children)) { } + Break_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector> t_children) + : AST_Node_Impl(std::move(t_ast_node_text), AST_Node_Type::Break, std::move(t_loc), std::move(t_children)) { + } - Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &) const override{ - throw detail::Break_Loop(); - } + Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &) const override { throw detail::Break_Loop(); } }; template struct Continue_AST_Node final : AST_Node_Impl { - Continue_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector> t_children) : - AST_Node_Impl(std::move(t_ast_node_text), AST_Node_Type::Continue, std::move(t_loc), std::move(t_children)) { } + Continue_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector> t_children) + : AST_Node_Impl(std::move(t_ast_node_text), AST_Node_Type::Continue, std::move(t_loc), std::move(t_children)) { + } - Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &) const override{ - throw detail::Continue_Loop(); - } + Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &) const override { throw detail::Continue_Loop(); } }; template struct Noop_AST_Node final : AST_Node_Impl { - Noop_AST_Node() : - AST_Node_Impl("", AST_Node_Type::Noop, Parse_Location()) - { } + Noop_AST_Node() + : AST_Node_Impl("", AST_Node_Type::Noop, Parse_Location()) { + } - Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &) const override{ - // It's a no-op, that evaluates to "void" - return val; - } + Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &) const override { + // It's a no-op, that evaluates to "void" + return val; + } - Boxed_Value val = void_var(); + Boxed_Value val = void_var(); }; template struct Map_Pair_AST_Node final : AST_Node_Impl { - Map_Pair_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector> t_children) : - AST_Node_Impl(std::move(t_ast_node_text), AST_Node_Type::Map_Pair, std::move(t_loc), std::move(t_children)) { } + Map_Pair_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector> t_children) + : AST_Node_Impl(std::move(t_ast_node_text), AST_Node_Type::Map_Pair, std::move(t_loc), std::move(t_children)) { + } }; template struct Value_Range_AST_Node final : AST_Node_Impl { - Value_Range_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector> t_children) : - AST_Node_Impl(std::move(t_ast_node_text), AST_Node_Type::Value_Range, std::move(t_loc), std::move(t_children)) { } + Value_Range_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector> t_children) + : AST_Node_Impl(std::move(t_ast_node_text), AST_Node_Type::Value_Range, std::move(t_loc), std::move(t_children)) { + } }; template struct Inline_Range_AST_Node final : AST_Node_Impl { - Inline_Range_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector> t_children) : - AST_Node_Impl(std::move(t_ast_node_text), AST_Node_Type::Inline_Range, std::move(t_loc), std::move(t_children)) { } + Inline_Range_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector> t_children) + : AST_Node_Impl(std::move(t_ast_node_text), AST_Node_Type::Inline_Range, std::move(t_loc), std::move(t_children)) { + } - Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override{ - try { - std::array params{ - this->children[0]->children[0]->children[0]->eval(t_ss), - this->children[0]->children[0]->children[1]->eval(t_ss) - }; + Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override { + try { + std::array params{this->children[0]->children[0]->children[0]->eval(t_ss), + this->children[0]->children[0]->children[1]->eval(t_ss)}; - return t_ss->call_function("generate_range", m_loc, Function_Params{params}, t_ss.conversions()); - } - catch (const exception::dispatch_error &e) { - throw exception::eval_error("Unable to generate range vector, while calling 'generate_range'", e.parameters, e.functions, false, *t_ss); - } + return t_ss->call_function("generate_range", m_loc, Function_Params{params}, t_ss.conversions()); + } catch (const exception::dispatch_error &e) { + throw exception::eval_error("Unable to generate range vector, while calling 'generate_range'", e.parameters, e.functions, false, *t_ss); } + } - private: - mutable std::atomic_uint_fast32_t m_loc = {0}; + private: + mutable std::atomic_uint_fast32_t m_loc = {0}; }; template struct Try_AST_Node final : AST_Node_Impl { - Try_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector> t_children) : - AST_Node_Impl(std::move(t_ast_node_text), AST_Node_Type::Try, std::move(t_loc), std::move(t_children)) { } + Try_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector> t_children) + : AST_Node_Impl(std::move(t_ast_node_text), AST_Node_Type::Try, std::move(t_loc), std::move(t_children)) { + } - Boxed_Value handle_exception(const chaiscript::detail::Dispatch_State &t_ss, const Boxed_Value &t_except) const - { - Boxed_Value retval; + Boxed_Value handle_exception(const chaiscript::detail::Dispatch_State &t_ss, const Boxed_Value &t_except) const { + Boxed_Value retval; - size_t end_point = this->children.size(); - if (this->children.back()->identifier == AST_Node_Type::Finally) { - assert(end_point > 0); - end_point = this->children.size() - 1; - } - for (size_t i = 1; i < end_point; ++i) { - chaiscript::eval::detail::Scope_Push_Pop catch_scope(t_ss); - auto &catch_block = *this->children[i]; - - if (catch_block.children.size() == 1) { - //No variable capture - retval = catch_block.children[0]->eval(t_ss); - break; - } else if (catch_block.children.size() == 2 || catch_block.children.size() == 3) { - const auto name = Arg_List_AST_Node::get_arg_name(*catch_block.children[0]); - - if (dispatch::Param_Types( - std::vector>{Arg_List_AST_Node::get_arg_type(*catch_block.children[0], t_ss)} - ).match(Function_Params{t_except}, t_ss.conversions()).first) - { - t_ss.add_object(name, t_except); - - if (catch_block.children.size() == 2) { - //Variable capture - retval = catch_block.children[1]->eval(t_ss); - break; - } - } - } - else { - if (this->children.back()->identifier == AST_Node_Type::Finally) { - this->children.back()->children[0]->eval(t_ss); - } - throw exception::eval_error("Internal error: catch block size unrecognized"); - } - } - - return retval; + size_t end_point = this->children.size(); + if (this->children.back()->identifier == AST_Node_Type::Finally) { + assert(end_point > 0); + end_point = this->children.size() - 1; } + for (size_t i = 1; i < end_point; ++i) { + chaiscript::eval::detail::Scope_Push_Pop catch_scope(t_ss); + auto &catch_block = *this->children[i]; - Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override { - Boxed_Value retval; + if (catch_block.children.size() == 1) { + // No variable capture + retval = catch_block.children[0]->eval(t_ss); + break; + } else if (catch_block.children.size() == 2 || catch_block.children.size() == 3) { + const auto name = Arg_List_AST_Node::get_arg_name(*catch_block.children[0]); - chaiscript::eval::detail::Scope_Push_Pop spp(t_ss); + if (dispatch::Param_Types( + std::vector>{Arg_List_AST_Node::get_arg_type(*catch_block.children[0], t_ss)}) + .match(Function_Params{t_except}, t_ss.conversions()) + .first) { + t_ss.add_object(name, t_except); - - try { - retval = this->children[0]->eval(t_ss); - } - catch (const exception::eval_error &e) { - retval = handle_exception(t_ss, Boxed_Value(std::ref(e))); - } - catch (const std::runtime_error &e) { - retval = handle_exception(t_ss, Boxed_Value(std::ref(e))); - } - catch (const std::out_of_range &e) { - retval = handle_exception(t_ss, Boxed_Value(std::ref(e))); - } - catch (const std::exception &e) { - retval = handle_exception(t_ss, Boxed_Value(std::ref(e))); - } - catch (Boxed_Value &e) { - retval = handle_exception(t_ss, e); - } - catch (...) { + if (catch_block.children.size() == 2) { + // Variable capture + retval = catch_block.children[1]->eval(t_ss); + break; + } + } + } else { if (this->children.back()->identifier == AST_Node_Type::Finally) { this->children.back()->children[0]->eval(t_ss); } - throw; + throw exception::eval_error("Internal error: catch block size unrecognized"); } - - - if (this->children.back()->identifier == AST_Node_Type::Finally) { - retval = this->children.back()->children[0]->eval(t_ss); - } - - return retval; } + return retval; + } + + Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override { + Boxed_Value retval; + + chaiscript::eval::detail::Scope_Push_Pop spp(t_ss); + + try { + retval = this->children[0]->eval(t_ss); + } catch (const exception::eval_error &e) { + retval = handle_exception(t_ss, Boxed_Value(std::ref(e))); + } catch (const std::runtime_error &e) { + retval = handle_exception(t_ss, Boxed_Value(std::ref(e))); + } catch (const std::out_of_range &e) { + retval = handle_exception(t_ss, Boxed_Value(std::ref(e))); + } catch (const std::exception &e) { + retval = handle_exception(t_ss, Boxed_Value(std::ref(e))); + } catch (Boxed_Value &e) { + retval = handle_exception(t_ss, e); + } catch (...) { + if (this->children.back()->identifier == AST_Node_Type::Finally) { + this->children.back()->children[0]->eval(t_ss); + } + throw; + } + + if (this->children.back()->identifier == AST_Node_Type::Finally) { + retval = this->children.back()->children[0]->eval(t_ss); + } + + return retval; + } }; template struct Catch_AST_Node final : AST_Node_Impl { - Catch_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector> t_children) : - AST_Node_Impl(std::move(t_ast_node_text), AST_Node_Type::Catch, std::move(t_loc), std::move(t_children)) { } + Catch_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector> t_children) + : AST_Node_Impl(std::move(t_ast_node_text), AST_Node_Type::Catch, std::move(t_loc), std::move(t_children)) { + } }; template struct Finally_AST_Node final : AST_Node_Impl { - Finally_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector> t_children) : - AST_Node_Impl(std::move(t_ast_node_text), AST_Node_Type::Finally, std::move(t_loc), std::move(t_children)) { } + Finally_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector> t_children) + : AST_Node_Impl(std::move(t_ast_node_text), AST_Node_Type::Finally, std::move(t_loc), std::move(t_children)) { + } }; template struct Method_AST_Node final : AST_Node_Impl { - std::shared_ptr> m_body_node; - std::shared_ptr> m_guard_node; + std::shared_ptr> m_body_node; + std::shared_ptr> m_guard_node; - Method_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector> t_children) : - AST_Node_Impl(std::move(t_ast_node_text), AST_Node_Type::Method, std::move(t_loc), - std::vector>(std::make_move_iterator(t_children.begin()), - std::make_move_iterator(std::prev(t_children.end(), Def_AST_Node::has_guard(t_children, 1)?2:1))) - ), - m_body_node(Def_AST_Node::get_body_node(std::move(t_children))), - m_guard_node(Def_AST_Node::get_guard_node(std::move(t_children), t_children.size()-this->children.size()==2)) - { - } + Method_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector> t_children) + : AST_Node_Impl(std::move(t_ast_node_text), + AST_Node_Type::Method, + std::move(t_loc), + std::vector>(std::make_move_iterator(t_children.begin()), + std::make_move_iterator( + std::prev(t_children.end(), Def_AST_Node::has_guard(t_children, 1) ? 2 : 1)))) + , m_body_node(Def_AST_Node::get_body_node(std::move(t_children))) + , m_guard_node(Def_AST_Node::get_guard_node(std::move(t_children), t_children.size() - this->children.size() == 2)) { + } - Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override{ + Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override { + AST_Node_Impl_Ptr guardnode; - AST_Node_Impl_Ptr guardnode; + const std::string &class_name = this->children[0]->text; - const std::string & class_name = this->children[0]->text; + // The first param of a method is always the implied this ptr. + std::vector t_param_names{"this"}; + dispatch::Param_Types param_types; - //The first param of a method is always the implied this ptr. - std::vector t_param_names{"this"}; - dispatch::Param_Types param_types; - - if ((this->children.size() > 2) - && (this->children[2]->identifier == AST_Node_Type::Arg_List)) { - auto args = Arg_List_AST_Node::get_arg_names(*this->children[2]); - t_param_names.insert(t_param_names.end(), args.begin(), args.end()); - param_types = Arg_List_AST_Node::get_arg_types(*this->children[2], t_ss); - } - - const size_t numparams = t_param_names.size(); - - std::shared_ptr guard; - std::reference_wrapper engine(*t_ss); - if (m_guard_node) { - guard = dispatch::make_dynamic_proxy_function( - [engine, t_param_names, guardnode = m_guard_node](const Function_Params &t_params) { - return chaiscript::eval::detail::eval_function(engine, *guardnode, t_param_names, t_params); - }, - static_cast(numparams), m_guard_node); - } - - try { - const std::string & function_name = this->children[1]->text; - - if (function_name == class_name) { - param_types.push_front(class_name, Type_Info()); - - t_ss->add( - std::make_shared(class_name, - dispatch::make_dynamic_proxy_function( - [engine, t_param_names, node = m_body_node](const Function_Params &t_params) { - return chaiscript::eval::detail::eval_function(engine, *node, t_param_names, t_params); - }, - static_cast(numparams), m_body_node, param_types, guard - ) - ), - function_name); - - } else { - // if the type is unknown, then this generates a function that looks up the type - // at runtime. Defining the type first before this is called is better - auto type = t_ss->get_type(class_name, false); - param_types.push_front(class_name, type); - - t_ss->add( - std::make_shared(class_name, - dispatch::make_dynamic_proxy_function( - [engine, t_param_names, node = m_body_node](const Function_Params &t_params) { - return chaiscript::eval::detail::eval_function(engine, *node, t_param_names, t_params); - }, - static_cast(numparams), m_body_node, param_types, guard), type), - function_name); - } - } catch (const exception::name_conflict_error &e) { - throw exception::eval_error("Method redefined '" + e.name() + "'"); - } - return void_var(); + if ((this->children.size() > 2) && (this->children[2]->identifier == AST_Node_Type::Arg_List)) { + auto args = Arg_List_AST_Node::get_arg_names(*this->children[2]); + t_param_names.insert(t_param_names.end(), args.begin(), args.end()); + param_types = Arg_List_AST_Node::get_arg_types(*this->children[2], t_ss); } + const size_t numparams = t_param_names.size(); + + std::shared_ptr guard; + std::reference_wrapper engine(*t_ss); + if (m_guard_node) { + guard = dispatch::make_dynamic_proxy_function( + [engine, t_param_names, guardnode = m_guard_node](const Function_Params &t_params) { + return chaiscript::eval::detail::eval_function(engine, *guardnode, t_param_names, t_params); + }, + static_cast(numparams), + m_guard_node); + } + + try { + const std::string &function_name = this->children[1]->text; + + if (function_name == class_name) { + param_types.push_front(class_name, Type_Info()); + + t_ss->add(std::make_shared( + class_name, + dispatch::make_dynamic_proxy_function( + [engine, t_param_names, node = m_body_node](const Function_Params &t_params) { + return chaiscript::eval::detail::eval_function(engine, *node, t_param_names, t_params); + }, + static_cast(numparams), + m_body_node, + param_types, + guard)), + function_name); + + } else { + // if the type is unknown, then this generates a function that looks up the type + // at runtime. Defining the type first before this is called is better + auto type = t_ss->get_type(class_name, false); + param_types.push_front(class_name, type); + + t_ss->add(std::make_shared( + class_name, + dispatch::make_dynamic_proxy_function( + [engine, t_param_names, node = m_body_node](const Function_Params &t_params) { + return chaiscript::eval::detail::eval_function(engine, *node, t_param_names, t_params); + }, + static_cast(numparams), + m_body_node, + param_types, + guard), + type), + function_name); + } + } catch (const exception::name_conflict_error &e) { + throw exception::eval_error("Method redefined '" + e.name() + "'"); + } + return void_var(); + } }; template struct Attr_Decl_AST_Node final : AST_Node_Impl { - Attr_Decl_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector> t_children) : - AST_Node_Impl(std::move(t_ast_node_text), AST_Node_Type::Attr_Decl, std::move(t_loc), std::move(t_children)) { } + Attr_Decl_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector> t_children) + : AST_Node_Impl(std::move(t_ast_node_text), AST_Node_Type::Attr_Decl, std::move(t_loc), std::move(t_children)) { + } - Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override - { - std::string class_name = this->children[0]->text; + Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override { + std::string class_name = this->children[0]->text; - try { - std::string attr_name = this->children[1]->text; + try { + std::string attr_name = this->children[1]->text; - t_ss->add( - std::make_shared( - std::move(class_name), - fun([attr_name](dispatch::Dynamic_Object &t_obj) { - return t_obj.get_attr(attr_name); - }), - true + t_ss->add(std::make_shared(std::move(class_name), + fun([attr_name](dispatch::Dynamic_Object &t_obj) { + return t_obj.get_attr(attr_name); + }), + true - ), this->children[1]->text); - } catch (const exception::name_conflict_error &e) { - throw exception::eval_error("Attribute redefined '" + e.name() + "'"); - } - return void_var(); + ), + this->children[1]->text); + } catch (const exception::name_conflict_error &e) { + throw exception::eval_error("Attribute redefined '" + e.name() + "'"); } - + return void_var(); + } }; - template struct Logical_And_AST_Node final : AST_Node_Impl { - Logical_And_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector> t_children) : - AST_Node_Impl(std::move(t_ast_node_text), AST_Node_Type::Logical_And, std::move(t_loc), std::move(t_children)) - { assert(this->children.size() == 2); } - - Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override - { - return const_var(this->get_bool_condition(this->children[0]->eval(t_ss), t_ss) - && this->get_bool_condition(this->children[1]->eval(t_ss), t_ss)); - } + Logical_And_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector> t_children) + : AST_Node_Impl(std::move(t_ast_node_text), AST_Node_Type::Logical_And, std::move(t_loc), std::move(t_children)) { + assert(this->children.size() == 2); + } + Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override { + return const_var(this->get_bool_condition(this->children[0]->eval(t_ss), t_ss) + && this->get_bool_condition(this->children[1]->eval(t_ss), t_ss)); + } }; template struct Logical_Or_AST_Node final : AST_Node_Impl { - Logical_Or_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector> t_children) : - AST_Node_Impl(std::move(t_ast_node_text), AST_Node_Type::Logical_Or, std::move(t_loc), std::move(t_children)) - { assert(this->children.size() == 2); } + Logical_Or_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector> t_children) + : AST_Node_Impl(std::move(t_ast_node_text), AST_Node_Type::Logical_Or, std::move(t_loc), std::move(t_children)) { + assert(this->children.size() == 2); + } - Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override - { - return const_var(this->get_bool_condition(this->children[0]->eval(t_ss), t_ss) - || this->get_bool_condition(this->children[1]->eval(t_ss), t_ss)); - } + Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override { + return const_var(this->get_bool_condition(this->children[0]->eval(t_ss), t_ss) + || this->get_bool_condition(this->children[1]->eval(t_ss), t_ss)); + } }; - } + } // namespace eval - -} +} // namespace chaiscript #endif /* CHAISCRIPT_EVAL_HPP_ */ - diff --git a/include/chaiscript/language/chaiscript_optimizer.hpp b/include/chaiscript/language/chaiscript_optimizer.hpp index d44d2cb6..d9f706b6 100644 --- a/include/chaiscript/language/chaiscript_optimizer.hpp +++ b/include/chaiscript/language/chaiscript_optimizer.hpp @@ -9,76 +9,68 @@ #include "chaiscript_eval.hpp" - namespace chaiscript { namespace optimizer { - - template - struct Optimizer : T... - { + template + struct Optimizer : T... { Optimizer() = default; - explicit Optimizer(T ... t) - : T(std::move(t))... - { + explicit Optimizer(T... t) + : T(std::move(t))... { } template auto optimize(eval::AST_Node_Impl_Ptr p) { - ( (p = static_cast(*this).optimize(std::move(p))), ... ); + ((p = static_cast(*this).optimize(std::move(p))), ...); return p; } }; template - eval::AST_Node_Impl &child_at(eval::AST_Node_Impl &node, const size_t offset) noexcept { - if (node.children[offset]->identifier == AST_Node_Type::Compiled) { - return *(dynamic_cast &>(*node.children[offset]).m_original_node); - } else { - return *node.children[offset]; - } + eval::AST_Node_Impl &child_at(eval::AST_Node_Impl &node, const size_t offset) noexcept { + if (node.children[offset]->identifier == AST_Node_Type::Compiled) { + return *(dynamic_cast &>(*node.children[offset]).m_original_node); + } else { + return *node.children[offset]; } + } template - const eval::AST_Node_Impl &child_at(const eval::AST_Node_Impl &node, const size_t offset) noexcept { - if (node.children[offset]->identifier == AST_Node_Type::Compiled) { - return *(dynamic_cast &>(*node.children[offset]).m_original_node); - } else { - return *node.children[offset]; - } - - - /* - if (node->identifier == AST_Node_Type::Compiled) { - return dynamic_cast&>(*node).m_original_node->children[offset]; - } else { - return node->children[offset]; - } - */ + const eval::AST_Node_Impl &child_at(const eval::AST_Node_Impl &node, const size_t offset) noexcept { + if (node.children[offset]->identifier == AST_Node_Type::Compiled) { + return *(dynamic_cast &>(*node.children[offset]).m_original_node); + } else { + return *node.children[offset]; } + /* + if (node->identifier == AST_Node_Type::Compiled) { + return dynamic_cast&>(*node).m_original_node->children[offset]; + } else { + return node->children[offset]; + } + */ + } + template - auto child_count(const eval::AST_Node_Impl &node) noexcept { - if (node.identifier == AST_Node_Type::Compiled) { - return dynamic_cast&>(node).m_original_node->children.size(); - } else { - return node.children.size(); - } + auto child_count(const eval::AST_Node_Impl &node) noexcept { + if (node.identifier == AST_Node_Type::Compiled) { + return dynamic_cast &>(node).m_original_node->children.size(); + } else { + return node.children.size(); } + } template - auto make_compiled_node(eval::AST_Node_Impl_Ptr original_node, std::vector> children, Callable callable) - { - return chaiscript::make_unique, eval::Compiled_AST_Node>(std::move(original_node), std::move(children), std::move(callable)); - } - + auto make_compiled_node(eval::AST_Node_Impl_Ptr original_node, std::vector> children, Callable callable) { + return chaiscript::make_unique, eval::Compiled_AST_Node>(std::move(original_node), + std::move(children), + std::move(callable)); + } struct Return { template - auto optimize(eval::AST_Node_Impl_Ptr p) - { - if ( (p->identifier == AST_Node_Type::Def || p->identifier == AST_Node_Type::Lambda) - && !p->children.empty()) - { + auto optimize(eval::AST_Node_Impl_Ptr p) { + if ((p->identifier == AST_Node_Type::Def || p->identifier == AST_Node_Type::Lambda) && !p->children.empty()) { auto &last_child = p->children.back(); if (last_child->identifier == AST_Node_Type::Block) { auto &block_last_child = last_child->children.back(); @@ -95,9 +87,9 @@ namespace chaiscript { }; template - bool contains_var_decl_in_scope(const eval::AST_Node_Impl &node) noexcept - { - if (node.identifier == AST_Node_Type::Var_Decl || node.identifier == AST_Node_Type::Assign_Decl || node.identifier == AST_Node_Type::Reference) { + bool contains_var_decl_in_scope(const eval::AST_Node_Impl &node) noexcept { + if (node.identifier == AST_Node_Type::Var_Decl || node.identifier == AST_Node_Type::Assign_Decl + || node.identifier == AST_Node_Type::Reference) { return true; } @@ -105,10 +97,8 @@ namespace chaiscript { for (size_t i = 0; i < num; ++i) { const auto &child = child_at(node, i); - if (child.identifier != AST_Node_Type::Block - && child.identifier != AST_Node_Type::For - && child.identifier != AST_Node_Type::Ranged_For - && contains_var_decl_in_scope(child)) { + if (child.identifier != AST_Node_Type::Block && child.identifier != AST_Node_Type::For + && child.identifier != AST_Node_Type::Ranged_For && contains_var_decl_in_scope(child)) { return true; } } @@ -119,15 +109,14 @@ namespace chaiscript { struct Block { template auto optimize(eval::AST_Node_Impl_Ptr node) { - if (node->identifier == AST_Node_Type::Block) - { - if (!contains_var_decl_in_scope(*node)) - { + if (node->identifier == AST_Node_Type::Block) { + if (!contains_var_decl_in_scope(*node)) { if (node->children.size() == 1) { return std::move(node->children[0]); } else { - return chaiscript::make_unique, eval::Scopeless_Block_AST_Node>(node->text, node->location, - std::move(node->children)); + return chaiscript::make_unique, eval::Scopeless_Block_AST_Node>(node->text, + node->location, + std::move(node->children)); } } } @@ -138,105 +127,91 @@ namespace chaiscript { struct Dead_Code { template - auto optimize(eval::AST_Node_Impl_Ptr node) { - if (node->identifier == AST_Node_Type::Block) - { - std::vector keepers; - const auto num_children = node->children.size(); - keepers.reserve(num_children); + auto optimize(eval::AST_Node_Impl_Ptr node) { + if (node->identifier == AST_Node_Type::Block) { + std::vector keepers; + const auto num_children = node->children.size(); + keepers.reserve(num_children); - for (size_t i = 0; i < num_children; ++i) { - const auto &child = *node->children[i]; - if ( (child.identifier != AST_Node_Type::Id - && child.identifier != AST_Node_Type::Constant - && child.identifier != AST_Node_Type::Noop) - || i == num_children - 1) { - keepers.push_back(i); - } + for (size_t i = 0; i < num_children; ++i) { + const auto &child = *node->children[i]; + if ((child.identifier != AST_Node_Type::Id && child.identifier != AST_Node_Type::Constant + && child.identifier != AST_Node_Type::Noop) + || i == num_children - 1) { + keepers.push_back(i); } - - if (keepers.size() == num_children) { - return node; - } else { - const auto new_children = [&](){ - std::vector> retval; - for (const auto x : keepers) - { - retval.push_back(std::move(node->children[x])); - } - return retval; - }; - - return chaiscript::make_unique, eval::Block_AST_Node>(node->text, node->location, new_children()); - } - } else { - return node; } + + if (keepers.size() == num_children) { + return node; + } else { + const auto new_children = [&]() { + std::vector> retval; + for (const auto x : keepers) { + retval.push_back(std::move(node->children[x])); + } + return retval; + }; + + return chaiscript::make_unique, eval::Block_AST_Node>(node->text, node->location, new_children()); + } + } else { + return node; } + } }; struct Unused_Return { template - auto optimize(eval::AST_Node_Impl_Ptr node) { - if ((node->identifier == AST_Node_Type::Block - || node->identifier == AST_Node_Type::Scopeless_Block) - && !node->children.empty()) - { - for (size_t i = 0; i < node->children.size()-1; ++i) { - auto child = node->children[i].get(); - if (child->identifier == AST_Node_Type::Fun_Call) { - node->children[i] = chaiscript::make_unique, eval::Unused_Return_Fun_Call_AST_Node>(child->text, child->location, - std::move(child->children)); - } + auto optimize(eval::AST_Node_Impl_Ptr node) { + if ((node->identifier == AST_Node_Type::Block || node->identifier == AST_Node_Type::Scopeless_Block) && !node->children.empty()) { + for (size_t i = 0; i < node->children.size() - 1; ++i) { + auto child = node->children[i].get(); + if (child->identifier == AST_Node_Type::Fun_Call) { + node->children[i] + = chaiscript::make_unique, eval::Unused_Return_Fun_Call_AST_Node>(child->text, + child->location, + std::move(child->children)); } - } else if ((node->identifier == AST_Node_Type::For - || node->identifier == AST_Node_Type::While) - && child_count(*node) > 0) { - auto &child = child_at(*node, child_count(*node) - 1); - if (child.identifier == AST_Node_Type::Block - || child.identifier == AST_Node_Type::Scopeless_Block) - { - auto num_sub_children = child_count(child); - for (size_t i = 0; i < num_sub_children; ++i) { - auto &sub_child = child_at(child, i); - if (sub_child.identifier == AST_Node_Type::Fun_Call) { - child.children[i] = chaiscript::make_unique, eval::Unused_Return_Fun_Call_AST_Node>(sub_child.text, sub_child.location, std::move(sub_child.children)); - } + } + } else if ((node->identifier == AST_Node_Type::For || node->identifier == AST_Node_Type::While) && child_count(*node) > 0) { + auto &child = child_at(*node, child_count(*node) - 1); + if (child.identifier == AST_Node_Type::Block || child.identifier == AST_Node_Type::Scopeless_Block) { + auto num_sub_children = child_count(child); + for (size_t i = 0; i < num_sub_children; ++i) { + auto &sub_child = child_at(child, i); + if (sub_child.identifier == AST_Node_Type::Fun_Call) { + child.children[i] = chaiscript::make_unique, eval::Unused_Return_Fun_Call_AST_Node>( + sub_child.text, sub_child.location, std::move(sub_child.children)); } } } - return node; } + return node; + } }; struct Assign_Decl { template auto optimize(eval::AST_Node_Impl_Ptr node) { - if ((node->identifier == AST_Node_Type::Equation) - && node->text == "=" - && node->children.size() == 2 - && node->children[0]->identifier == AST_Node_Type::Var_Decl - ) - { + if ((node->identifier == AST_Node_Type::Equation) && node->text == "=" && node->children.size() == 2 + && node->children[0]->identifier == AST_Node_Type::Var_Decl) { std::vector> new_children; new_children.push_back(std::move(node->children[0]->children[0])); new_children.push_back(std::move(node->children[1])); - return chaiscript::make_unique, eval::Assign_Decl_AST_Node>(node->text, - node->location, std::move(new_children) ); + return chaiscript::make_unique, eval::Assign_Decl_AST_Node>(node->text, + node->location, + std::move(new_children)); } return node; } }; - struct If { template auto optimize(eval::AST_Node_Impl_Ptr node) { - if ((node->identifier == AST_Node_Type::If) - && node->children.size() >= 2 - && node->children[0]->identifier == AST_Node_Type::Constant) - { + if ((node->identifier == AST_Node_Type::If) && node->children.size() >= 2 && node->children[0]->identifier == AST_Node_Type::Constant) { const auto condition = dynamic_cast *>(node->children[0].get())->m_value; if (condition.get_type_info().bare_equal_type_info(typeid(bool))) { if (boxed_cast(condition)) { @@ -254,25 +229,21 @@ namespace chaiscript { struct Partial_Fold { template auto optimize(eval::AST_Node_Impl_Ptr node) { - // Fold right side - if (node->identifier == AST_Node_Type::Binary - && node->children.size() == 2 - && node->children[0]->identifier != AST_Node_Type::Constant - && node->children[1]->identifier == AST_Node_Type::Constant) - { + if (node->identifier == AST_Node_Type::Binary && node->children.size() == 2 + && node->children[0]->identifier != AST_Node_Type::Constant && node->children[1]->identifier == AST_Node_Type::Constant) { try { const auto &oper = node->text; const auto parsed = Operators::to_operator(oper); if (parsed != Operators::Opers::invalid) { const auto rhs = dynamic_cast *>(node->children[1].get())->m_value; if (rhs.get_type_info().is_arithmetic()) { - return chaiscript::make_unique, eval::Fold_Right_Binary_Operator_AST_Node>(node->text, node->location, - std::move(node->children), rhs); + return chaiscript::make_unique, eval::Fold_Right_Binary_Operator_AST_Node>( + node->text, node->location, std::move(node->children), rhs); } } } 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 { template auto optimize(eval::AST_Node_Impl_Ptr 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 { const auto &oper = node->text; const auto parsed = Operators::to_operator(oper, true); @@ -295,39 +262,43 @@ namespace chaiscript { const auto match = oper + node->children[0]->text; 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); - return chaiscript::make_unique, eval::Constant_AST_Node>(std::move(match), node->location, std::move(val)); + const auto val = Boxed_Number::do_oper(parsed, lhs); + return chaiscript::make_unique, eval::Constant_AST_Node>(std::move(match), + node->location, + std::move(val)); } else if (lhs.get_type_info().bare_equal_type_info(typeid(bool)) && oper == "!") { - return chaiscript::make_unique, eval::Constant_AST_Node>(std::move(match), node->location, Boxed_Value(!boxed_cast(lhs))); + return chaiscript::make_unique, eval::Constant_AST_Node>(std::move(match), + node->location, + Boxed_Value(!boxed_cast(lhs))); } } 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) - && node->children.size() == 2 - && node->children[0]->identifier == AST_Node_Type::Constant - && node->children[1]->identifier == AST_Node_Type::Constant) - { + && node->children.size() == 2 && node->children[0]->identifier == AST_Node_Type::Constant + && node->children[1]->identifier == AST_Node_Type::Constant) { try { const auto lhs = dynamic_cast &>(*node->children[0]).m_value; const auto rhs = dynamic_cast &>(*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))) { const auto match = node->children[0]->text + " " + node->text + " " + node->children[1]->text; const auto val = [lhs_val = boxed_cast(lhs), rhs_val = boxed_cast(rhs), id = node->identifier] { - if (id == AST_Node_Type::Logical_And) { return Boxed_Value(lhs_val && rhs_val); } - else { return Boxed_Value(lhs_val || rhs_val); } + if (id == AST_Node_Type::Logical_And) { + return Boxed_Value(lhs_val && rhs_val); + } else { + return Boxed_Value(lhs_val || rhs_val); + } }(); - return chaiscript::make_unique, eval::Constant_AST_Node>(std::move(match), node->location, std::move(val)); + return chaiscript::make_unique, eval::Constant_AST_Node>(std::move(match), + node->location, + std::move(val)); } } catch (const std::exception &) { - //failure to fold, that's OK + // failure to fold, that's OK } - } else if (node->identifier == AST_Node_Type::Binary - && node->children.size() == 2 - && node->children[0]->identifier == AST_Node_Type::Constant - && node->children[1]->identifier == AST_Node_Type::Constant) - { + } else if (node->identifier == AST_Node_Type::Binary && node->children.size() == 2 + && node->children[0]->identifier == AST_Node_Type::Constant && node->children[1]->identifier == AST_Node_Type::Constant) { try { const auto &oper = node->text; const auto parsed = Operators::to_operator(oper); @@ -335,28 +306,28 @@ namespace chaiscript { const auto lhs = dynamic_cast &>(*node->children[0]).m_value; const auto rhs = dynamic_cast &>(*node->children[1]).m_value; 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; - return chaiscript::make_unique, eval::Constant_AST_Node>(std::move(match), node->location, std::move(val)); + return chaiscript::make_unique, eval::Constant_AST_Node>(std::move(match), + node->location, + std::move(val)); } } } 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 - && node->children.size() == 2 - && node->children[0]->identifier == AST_Node_Type::Id - && 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) { - + } else if (node->identifier == AST_Node_Type::Fun_Call && node->children.size() == 2 + && node->children[0]->identifier == AST_Node_Type::Id && 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 &>(*node->children[1]->children[0]).m_value; if (arg.get_type_info().is_arithmetic()) { 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 + ")"; - return chaiscript::make_unique, eval::Constant_AST_Node>(std::move(match), node->location, const_var(val)); + return chaiscript::make_unique, eval::Constant_AST_Node>(std::move(match), + node->location, + const_var(val)); }; if (fun_name == "double") { @@ -370,10 +341,7 @@ namespace chaiscript { } else if (fun_name == "size_t") { return make_constant(Boxed_Number(arg).get_as()); } - - } - } return node; @@ -383,7 +351,6 @@ namespace chaiscript { struct For_Loop { template auto optimize(eval::AST_Node_Impl_Ptr for_node) { - if (for_node->identifier != AST_Node_Type::For) { return for_node; } @@ -392,66 +359,55 @@ namespace chaiscript { const auto &binary_node = child_at(*for_node, 1); const auto &prefix_node = child_at(*for_node, 2); - if (child_count(*for_node) == 4 - && eq_node.identifier == AST_Node_Type::Assign_Decl - && child_count(eq_node) == 2 - && child_at(eq_node, 0).identifier == AST_Node_Type::Id - && child_at(eq_node, 1).identifier == AST_Node_Type::Constant - && binary_node.identifier == AST_Node_Type::Binary - && binary_node.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) - { + if (child_count(*for_node) == 4 && eq_node.identifier == AST_Node_Type::Assign_Decl && child_count(eq_node) == 2 + && child_at(eq_node, 0).identifier == AST_Node_Type::Id && child_at(eq_node, 1).identifier == AST_Node_Type::Constant + && binary_node.identifier == AST_Node_Type::Binary && binary_node.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 &>(child_at(eq_node, 1)).m_value; const Boxed_Value &end = dynamic_cast &>(child_at(binary_node, 1)).m_value; const std::string &id = child_at(prefix_node, 0).text; - if (begin.get_type_info().bare_equal(user_type()) - && end.get_type_info().bare_equal(user_type())) { - + if (begin.get_type_info().bare_equal(user_type()) && end.get_type_info().bare_equal(user_type())) { const auto start_int = boxed_cast(begin); const auto end_int = boxed_cast(end); - // note that we are moving the last element out, then popping the empty shared_ptr + // note that we are moving the last element out, then popping the empty shared_ptr // from the vector std::vector> body_vector; auto body_child = std::move(for_node->children[3]); for_node->children.pop_back(); body_vector.emplace_back(std::move(body_child)); - - return make_compiled_node(std::move(for_node), std::move(body_vector), - [id, start_int, end_int](const std::vector> &children, const chaiscript::detail::Dispatch_State &t_ss) { - assert(children.size() == 1); - chaiscript::eval::detail::Scope_Push_Pop spp(t_ss); - int i = start_int; - t_ss.add_object(id, var(&i)); + return make_compiled_node(std::move(for_node), + std::move(body_vector), + [id, start_int, end_int](const std::vector> &children, + const chaiscript::detail::Dispatch_State &t_ss) { + assert(children.size() == 1); + chaiscript::eval::detail::Scope_Push_Pop spp(t_ss); - try { - for (; i < end_int; ++i) { - try { - // Body of Loop - children[0]->eval(t_ss); - } catch (eval::detail::Continue_Loop &) { - // we got a continue exception, which means all of the remaining - // loop implementation is skipped and we just need to continue to - // the next iteration step - } - } - } catch (eval::detail::Break_Loop &) { - // loop broken - } + int i = start_int; + t_ss.add_object(id, var(&i)); - return void_var(); - } - ); + try { + for (; i < end_int; ++i) { + try { + // Body of Loop + children[0]->eval(t_ss); + } catch (eval::detail::Continue_Loop &) { + // we got a continue exception, which means all of the remaining + // loop implementation is skipped and we just need to continue to + // the next iteration step + } + } + } catch (eval::detail::Break_Loop &) { + // loop broken + } + + return void_var(); + }); } else { return for_node; } @@ -461,12 +417,17 @@ namespace chaiscript { } }; - using Optimizer_Default = Optimizer; - - } -} + using Optimizer_Default = Optimizer; + } // namespace optimizer +} // namespace chaiscript #endif - diff --git a/include/chaiscript/language/chaiscript_parser.hpp b/include/chaiscript/language/chaiscript_parser.hpp index abcecefe..df64f9b9 100644 --- a/include/chaiscript/language/chaiscript_parser.hpp +++ b/include/chaiscript/language/chaiscript_parser.hpp @@ -7,32 +7,28 @@ // This is an open source non-commercial project. Dear PVS-Studio, please check it. // PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com - #ifndef CHAISCRIPT_PARSER_HPP_ #define CHAISCRIPT_PARSER_HPP_ +#include +#include #include #include #include #include #include #include -#include -#include - - - #include "../dispatchkit/boxed_value.hpp" +#include "../utility/hash.hpp" +#include "../utility/static_string.hpp" #include "chaiscript_common.hpp" #include "chaiscript_optimizer.hpp" #include "chaiscript_tracer.hpp" -#include "../utility/hash.hpp" -#include "../utility/static_string.hpp" #if defined(CHAISCRIPT_UTF16_UTF32) -#include #include +#include #endif #if defined(CHAISCRIPT_MSVC) && defined(max) && defined(min) @@ -43,57 +39,49 @@ #undef min #endif - -namespace chaiscript -{ +namespace chaiscript { /// \brief Classes and functions used during the parsing process. - namespace parser - { + namespace parser { /// \brief Classes and functions internal to the parsing process. Not supported for the end user. - namespace detail - { - enum Alphabet - { symbol_alphabet = 0 - , keyword_alphabet - , int_alphabet - , float_alphabet - , x_alphabet - , hex_alphabet - , b_alphabet - , bin_alphabet - , id_alphabet - , white_alphabet - , int_suffix_alphabet - , float_suffix_alphabet - , max_alphabet - , lengthof_alphabet = 256 + namespace detail { + enum Alphabet { + symbol_alphabet = 0, + keyword_alphabet, + int_alphabet, + float_alphabet, + x_alphabet, + hex_alphabet, + b_alphabet, + bin_alphabet, + id_alphabet, + white_alphabet, + int_suffix_alphabet, + float_suffix_alphabet, + max_alphabet, + lengthof_alphabet = 256 }; // Generic for u16, u32 and wchar template - struct Char_Parser_Helper - { + struct Char_Parser_Helper { // common for all implementations - static std::string u8str_from_ll(long long val) - { + static std::string u8str_from_ll(long long val) { using char_type = std::string::value_type; char_type c[2]; c[1] = char_type(val); c[0] = char_type(val >> 8); - if (c[0] == 0) - { + if (c[0] == 0) { return std::string(1, c[1]); // size, character } return std::string(c, 2); // char buffer, size } - static string_type str_from_ll(long long val) - { + static string_type str_from_ll(long long val) { using target_char_type = typename string_type::value_type; -#if defined (CHAISCRIPT_UTF16_UTF32) +#if defined(CHAISCRIPT_UTF16_UTF32) // prepare converter std::wstring_convert, target_char_type> converter; // convert @@ -107,55 +95,45 @@ namespace chaiscript // Specialization for char AKA UTF-8 template<> - struct Char_Parser_Helper - { - static std::string str_from_ll(long long val) - { + struct Char_Parser_Helper { + static std::string str_from_ll(long long val) { // little SFINAE trick to avoid base class return Char_Parser_Helper::u8str_from_ll(val); } }; - } + } // namespace detail - - template + template class ChaiScript_Parser final : public ChaiScript_Parser_Base { - void *get_tracer_ptr() noexcept override { - return &m_tracer; - } + void *get_tracer_ptr() noexcept override { return &m_tracer; } std::size_t m_current_parse_depth = 0; - struct Depth_Counter - { + struct Depth_Counter { static const auto max_depth = Parse_Depth; - Depth_Counter(ChaiScript_Parser *t_parser) : parser(t_parser) - { + Depth_Counter(ChaiScript_Parser *t_parser) + : parser(t_parser) { ++parser->m_current_parse_depth; if (parser->m_current_parse_depth > max_depth) { - throw exception::eval_error("Maximum parse depth exceeded", - File_Position(parser->m_position.line, parser->m_position.col), *(parser->m_filename)); + throw exception::eval_error("Maximum parse depth exceeded", + File_Position(parser->m_position.line, parser->m_position.col), + *(parser->m_filename)); } } - ~Depth_Counter() noexcept - { - --parser->m_current_parse_depth; - } + ~Depth_Counter() noexcept { --parser->m_current_parse_depth; } ChaiScript_Parser *parser; }; template - constexpr static void set_alphabet(Array2D &array, const First first, const Second second) noexcept - { + constexpr static void set_alphabet(Array2D &array, const First first, const Second second) noexcept { auto *first_ptr = &std::get<0>(array) + static_cast(first); auto *second_ptr = &std::get<0>(*first_ptr) + static_cast(second); *second_ptr = true; } - constexpr static std::array, detail::max_alphabet> build_alphabet() noexcept - { + constexpr static std::array, detail::max_alphabet> build_alphabet() noexcept { std::array, detail::max_alphabet> alphabet{}; set_alphabet(alphabet, detail::symbol_alphabet, '?'); @@ -173,28 +151,50 @@ namespace chaiscript set_alphabet(alphabet, detail::symbol_alphabet, '<'); set_alphabet(alphabet, detail::symbol_alphabet, '>'); - for ( size_t c = 'a' ; c <= 'z' ; ++c ) { set_alphabet(alphabet, detail::keyword_alphabet, c); } - for ( size_t c = 'A' ; c <= 'Z' ; ++c ) { set_alphabet(alphabet, detail::keyword_alphabet, c); } - for ( size_t c = '0' ; c <= '9' ; ++c ) { set_alphabet(alphabet, detail::keyword_alphabet, c); } + for (size_t c = 'a'; c <= 'z'; ++c) { + set_alphabet(alphabet, detail::keyword_alphabet, c); + } + for (size_t c = 'A'; c <= 'Z'; ++c) { + set_alphabet(alphabet, detail::keyword_alphabet, c); + } + for (size_t c = '0'; c <= '9'; ++c) { + set_alphabet(alphabet, detail::keyword_alphabet, c); + } set_alphabet(alphabet, detail::keyword_alphabet, '_'); - for ( size_t c = '0' ; c <= '9' ; ++c ) { set_alphabet(alphabet, detail::int_alphabet, c); } - for ( size_t c = '0' ; c <= '9' ; ++c ) { set_alphabet(alphabet, detail::float_alphabet, c); } + for (size_t c = '0'; c <= '9'; ++c) { + set_alphabet(alphabet, detail::int_alphabet, c); + } + for (size_t c = '0'; c <= '9'; ++c) { + set_alphabet(alphabet, detail::float_alphabet, c); + } set_alphabet(alphabet, detail::float_alphabet, '.'); - for ( size_t c = '0' ; c <= '9' ; ++c ) { set_alphabet(alphabet, detail::hex_alphabet, c); } - for ( size_t c = 'a' ; c <= 'f' ; ++c ) { set_alphabet(alphabet, detail::hex_alphabet, c); } - for ( size_t c = 'A' ; c <= 'F' ; ++c ) { set_alphabet(alphabet, detail::hex_alphabet, c); } + for (size_t c = '0'; c <= '9'; ++c) { + set_alphabet(alphabet, detail::hex_alphabet, c); + } + for (size_t c = 'a'; c <= 'f'; ++c) { + set_alphabet(alphabet, detail::hex_alphabet, c); + } + for (size_t c = 'A'; c <= 'F'; ++c) { + set_alphabet(alphabet, detail::hex_alphabet, c); + } set_alphabet(alphabet, detail::x_alphabet, 'x'); set_alphabet(alphabet, detail::x_alphabet, 'X'); - for ( size_t c = '0' ; c <= '1' ; ++c ) { set_alphabet(alphabet, detail::bin_alphabet, c); } + for (size_t c = '0'; c <= '1'; ++c) { + set_alphabet(alphabet, detail::bin_alphabet, c); + } set_alphabet(alphabet, detail::b_alphabet, 'b'); set_alphabet(alphabet, detail::b_alphabet, 'B'); - for ( size_t c = 'a' ; c <= 'z' ; ++c ) { set_alphabet(alphabet, detail::id_alphabet, c); } - for ( size_t c = 'A' ; c <= 'Z' ; ++c ) { set_alphabet(alphabet, detail::id_alphabet, c); } + for (size_t c = 'a'; c <= 'z'; ++c) { + set_alphabet(alphabet, detail::id_alphabet, c); + } + for (size_t c = 'A'; c <= 'Z'; ++c) { + set_alphabet(alphabet, detail::id_alphabet, c); + } set_alphabet(alphabet, detail::id_alphabet, '_'); set_alphabet(alphabet, detail::white_alphabet, ' '); @@ -213,93 +213,111 @@ namespace chaiscript return alphabet; } - - struct Operator_Matches - { + struct Operator_Matches { using SS = utility::Static_String; - std::array m_0 {{SS("?")}}; - std::array m_1 {{SS("||")}}; - std::array m_2 {{SS("&&")}}; - std::array m_3 {{SS("|")}}; - std::array m_4 {{SS("^")}}; - std::array m_5 {{SS("&")}}; - std::array m_6 {{SS("=="), SS("!=")}}; - std::array m_7 {{SS("<"), SS("<="), SS(">"), SS(">=")}}; - std::array m_8 {{SS("<<"), SS(">>")}}; - //We share precedence here but then separate them later - std::array m_9 {{SS("+"), SS("-")}}; - std::array m_10 {{SS("*"), SS("/"), SS("%")}}; - std::array m_11 {{SS("++"), SS("--"), SS("-"), SS("+"), SS("!"), SS("~")}}; + std::array m_0{{SS("?")}}; + std::array m_1{{SS("||")}}; + std::array m_2{{SS("&&")}}; + std::array m_3{{SS("|")}}; + std::array m_4{{SS("^")}}; + std::array m_5{{SS("&")}}; + std::array m_6{{SS("=="), SS("!=")}}; + std::array m_7{{SS("<"), SS("<="), SS(">"), SS(">=")}}; + std::array m_8{{SS("<<"), SS(">>")}}; + // We share precedence here but then separate them later + std::array m_9{{SS("+"), SS("-")}}; + std::array m_10{{SS("*"), SS("/"), SS("%")}}; + std::array m_11{{SS("++"), SS("--"), SS("-"), SS("+"), SS("!"), SS("~")}}; bool is_match(std::string_view t_str) const noexcept { - constexpr std::array groups{{0,1,2,3,4,5,6,7,8,9,10,11}}; - return std::any_of(groups.begin(), groups.end(), [&t_str, this](const std::size_t group){ return is_match(group, t_str); }); + constexpr std::array groups{{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}}; + return std::any_of(groups.begin(), groups.end(), [&t_str, this](const std::size_t group) { return is_match(group, t_str); }); } template - bool any_of(const std::size_t t_group, Predicate &&predicate) const - { - auto match = [&predicate](const auto &array) { - return std::any_of(array.begin(), array.end(), predicate); - }; + bool any_of(const std::size_t t_group, Predicate &&predicate) const { + auto match = [&predicate](const auto &array) { return std::any_of(array.begin(), array.end(), predicate); }; switch (t_group) { - case 0: return match(m_0); - case 1: return match(m_1); - case 2: return match(m_2); - case 3: return match(m_3); - case 4: return match(m_4); - case 5: return match(m_5); - case 6: return match(m_6); - case 7: return match(m_7); - case 8: return match(m_8); - case 9: return match(m_9); - case 10: return match(m_10); - case 11: return match(m_11); - default: return false; + case 0: + return match(m_0); + case 1: + return match(m_1); + case 2: + return match(m_2); + case 3: + return match(m_3); + case 4: + return match(m_4); + case 5: + return match(m_5); + case 6: + return match(m_6); + case 7: + return match(m_7); + case 8: + return match(m_8); + case 9: + return match(m_9); + case 10: + return match(m_10); + case 11: + return match(m_11); + default: + return false; } } constexpr bool is_match(const std::size_t t_group, std::string_view t_str) const noexcept { auto match = [&t_str](const auto &array) { - return std::any_of(array.begin(), array.end(), [&t_str](const auto &v){ return v == t_str; }); + return std::any_of(array.begin(), array.end(), [&t_str](const auto &v) { return v == t_str; }); }; switch (t_group) { - case 0: return match(m_0); - case 1: return match(m_1); - case 2: return match(m_2); - case 3: return match(m_3); - case 4: return match(m_4); - case 5: return match(m_5); - case 6: return match(m_6); - case 7: return match(m_7); - case 8: return match(m_8); - case 9: return match(m_9); - case 10: return match(m_10); - case 11: return match(m_11); - default: return false; + case 0: + return match(m_0); + case 1: + return match(m_1); + case 2: + return match(m_2); + case 3: + return match(m_3); + case 4: + return match(m_4); + case 5: + return match(m_5); + case 6: + return match(m_6); + case 7: + return match(m_7); + case 8: + return match(m_8); + case 9: + return match(m_9); + case 10: + return match(m_10); + case 11: + return match(m_11); + default: + return false; } } - }; constexpr static std::array create_operators() noexcept { - std::array operators = { { - Operator_Precedence::Ternary_Cond, - Operator_Precedence::Logical_Or, - Operator_Precedence::Logical_And, - Operator_Precedence::Bitwise_Or, - Operator_Precedence::Bitwise_Xor, - Operator_Precedence::Bitwise_And, - Operator_Precedence::Equality, - Operator_Precedence::Comparison, - Operator_Precedence::Shift, - Operator_Precedence::Addition, - Operator_Precedence::Multiplication, - Operator_Precedence::Prefix - } }; + std::array operators = {{Operator_Precedence::Ternary_Cond, + Operator_Precedence::Logical_Or, + Operator_Precedence::Logical_And, + Operator_Precedence::Bitwise_Or, + Operator_Precedence::Bitwise_Xor, + Operator_Precedence::Bitwise_And, + Operator_Precedence::Equality, + Operator_Precedence::Comparison, + Operator_Precedence::Shift, + Operator_Precedence::Addition, + Operator_Precedence::Multiplication, + Operator_Precedence::Prefix}}; return operators; } @@ -313,14 +331,15 @@ namespace chaiscript std::shared_ptr m_filename; std::vector> m_match_stack; - - struct Position - { + struct Position { constexpr Position() = default; - constexpr Position(const char * t_pos, const char * t_end) noexcept - : line(1), col(1), m_pos(t_pos), m_end(t_end), m_last_col(1) - { + constexpr Position(const char *t_pos, const char *t_end) noexcept + : line(1) + , col(1) + , m_pos(t_pos) + , m_end(t_end) + , m_last_col(1) { } static std::string_view str(const Position &t_begin, const Position &t_end) noexcept { @@ -383,23 +402,15 @@ namespace chaiscript return ret; } - constexpr bool operator==(const Position &t_rhs) const noexcept { - return m_pos == t_rhs.m_pos; - } + constexpr bool operator==(const Position &t_rhs) const noexcept { return m_pos == t_rhs.m_pos; } - constexpr bool operator!=(const Position &t_rhs) const noexcept { - return m_pos != t_rhs.m_pos; - } + constexpr bool operator!=(const Position &t_rhs) const noexcept { return m_pos != t_rhs.m_pos; } - constexpr bool has_more() const noexcept { - return m_pos != m_end; - } + constexpr bool has_more() const noexcept { return m_pos != m_end; } - constexpr size_t remaining() const noexcept { - return static_cast(m_end - m_pos); - } + constexpr size_t remaining() const noexcept { return static_cast(m_end - m_pos); } - constexpr const char& operator*() const noexcept { + constexpr const char &operator*() const noexcept { if (m_pos == m_end) { return ""[0]; } else { @@ -410,10 +421,10 @@ namespace chaiscript int line = -1; int col = -1; - private: - const char *m_pos = nullptr; - const char *m_end = nullptr; - int m_last_col = -1; + private: + const char *m_pos = nullptr; + const char *m_end = nullptr; + int m_last_col = -1; }; Position m_position; @@ -421,30 +432,22 @@ namespace chaiscript Tracer m_tracer; Optimizer m_optimizer; - void validate_object_name(std::string_view name) const - { + void validate_object_name(std::string_view name) const { if (!Name_Validator::valid_object_name(name)) { throw exception::eval_error("Invalid Object Name: " + std::string(name), File_Position(m_position.line, m_position.col), *m_filename); } } public: - explicit ChaiScript_Parser(Tracer tracer = Tracer(), Optimizer optimizer=Optimizer()) - : m_tracer(std::move(tracer)), - m_optimizer(std::move(optimizer)) - { + explicit ChaiScript_Parser(Tracer tracer = Tracer(), Optimizer optimizer = Optimizer()) + : m_tracer(std::move(tracer)) + , m_optimizer(std::move(optimizer)) { m_match_stack.reserve(2); } - Tracer &get_tracer() noexcept - { - return m_tracer; - } + Tracer &get_tracer() noexcept { return m_tracer; } - Optimizer &get_optimizer() noexcept - { - return m_optimizer; - } + Optimizer &get_optimizer() noexcept { return m_optimizer; } ChaiScript_Parser(const ChaiScript_Parser &) = delete; ChaiScript_Parser &operator=(const ChaiScript_Parser &) = delete; @@ -455,74 +458,60 @@ namespace chaiscript constexpr static Operator_Matches m_operator_matches{}; /// test a char in an m_alphabet - constexpr bool char_in_alphabet(char c, detail::Alphabet a) const noexcept { - return m_alphabet[a][static_cast(c)]; - } + constexpr bool char_in_alphabet(char c, detail::Alphabet a) const noexcept { return m_alphabet[a][static_cast(c)]; } /// Prints the parsed ast_nodes as a tree void debug_print(const AST_Node &t, std::string prepend = "") const override { - std::cout << prepend << "(" << ast_node_type_to_string(t.identifier) << ") " << t.text << " : " << t.start().line << ", " << t.start().column << '\n'; + std::cout << prepend << "(" << ast_node_type_to_string(t.identifier) << ") " << t.text << " : " << t.start().line << ", " + << t.start().column << '\n'; for (const auto &node : t.get_children()) { debug_print(node.get(), prepend + " "); } } - /// Helper function that collects ast_nodes from a starting position to the top of the stack into a new AST node template void build_match(size_t t_match_start, std::string t_text = "") { bool is_deep = false; - Parse_Location filepos = [&]()->Parse_Location{ - //so we want to take everything to the right of this and make them children + Parse_Location filepos = [&]() -> Parse_Location { + // so we want to take everything to the right of this and make them children if (t_match_start != m_match_stack.size()) { is_deep = true; - return Parse_Location( - m_filename, - m_match_stack[t_match_start]->location.start.line, - m_match_stack[t_match_start]->location.start.column, - m_position.line, - m_position.col - ); + return Parse_Location(m_filename, + m_match_stack[t_match_start]->location.start.line, + m_match_stack[t_match_start]->location.start.column, + m_position.line, + m_position.col); } else { - return Parse_Location( - m_filename, - m_position.line, - m_position.col, - m_position.line, - m_position.col - ); + return Parse_Location(m_filename, m_position.line, m_position.col, m_position.line, m_position.col); } }(); std::vector> new_children; if (is_deep) { - new_children.assign(std::make_move_iterator(m_match_stack.begin() + static_cast(t_match_start)), + new_children.assign(std::make_move_iterator(m_match_stack.begin() + static_cast(t_match_start)), std::make_move_iterator(m_match_stack.end())); m_match_stack.erase(m_match_stack.begin() + static_cast(t_match_start), m_match_stack.end()); } /// \todo fix the fact that a successful match that captured no ast_nodes doesn't have any real start position m_match_stack.push_back( - m_optimizer.optimize( - chaiscript::make_unique, NodeType>( - std::move(t_text), - std::move(filepos), - std::move(new_children))) - ); + m_optimizer.optimize(chaiscript::make_unique, NodeType>(std::move(t_text), + std::move(filepos), + std::move(new_children)))); } - /// Reads a symbol group from input if it matches the parameter, without skipping initial whitespace - inline auto Symbol_(const utility::Static_String &sym) noexcept - { + inline auto Symbol_(const utility::Static_String &sym) noexcept { const auto len = sym.size(); if (m_position.remaining() >= len) { const char *file_pos = &(*m_position); - for (size_t pos = 0; pos < len; ++pos) - { - if (sym.c_str()[pos] != file_pos[pos]) { return false; } + for (size_t pos = 0; pos < len; ++pos) { + if (sym.c_str()[pos] != file_pos[pos]) { + return false; + } } m_position += len; return true; @@ -571,23 +560,21 @@ namespace chaiscript return false; } - /// Skips ChaiScript whitespace, which means space and tab, but not cr/lf /// jespada: Modified SkipWS to skip optionally CR ('\n') and/or LF+CR ("\r\n") /// AlekMosingiewicz: Added exception when illegal character detected - bool SkipWS(bool skip_cr=false) { + bool SkipWS(bool skip_cr = false) { bool retval = false; while (m_position.has_more()) { - if(static_cast(*m_position) > 0x7e) { + if (static_cast(*m_position) > 0x7e) { throw exception::eval_error("Illegal character", File_Position(m_position.line, m_position.col), *m_filename); } - auto end_line = (*m_position != 0) && ((*m_position == '\n') || (*m_position == '\r' && *(m_position+1) == '\n')); + auto end_line = (*m_position != 0) && ((*m_position == '\n') || (*m_position == '\r' && *(m_position + 1) == '\n')); - if ( char_in_alphabet(*m_position,detail::white_alphabet) || (skip_cr && end_line)) { - - if(end_line) { - if(*m_position == '\r') { + if (char_in_alphabet(*m_position, detail::white_alphabet) || (skip_cr && end_line)) { + if (end_line) { + if (*m_position == '\r') { // discards lf ++m_position; } @@ -596,8 +583,7 @@ namespace chaiscript ++m_position; retval = true; - } - else if (SkipComment()) { + } else if (SkipComment()) { retval = true; } else { break; @@ -615,7 +601,7 @@ namespace chaiscript ++m_position; } auto exponent_pos = m_position; - while (m_position.has_more() && char_in_alphabet(*m_position,detail::int_alphabet) ) { + while (m_position.has_more() && char_in_alphabet(*m_position, detail::int_alphabet)) { ++m_position; } if (m_position == exponent_pos) { @@ -625,30 +611,27 @@ namespace chaiscript } // Parse optional float suffix - while (m_position.has_more() && char_in_alphabet(*m_position, detail::float_suffix_alphabet)) - { + while (m_position.has_more() && char_in_alphabet(*m_position, detail::float_suffix_alphabet)) { ++m_position; } return true; } - /// Reads a floating point value from input, without skipping initial whitespace bool Float_() noexcept { - if (m_position.has_more() && char_in_alphabet(*m_position,detail::float_alphabet) ) { - while (m_position.has_more() && char_in_alphabet(*m_position,detail::int_alphabet) ) { + if (m_position.has_more() && char_in_alphabet(*m_position, detail::float_alphabet)) { + while (m_position.has_more() && char_in_alphabet(*m_position, detail::int_alphabet)) { ++m_position; } if (m_position.has_more() && (std::tolower(*m_position) == 'e')) { // The exponent is valid even without any decimal in the Float (1e8, 3e-15) return read_exponent_and_suffix(); - } - else if (m_position.has_more() && (*m_position == '.')) { + } else if (m_position.has_more() && (*m_position == '.')) { ++m_position; - if (m_position.has_more() && char_in_alphabet(*m_position,detail::int_alphabet)) { - while (m_position.has_more() && char_in_alphabet(*m_position,detail::int_alphabet) ) { + if (m_position.has_more() && char_in_alphabet(*m_position, detail::int_alphabet)) { + while (m_position.has_more() && char_in_alphabet(*m_position, detail::int_alphabet)) { ++m_position; } @@ -667,24 +650,21 @@ namespace chaiscript if (m_position.has_more() && (*m_position == '0')) { ++m_position; - if (m_position.has_more() && char_in_alphabet(*m_position, detail::x_alphabet) ) { + if (m_position.has_more() && char_in_alphabet(*m_position, detail::x_alphabet)) { ++m_position; if (m_position.has_more() && char_in_alphabet(*m_position, detail::hex_alphabet)) { - while (m_position.has_more() && char_in_alphabet(*m_position, detail::hex_alphabet) ) { + while (m_position.has_more() && char_in_alphabet(*m_position, detail::hex_alphabet)) { ++m_position; } - while (m_position.has_more() && char_in_alphabet(*m_position, detail::int_suffix_alphabet)) - { + while (m_position.has_more() && char_in_alphabet(*m_position, detail::int_suffix_alphabet)) { ++m_position; } return true; - } - else { + } else { --m_position; } - } - else { + } else { --m_position; } } @@ -694,8 +674,7 @@ namespace chaiscript /// Reads an integer suffix void IntSuffix_() { - while (m_position.has_more() && char_in_alphabet(*m_position, detail::int_suffix_alphabet)) - { + while (m_position.has_more() && char_in_alphabet(*m_position, detail::int_suffix_alphabet)) { ++m_position; } } @@ -705,10 +684,10 @@ namespace chaiscript if (m_position.has_more() && (*m_position == '0')) { ++m_position; - if (m_position.has_more() && char_in_alphabet(*m_position, detail::b_alphabet) ) { + if (m_position.has_more() && char_in_alphabet(*m_position, detail::b_alphabet)) { ++m_position; - if (m_position.has_more() && char_in_alphabet(*m_position, detail::bin_alphabet) ) { - while (m_position.has_more() && char_in_alphabet(*m_position, detail::bin_alphabet) ) { + if (m_position.has_more() && char_in_alphabet(*m_position, detail::bin_alphabet)) { + while (m_position.has_more() && char_in_alphabet(*m_position, detail::bin_alphabet)) { ++m_position; } return true; @@ -724,19 +703,16 @@ namespace chaiscript } /// Parses a floating point value and returns a Boxed_Value representation of it - static Boxed_Value buildFloat(std::string_view t_val) - { + static Boxed_Value buildFloat(std::string_view t_val) { bool float_ = false; bool long_ = false; auto i = t_val.size(); - for (; i > 0; --i) - { - char val = t_val[i-1]; + for (; i > 0; --i) { + char val = t_val[i - 1]; - if (val == 'f' || val == 'F') - { + if (val == 'f' || val == 'F') { float_ = true; } else if (val == 'l' || val == 'L') { long_ = true; @@ -745,36 +721,29 @@ namespace chaiscript } } - if (float_) - { - return const_var(parse_num(t_val.substr(0,i))); + if (float_) { + return const_var(parse_num(t_val.substr(0, i))); } else if (long_) { - return const_var(parse_num(t_val.substr(0,i))); + return const_var(parse_num(t_val.substr(0, i))); } else { - return const_var(parse_num(t_val.substr(0,i))); + return const_var(parse_num(t_val.substr(0, i))); } } - - - static Boxed_Value buildInt(const int base, std::string_view t_val, const bool prefixed) - { + static Boxed_Value buildInt(const int base, std::string_view t_val, const bool prefixed) { bool unsigned_ = false; bool long_ = false; bool longlong_ = false; auto i = t_val.size(); - for (; i > 0; --i) - { - const char val = t_val[i-1]; + for (; i > 0; --i) { + const char val = t_val[i - 1]; - if (val == 'u' || val == 'U') - { + if (val == 'u' || val == 'U') { unsigned_ = true; } else if (val == 'l' || val == 'L') { - if (long_) - { + if (long_) { longlong_ = true; } @@ -784,7 +753,9 @@ namespace chaiscript } } - if (prefixed) { t_val.remove_prefix(2); } + if (prefixed) { + t_val.remove_prefix(2); + } #ifdef __GNUC__ #pragma GCC diagnostic push @@ -801,17 +772,16 @@ namespace chaiscript try { /// TODO fix this to use from_chars - auto u = std::stoll(std::string(t_val),nullptr,base); - + auto u = std::stoll(std::string(t_val), nullptr, base); if (!unsigned_ && !long_ && u >= std::numeric_limits::min() && u <= std::numeric_limits::max()) { return const_var(static_cast(u)); - } else if ((unsigned_ || base != 10) && !long_ && u >= std::numeric_limits::min() && u <= std::numeric_limits::max()) { + } else if ((unsigned_ || base != 10) && !long_ && u >= std::numeric_limits::min() + && u <= std::numeric_limits::max()) { return const_var(static_cast(u)); } else if (!unsigned_ && !longlong_ && u >= std::numeric_limits::min() && u <= std::numeric_limits::max()) { return const_var(static_cast(u)); - } else if ((unsigned_ || base != 10) && !longlong_ - && u >= std::numeric_limits::min() + } else if ((unsigned_ || base != 10) && !longlong_ && u >= std::numeric_limits::min() && u <= std::numeric_limits::max()) { return const_var(static_cast(u)); } else if (!unsigned_ && u >= std::numeric_limits::min() && u <= std::numeric_limits::max()) { @@ -824,7 +794,7 @@ namespace chaiscript // too big to be signed try { /// TODO fix this to use from_chars - auto u = std::stoull(std::string(t_val),nullptr,base); + auto u = std::stoull(std::string(t_val), nullptr, base); if (!longlong_ && u >= std::numeric_limits::min() && u <= std::numeric_limits::max()) { return const_var(static_cast(u)); @@ -840,13 +810,15 @@ namespace chaiscript #ifdef __GNUC__ #pragma GCC diagnostic pop #endif - } - template - std::unique_ptr> make_node(std::string_view t_match, const int t_prev_line, const int t_prev_col, Param && ...param) - { - return chaiscript::make_unique, T>(std::string(t_match), Parse_Location(m_filename, t_prev_line, t_prev_col, m_position.line, m_position.col), std::forward(param)...); + template + std::unique_ptr> + make_node(std::string_view t_match, const int t_prev_line, const int t_prev_col, Param &&...param) { + return chaiscript::make_unique, T>( + std::string(t_match), + Parse_Location(m_filename, t_prev_line, t_prev_col, m_position.line, m_position.col), + std::forward(param)...); } /// Reads a number from the input, detecting if it's an integer or floating point @@ -854,7 +826,7 @@ namespace chaiscript SkipWS(); const auto start = m_position; - if (m_position.has_more() && char_in_alphabet(*m_position, detail::float_alphabet) ) { + if (m_position.has_more() && char_in_alphabet(*m_position, detail::float_alphabet)) { try { if (Hex_()) { auto match = Position::str(start, m_position); @@ -874,15 +846,13 @@ namespace chaiscript auto bv = buildFloat(match); m_match_stack.push_back(make_node>(match, start.line, start.col, std::move(bv))); return true; - } - else { + } else { IntSuffix_(); auto match = Position::str(start, m_position); if (!match.empty() && (match[0] == '0')) { auto bv = buildInt(8, match, false); m_match_stack.push_back(make_node>(match, start.line, start.col, std::move(bv))); - } - else if (!match.empty()) { + } else if (!match.empty()) { auto bv = buildInt(10, match, false); m_match_stack.push_back(make_node>(match, start.line, start.col, std::move(bv))); } else { @@ -894,8 +864,7 @@ namespace chaiscript // error parsing number passed in to buildFloat/buildInt return false; } - } - else { + } else { return false; } } @@ -903,7 +872,7 @@ namespace chaiscript /// Reads an identifier from input which conforms to C's identifier naming conventions, without skipping initial whitespace bool Id_() { if (m_position.has_more() && char_in_alphabet(*m_position, detail::id_alphabet)) { - while (m_position.has_more() && char_in_alphabet(*m_position, detail::keyword_alphabet) ) { + while (m_position.has_more() && char_in_alphabet(*m_position, detail::keyword_alphabet)) { ++m_position; } @@ -914,17 +883,17 @@ namespace chaiscript while (m_position.has_more() && (*m_position != '`')) { if (Eol()) { - throw exception::eval_error("Carriage return in identifier literal", File_Position(m_position.line, m_position.col), *m_filename); - } - else { + throw exception::eval_error("Carriage return in identifier literal", + File_Position(m_position.line, m_position.col), + *m_filename); + } else { ++m_position; } } if (start == m_position) { throw exception::eval_error("Missing contents of identifier literal", File_Position(m_position.line, m_position.col), *m_filename); - } - else if (!m_position.has_more()) { + } else if (!m_position.has_more()) { throw exception::eval_error("Incomplete identifier literal", File_Position(m_position.line, m_position.col), *m_filename); } @@ -941,7 +910,6 @@ namespace chaiscript const auto start = m_position; if (Id_()) { - auto text = Position::str(start, m_position); const auto text_hash = utility::hash(text); @@ -962,57 +930,58 @@ namespace chaiscript m_match_stack.push_back(make_node>(text, start.line, start.col, const_var(false))); } break; case utility::hash("Infinity"): { - m_match_stack.push_back(make_node>(text, start.line, start.col, - const_var(std::numeric_limits::infinity()))); + m_match_stack.push_back(make_node>(text, + start.line, + start.col, + const_var(std::numeric_limits::infinity()))); } break; case utility::hash("NaN"): { - m_match_stack.push_back(make_node>(text, start.line, start.col, - const_var(std::numeric_limits::quiet_NaN()))); + m_match_stack.push_back(make_node>(text, + start.line, + start.col, + const_var(std::numeric_limits::quiet_NaN()))); } break; case utility::hash("__LINE__"): { - m_match_stack.push_back(make_node>(text, start.line, start.col, - const_var(start.line))); + m_match_stack.push_back(make_node>(text, start.line, start.col, const_var(start.line))); } break; case utility::hash("__FILE__"): { - m_match_stack.push_back(make_node>(text, start.line, start.col, - const_var(m_filename))); + m_match_stack.push_back(make_node>(text, start.line, start.col, const_var(m_filename))); } break; case utility::hash("__FUNC__"): { std::string fun_name = "NOT_IN_FUNCTION"; - for (size_t idx = m_match_stack.empty() ? 0 : m_match_stack.size() - 1; idx > 0; --idx) - { - if (m_match_stack[idx-1]->identifier == AST_Node_Type::Id - && m_match_stack[idx-0]->identifier == AST_Node_Type::Arg_List) { - fun_name = m_match_stack[idx-1]->text; + for (size_t idx = m_match_stack.empty() ? 0 : m_match_stack.size() - 1; idx > 0; --idx) { + if (m_match_stack[idx - 1]->identifier == AST_Node_Type::Id + && m_match_stack[idx - 0]->identifier == AST_Node_Type::Arg_List) { + fun_name = m_match_stack[idx - 1]->text; } } - m_match_stack.push_back(make_node>(text, start.line, start.col, - const_var(fun_name))); + m_match_stack.push_back(make_node>(text, start.line, start.col, const_var(fun_name))); } break; case utility::hash("__CLASS__"): { std::string fun_name = "NOT_IN_CLASS"; - for (size_t idx = m_match_stack.empty() ? 0 : m_match_stack.size() - 1; idx > 1; --idx) - { - if (m_match_stack[idx-2]->identifier == AST_Node_Type::Id - && m_match_stack[idx-1]->identifier == AST_Node_Type::Id - && m_match_stack[idx-0]->identifier == AST_Node_Type::Arg_List) { - fun_name = m_match_stack[idx-2]->text; + for (size_t idx = m_match_stack.empty() ? 0 : m_match_stack.size() - 1; idx > 1; --idx) { + if (m_match_stack[idx - 2]->identifier == AST_Node_Type::Id && m_match_stack[idx - 1]->identifier == AST_Node_Type::Id + && m_match_stack[idx - 0]->identifier == AST_Node_Type::Arg_List) { + fun_name = m_match_stack[idx - 2]->text; } } - m_match_stack.push_back(make_node>(std::move(text), start.line, start.col, - const_var(fun_name))); + m_match_stack.push_back( + make_node>(std::move(text), start.line, start.col, const_var(fun_name))); } break; case utility::hash("_"): { - m_match_stack.push_back(make_node>(std::move(text), start.line, start.col, - Boxed_Value(std::make_shared()))); + m_match_stack.push_back( + make_node>(std::move(text), + start.line, + start.col, + Boxed_Value(std::make_shared()))); } break; default: { auto val = text; if (*start == '`') { // 'escaped' literal, like an operator name - val = Position::str(start+1, m_position-1); + val = Position::str(start + 1, m_position - 1); // val.remove_prefix(1); val.remove_suffix(1); } m_match_stack.push_back(make_node>(val, start.line, start.col)); @@ -1023,7 +992,6 @@ namespace chaiscript #pragma warning(pop) #endif - return true; } else { return false; @@ -1050,8 +1018,6 @@ namespace chaiscript return true; } - - /// Reads a quoted string from input, without skipping initial whitespace bool Quoted_String_() { if (m_position.has_more() && (*m_position == '\"')) { @@ -1062,7 +1028,6 @@ namespace chaiscript bool in_quote = false; while (m_position.has_more() && ((*m_position != '\"') || (in_interpolation > 0) || (prev_char == '\\'))) { - if (!Eol_()) { if (prev_char == '$' && *m_position == '{') { ++in_interpolation; @@ -1093,8 +1058,7 @@ namespace chaiscript } template - struct Char_Parser - { + struct Char_Parser { string_type &match; using char_type = typename string_type::value_type; bool is_escaped = false; @@ -1109,14 +1073,13 @@ namespace chaiscript string_type hex_matches; Char_Parser(string_type &t_match, const bool t_interpolation_allowed) - : match(t_match), - interpolation_allowed(t_interpolation_allowed) - { + : match(t_match) + , interpolation_allowed(t_interpolation_allowed) { } Char_Parser &operator=(const Char_Parser &) = delete; - ~Char_Parser(){ + ~Char_Parser() { try { if (is_octal) { process_octal(); @@ -1135,8 +1098,7 @@ namespace chaiscript } } - void process_hex() - { + void process_hex() { if (!hex_matches.empty()) { auto val = stoll(hex_matches, nullptr, 16); match.push_back(char_type(val)); @@ -1146,9 +1108,7 @@ namespace chaiscript is_hex = false; } - - void process_octal() - { + void process_octal() { if (!octal_matches.empty()) { auto val = stoll(octal_matches, nullptr, 8); match.push_back(char_type(val)); @@ -1158,9 +1118,7 @@ namespace chaiscript is_octal = false; } - - void process_unicode() - { + void process_unicode() { const auto ch = static_cast(std::stoi(hex_matches, nullptr, 16)); const auto match_size = hex_matches.size(); hex_matches.clear(); @@ -1176,7 +1134,6 @@ namespace chaiscript throw exception::eval_error("Invalid 16 bit universal character"); } - if (ch < 0x80) { match += static_cast(ch); } else if (ch < 0x800) { @@ -1184,15 +1141,15 @@ namespace chaiscript buf[1] = static_cast(0x80 | (ch & 0x3F)); match.append(buf, 2); } else if (ch < 0x10000) { - buf[0] = static_cast(0xE0 | (ch >> 12)); - buf[1] = static_cast(0x80 | ((ch >> 6) & 0x3F)); - buf[2] = static_cast(0x80 | (ch & 0x3F)); + buf[0] = static_cast(0xE0 | (ch >> 12)); + buf[1] = static_cast(0x80 | ((ch >> 6) & 0x3F)); + buf[2] = static_cast(0x80 | (ch & 0x3F)); match.append(buf, 3); } else if (ch < 0x200000) { - buf[0] = static_cast(0xF0 | (ch >> 18)); + buf[0] = static_cast(0xF0 | (ch >> 18)); buf[1] = static_cast(0x80 | ((ch >> 12) & 0x3F)); - buf[2] = static_cast(0x80 | ((ch >> 6) & 0x3F)); - buf[3] = static_cast(0x80 | (ch & 0x3F)); + buf[2] = static_cast(0x80 | ((ch >> 6) & 0x3F)); + buf[3] = static_cast(0x80 | (ch & 0x3F)); match.append(buf, 4); } else { // this must be an invalid escape sequence? @@ -1203,9 +1160,7 @@ namespace chaiscript void parse(const char_type t_char, const int line, const int col, const std::string &filename) { const bool is_octal_char = t_char >= '0' && t_char <= '7'; - const bool is_hex_char = (t_char >= '0' && t_char <= '9') - || (t_char >= 'a' && t_char <= 'f') - || (t_char >= 'A' && t_char <= 'F'); + const bool is_hex_char = (t_char >= '0' && t_char <= '9') || (t_char >= 'a' && t_char <= 'f') || (t_char >= 'A' && t_char <= 'F'); if (is_octal) { if (is_octal_char) { @@ -1222,7 +1177,7 @@ namespace chaiscript if (is_hex_char) { hex_matches.push_back(t_char); - if (hex_matches.size() == 2*sizeof(char_type)) { + if (hex_matches.size() == 2 * sizeof(char_type)) { // This rule differs from the C/C++ standard, but ChaiScript // does not offer the same workaround options, and having // hexadecimal sequences longer than can fit into the char @@ -1237,7 +1192,7 @@ namespace chaiscript if (is_hex_char) { hex_matches.push_back(t_char); - if(hex_matches.size() == unicode_size) { + if (hex_matches.size() == unicode_size) { // Format is specified to be 'slash'uABCD // on collecting from A to D do parsing process_unicode(); @@ -1270,18 +1225,41 @@ namespace chaiscript unicode_size = 8; } else { switch (t_char) { - case ('\'') : match.push_back('\''); break; - case ('\"') : match.push_back('\"'); break; - case ('?') : match.push_back('?'); break; - case ('a') : match.push_back('\a'); break; - case ('b') : match.push_back('\b'); break; - case ('f') : match.push_back('\f'); break; - case ('n') : match.push_back('\n'); break; - case ('r') : match.push_back('\r'); break; - case ('t') : match.push_back('\t'); break; - case ('v') : match.push_back('\v'); break; - case ('$') : match.push_back('$'); break; - default: throw exception::eval_error("Unknown escaped sequence in string", File_Position(line, col), filename); + case ('\''): + match.push_back('\''); + break; + case ('\"'): + match.push_back('\"'); + break; + case ('?'): + match.push_back('?'); + break; + case ('a'): + match.push_back('\a'); + break; + case ('b'): + match.push_back('\b'); + break; + case ('f'): + match.push_back('\f'); + break; + case ('n'): + match.push_back('\n'); + break; + case ('r'): + match.push_back('\r'); + break; + case ('t'): + match.push_back('\t'); + break; + case ('v'): + match.push_back('\v'); + break; + case ('$'): + match.push_back('$'); + break; + default: + throw exception::eval_error("Unknown escaped sequence in string", File_Position(line, col), filename); } is_escaped = false; } @@ -1292,10 +1270,8 @@ namespace chaiscript } } } - }; - /// Reads (and potentially captures) a quoted string from input. Translates escaped sequences. bool Quoted_String() { Depth_Counter dc{this}; @@ -1307,25 +1283,24 @@ namespace chaiscript std::string match; const auto prev_stack_top = m_match_stack.size(); - bool is_interpolated = [&]()->bool { + bool is_interpolated = [&]() -> bool { Char_Parser cparser(match, true); - auto s = start + 1, end = m_position - 1; while (s != end) { if (cparser.saw_interpolation_marker) { if (*s == '{') { - //We've found an interpolation point + // We've found an interpolation point m_match_stack.push_back(make_node>(match, start.line, start.col, const_var(match))); if (cparser.is_interpolated) { - //If we've seen previous interpolation, add on instead of making a new one + // If we've seen previous interpolation, add on instead of making a new one build_match>(prev_stack_top, "+"); } - //We've finished with the part of the string up to this point, so clear it + // We've finished with the part of the string up to this point, so clear it match.clear(); std::string eval_match; @@ -1435,13 +1410,14 @@ namespace chaiscript } if (match.size() != 1) { - throw exception::eval_error("Single-quoted strings must be 1 character long", File_Position(m_position.line, m_position.col), *m_filename); + throw exception::eval_error("Single-quoted strings must be 1 character long", + File_Position(m_position.line, m_position.col), + *m_filename); } m_match_stack.push_back(make_node>(match, start.line, start.col, const_var(char(match.at(0))))); return true; - } - else { + } else { return false; } } @@ -1488,7 +1464,7 @@ namespace chaiscript const auto start = m_position; bool retval = Keyword_(t_s); // ignore substring matches - if ( retval && m_position.has_more() && char_in_alphabet(*m_position, detail::keyword_alphabet) ) { + if (retval && m_position.has_more() && char_in_alphabet(*m_position, detail::keyword_alphabet)) { m_position = start; retval = false; } @@ -1496,20 +1472,18 @@ namespace chaiscript return retval; } - bool is_operator(std::string_view t_s) const noexcept { - return m_operator_matches.is_match(t_s); - } + bool is_operator(std::string_view t_s) const noexcept { return m_operator_matches.is_match(t_s); } /// Reads (and potentially captures) a symbol group from input if it matches the parameter - bool Symbol(const utility::Static_String &t_s, const bool t_disallow_prevention=false) { + bool Symbol(const utility::Static_String &t_s, const bool t_disallow_prevention = false) { Depth_Counter dc{this}; SkipWS(); const auto start = m_position; bool retval = Symbol_(t_s); // ignore substring matches - if (retval && m_position.has_more() && (t_disallow_prevention == false) && char_in_alphabet(*m_position,detail::symbol_alphabet)) { - if (*m_position != '=' && is_operator(Position::str(start, m_position)) && !is_operator(Position::str(start, m_position+1))) { + if (retval && m_position.has_more() && (t_disallow_prevention == false) && char_in_alphabet(*m_position, detail::symbol_alphabet)) { + if (*m_position != '=' && is_operator(Position::str(start, m_position)) && !is_operator(Position::str(start, m_position + 1))) { // don't throw this away, it's a good match and the next is not } else { m_position = start; @@ -1561,14 +1535,16 @@ namespace chaiscript if (Arg(false)) { retval = true; - while (Eol()) {} + while (Eol()) { + } while (Char(',')) { - while (Eol()) {} + while (Eol()) { + } if (!Arg(false)) { throw exception::eval_error("Unexpected value in parameter list", File_Position(m_position.line, m_position.col), *m_filename); } - } + } } build_match>(prev_stack_top); @@ -1587,10 +1563,12 @@ namespace chaiscript if (Arg()) { retval = true; - while (Eol()) {} + while (Eol()) { + } while (Char(',')) { - while (Eol()) {} + while (Eol()) { + } if (!Arg()) { throw exception::eval_error("Unexpected value in parameter list", File_Position(m_position.line, m_position.col), *m_filename); } @@ -1603,7 +1581,6 @@ namespace chaiscript return retval; } - /// Reads a comma-separated list of values from input bool Arg_List() { Depth_Counter dc{this}; @@ -1614,9 +1591,11 @@ namespace chaiscript if (Equation()) { retval = true; - while (Eol()) {} + while (Eol()) { + } while (Char(',')) { - while (Eol()) {} + while (Eol()) { + } if (!Equation()) { throw exception::eval_error("Unexpected value in parameter list", File_Position(m_position.line, m_position.col), *m_filename); } @@ -1643,9 +1622,11 @@ namespace chaiscript build_match>(prev_stack_top); } else if (Map_Pair()) { retval = true; - while (Eol()) {} + while (Eol()) { + } while (Char(',')) { - while (Eol()) {} + while (Eol()) { + } if (!Map_Pair()) { throw exception::eval_error("Unexpected value in container", File_Position(m_position.line, m_position.col), *m_filename); } @@ -1653,9 +1634,11 @@ namespace chaiscript build_match>(prev_stack_top); } else if (Operator()) { retval = true; - while (Eol()) {} + while (Eol()) { + } while (Char(',')) { - while (Eol()) {} + while (Eol()) { + } if (!Operator()) { throw exception::eval_error("Unexpected value in container", File_Position(m_position.line, m_position.col), *m_filename); } @@ -1697,8 +1680,8 @@ namespace chaiscript throw exception::eval_error("Incomplete anonymous function", File_Position(m_position.line, m_position.col), *m_filename); } - - while (Eol()) {} + while (Eol()) { + } if (!Block()) { throw exception::eval_error("Incomplete anonymous function", File_Position(m_position.line, m_position.col), *m_filename); @@ -1731,7 +1714,7 @@ namespace chaiscript bool is_method = false; if (Symbol("::")) { - //We're now a method + // We're now a method is_method = true; if (!Id(true)) { @@ -1746,15 +1729,19 @@ namespace chaiscript } } - while (Eos()) {} + while (Eos()) { + } if (Char(':')) { if (!Operator()) { - throw exception::eval_error("Missing guard expression for function", File_Position(m_position.line, m_position.col), *m_filename); + throw exception::eval_error("Missing guard expression for function", + File_Position(m_position.line, m_position.col), + *m_filename); } } - while (Eol()) {} + while (Eol()) { + } if (!Block()) { throw exception::eval_error("Incomplete function definition", File_Position(m_position.line, m_position.col), *m_filename); } @@ -1764,7 +1751,6 @@ namespace chaiscript } else { build_match>(prev_stack_top); } - } return retval; @@ -1780,7 +1766,8 @@ namespace chaiscript if (Keyword("try")) { retval = true; - while (Eol()) {} + while (Eol()) { + } if (!Block()) { throw exception::eval_error("Incomplete 'try' block", File_Position(m_position.line, m_position.col), *m_filename); @@ -1788,17 +1775,21 @@ namespace chaiscript bool has_matches = true; while (has_matches) { - while (Eol()) {} + while (Eol()) { + } has_matches = false; if (Keyword("catch")) { const auto catch_stack_top = m_match_stack.size(); if (Char('(')) { if (!(Arg() && Char(')'))) { - throw exception::eval_error("Incomplete 'catch' expression", File_Position(m_position.line, m_position.col), *m_filename); + throw exception::eval_error("Incomplete 'catch' expression", + File_Position(m_position.line, m_position.col), + *m_filename); } } - while (Eol()) {} + while (Eol()) { + } if (!Block()) { throw exception::eval_error("Incomplete 'catch' block", File_Position(m_position.line, m_position.col), *m_filename); @@ -1807,11 +1798,13 @@ namespace chaiscript has_matches = true; } } - while (Eol()) {} + while (Eol()) { + } if (Keyword("finally")) { const auto finally_stack_top = m_match_stack.size(); - while (Eol()) {} + while (Eol()) { + } if (!Block()) { throw exception::eval_error("Incomplete 'finally' block", File_Position(m_position.line, m_position.col), *m_filename); @@ -1849,7 +1842,8 @@ namespace chaiscript throw exception::eval_error("Incomplete 'if' expression", File_Position(m_position.line, m_position.col), *m_filename); } - while (Eol()) {} + while (Eol()) { + } if (!Block()) { throw exception::eval_error("Incomplete 'if' block", File_Position(m_position.line, m_position.col), *m_filename); @@ -1857,13 +1851,15 @@ namespace chaiscript bool has_matches = true; while (has_matches) { - while (Eol()) {} + while (Eol()) { + } has_matches = false; if (Keyword("else")) { if (If()) { has_matches = true; } else { - while (Eol()) {} + while (Eol()) { + } if (!Block()) { throw exception::eval_error("Incomplete 'else' block", File_Position(m_position.line, m_position.col), *m_filename); @@ -1875,15 +1871,14 @@ namespace chaiscript const auto num_children = m_match_stack.size() - prev_stack_top; - if ((is_if_init && num_children == 3) - || (!is_if_init && num_children == 2)) { + if ((is_if_init && num_children == 3) || (!is_if_init && num_children == 2)) { m_match_stack.push_back(chaiscript::make_unique, eval::Noop_AST_Node>()); } if (!is_if_init) { build_match>(prev_stack_top); } else { - build_match>(prev_stack_top+1); + build_match>(prev_stack_top + 1); build_match>(prev_stack_top); } } @@ -1900,7 +1895,9 @@ namespace chaiscript if (Keyword("class")) { if (!t_class_allowed) { - throw exception::eval_error("Class definitions only allowed at top scope", File_Position(m_position.line, m_position.col), *m_filename); + throw exception::eval_error("Class definitions only allowed at top scope", + File_Position(m_position.line, m_position.col), + *m_filename); } retval = true; @@ -1911,7 +1908,8 @@ namespace chaiscript const auto class_name = m_match_stack.back()->text; - while (Eol()) {} + while (Eol()) { + } if (!Class_Block(class_name)) { throw exception::eval_error("Incomplete 'class' block", File_Position(m_position.line, m_position.col), *m_filename); @@ -1923,7 +1921,6 @@ namespace chaiscript return retval; } - /// Reads a while block from input bool While() { Depth_Counter dc{this}; @@ -1942,7 +1939,8 @@ namespace chaiscript throw exception::eval_error("Incomplete 'while' expression", File_Position(m_position.line, m_position.col), *m_filename); } - while (Eol()) {} + while (Eol()) { + } if (!Block()) { throw exception::eval_error("Incomplete 'while' block", File_Position(m_position.line, m_position.col), *m_filename); @@ -1961,39 +1959,33 @@ namespace chaiscript return Char(':') && Equation(); } - /// Reads the C-style `for` conditions from input bool For_Guards() { Depth_Counter dc{this}; - if (!(Equation() && Eol())) - { - if (!Eol()) - { + if (!(Equation() && Eol())) { + if (!Eol()) { return false; } else { m_match_stack.push_back(chaiscript::make_unique, eval::Noop_AST_Node>()); } } - if (!(Equation() && Eol())) - { - if (!Eol()) - { + if (!(Equation() && Eol())) { + if (!Eol()) { return false; } else { - m_match_stack.push_back(chaiscript::make_unique, eval::Constant_AST_Node>(Boxed_Value(true))); + m_match_stack.push_back( + chaiscript::make_unique, eval::Constant_AST_Node>(Boxed_Value(true))); } } - if (!Equation()) - { + if (!Equation()) { m_match_stack.push_back(chaiscript::make_unique, eval::Noop_AST_Node>()); } - return true; + return true; } - /// Reads a for block from input bool For() { Depth_Counter dc{this}; @@ -2013,7 +2005,8 @@ namespace chaiscript throw exception::eval_error("Incomplete 'for' expression", File_Position(m_position.line, m_position.col), *m_filename); } - while (Eol()) {} + while (Eol()) { + } if (!Block()) { throw exception::eval_error("Incomplete 'for' block", File_Position(m_position.line, m_position.col), *m_filename); @@ -2037,7 +2030,6 @@ namespace chaiscript return retval; } - /// Reads a case block from input bool Case() { Depth_Counter dc{this}; @@ -2056,7 +2048,8 @@ namespace chaiscript throw exception::eval_error("Incomplete 'case' expression", File_Position(m_position.line, m_position.col), *m_filename); } - while (Eol()) {} + while (Eol()) { + } if (!Block()) { throw exception::eval_error("Incomplete 'case' block", File_Position(m_position.line, m_position.col), *m_filename); @@ -2066,7 +2059,8 @@ namespace chaiscript } else if (Keyword("default")) { retval = true; - while (Eol()) {} + while (Eol()) { + } if (!Block()) { throw exception::eval_error("Incomplete 'default' block", File_Position(m_position.line, m_position.col), *m_filename); @@ -2078,14 +2072,12 @@ namespace chaiscript return retval; } - /// Reads a switch statement from input bool Switch() { Depth_Counter dc{this}; const auto prev_stack_top = m_match_stack.size(); if (Keyword("switch")) { - if (!Char('(')) { throw exception::eval_error("Incomplete 'switch' expression", File_Position(m_position.line, m_position.col), *m_filename); } @@ -2094,22 +2086,25 @@ namespace chaiscript throw exception::eval_error("Incomplete 'switch' expression", File_Position(m_position.line, m_position.col), *m_filename); } - while (Eol()) {} + while (Eol()) { + } if (Char('{')) { - while (Eol()) {} - - while (Case()) { - while (Eol()) { } // eat + while (Eol()) { } - while (Eol()) { } // eat + while (Case()) { + while (Eol()) { + } // eat + } + + while (Eol()) { + } // eat if (!Char('}')) { throw exception::eval_error("Incomplete block", File_Position(m_position.line, m_position.col), *m_filename); } - } - else { + } else { throw exception::eval_error("Incomplete block", File_Position(m_position.line, m_position.col), *m_filename); } @@ -2119,10 +2114,8 @@ namespace chaiscript } else { return false; } - } - /// Reads a curly-brace C-style class block from input bool Class_Block(const std::string &t_class_name) { Depth_Counter dc{this}; @@ -2219,9 +2212,7 @@ namespace chaiscript bool retval = false; const auto prev_stack_top = m_match_stack.size(); - if (Lambda() || Num() || Quoted_String() || Single_Quoted_String() || - Paren_Expression() || Inline_Container() || Id(false)) - { + if (Lambda() || Num() || Quoted_String() || Single_Quoted_String() || Paren_Expression() || Inline_Container() || Id(false)) { retval = true; bool has_more = true; @@ -2240,21 +2231,33 @@ namespace chaiscript /// \todo Work around for method calls until we have a better solution if (!m_match_stack.back()->children.empty()) { if (m_match_stack.back()->children[0]->identifier == AST_Node_Type::Dot_Access) { - if (m_match_stack.empty()) { throw exception::eval_error("Incomplete dot access fun call", File_Position(m_position.line, m_position.col), *m_filename); -} - if (m_match_stack.back()->children.empty()) { throw exception::eval_error("Incomplete dot access fun call", File_Position(m_position.line, m_position.col), *m_filename); -} + if (m_match_stack.empty()) { + throw exception::eval_error("Incomplete dot access fun call", + File_Position(m_position.line, m_position.col), + *m_filename); + } + if (m_match_stack.back()->children.empty()) { + throw exception::eval_error("Incomplete dot access fun call", + File_Position(m_position.line, m_position.col), + *m_filename); + } auto dot_access = std::move(m_match_stack.back()->children[0]); auto func_call = std::move(m_match_stack.back()); m_match_stack.pop_back(); func_call->children.erase(func_call->children.begin()); - if (dot_access->children.empty()) { throw exception::eval_error("Incomplete dot access fun call", File_Position(m_position.line, m_position.col), *m_filename); -} + if (dot_access->children.empty()) { + throw exception::eval_error("Incomplete dot access fun call", + File_Position(m_position.line, m_position.col), + *m_filename); + } func_call->children.insert(func_call->children.begin(), std::move(dot_access->children.back())); dot_access->children.pop_back(); dot_access->children.push_back(std::move(func_call)); - if (dot_access->children.size() != 2) { throw exception::eval_error("Incomplete dot access fun call", File_Position(m_position.line, m_position.col), *m_filename); -} + if (dot_access->children.size() != 2) { + throw exception::eval_error("Incomplete dot access fun call", + File_Position(m_position.line, m_position.col), + *m_filename); + } m_match_stack.push_back(std::move(dot_access)); } } @@ -2266,21 +2269,20 @@ namespace chaiscript } build_match>(prev_stack_top); - } - else if (Symbol(".")) { + } else if (Symbol(".")) { has_more = true; if (!(Id(true))) { throw exception::eval_error("Incomplete dot access fun call", File_Position(m_position.line, m_position.col), *m_filename); } - if ( std::distance(m_match_stack.begin() + static_cast(prev_stack_top), m_match_stack.end()) != 2) { + if (std::distance(m_match_stack.begin() + static_cast(prev_stack_top), m_match_stack.end()) != 2) { throw exception::eval_error("Incomplete dot access fun call", File_Position(m_position.line, m_position.col), *m_filename); } build_match>(prev_stack_top); - } - else if (Eol()) { + } else if (Eol()) { auto start = --m_position; - while (Eol()) {} + while (Eol()) { + } if (Symbol(".")) { has_more = true; --m_position; @@ -2311,7 +2313,7 @@ namespace chaiscript } build_match>(prev_stack_top); - } else if (Keyword("auto") || Keyword("var") ) { + } else if (Keyword("auto") || Keyword("var")) { retval = true; if (Reference()) { @@ -2343,7 +2345,6 @@ namespace chaiscript throw exception::eval_error("Missing attribute name in definition", File_Position(m_position.line, m_position.col), *m_filename); } - build_match>(prev_stack_top); } @@ -2375,20 +2376,19 @@ namespace chaiscript Container_Arg_List(); if (!Char(']')) { - throw exception::eval_error("Missing closing square bracket ']' in container initializer", File_Position(m_position.line, m_position.col), *m_filename); + throw exception::eval_error("Missing closing square bracket ']' in container initializer", + File_Position(m_position.line, m_position.col), + *m_filename); } if ((prev_stack_top != m_match_stack.size()) && (!m_match_stack.back()->children.empty())) { if (m_match_stack.back()->children[0]->identifier == AST_Node_Type::Value_Range) { build_match>(prev_stack_top); - } - else if (m_match_stack.back()->children[0]->identifier == AST_Node_Type::Map_Pair) { + } else if (m_match_stack.back()->children[0]->identifier == AST_Node_Type::Map_Pair) { build_match>(prev_stack_top); - } - else { + } else { build_match>(prev_stack_top); } - } - else { + } else { build_match>(prev_stack_top); } @@ -2420,22 +2420,15 @@ namespace chaiscript Depth_Counter dc{this}; const auto prev_stack_top = m_match_stack.size(); using SS = utility::Static_String; - const std::array prefix_opers{{ - SS{"++"}, - SS{"--"}, - SS{"-"}, - SS{"+"}, - SS{"!"}, - SS{"~"} - }}; + const std::array prefix_opers{{SS{"++"}, SS{"--"}, SS{"-"}, SS{"+"}, SS{"!"}, SS{"~"}}}; - for (const auto &oper : prefix_opers) - { + for (const auto &oper : prefix_opers) { const bool is_char = oper.size() == 1; - if ((is_char && Char(oper.c_str()[0])) || (!is_char && Symbol(oper))) - { - if (!Operator(m_operators.size()-1)) { - throw exception::eval_error("Incomplete prefix '" + std::string(oper.c_str()) + "' expression", File_Position(m_position.line, m_position.col), *m_filename); + if ((is_char && Char(oper.c_str()[0])) || (!is_char && Symbol(oper))) { + if (!Operator(m_operators.size() - 1)) { + throw exception::eval_error("Incomplete prefix '" + std::string(oper.c_str()) + "' expression", + File_Position(m_position.line, m_position.col), + *m_filename); } build_match>(prev_stack_top, oper.c_str()); @@ -2453,73 +2446,74 @@ namespace chaiscript } bool Operator_Helper(const size_t t_precedence, std::string &oper) { - return m_operator_matches.any_of(t_precedence, - [&oper, this](const auto &elem){ - if (Symbol(elem)) { - oper = elem.c_str(); - return true; - } else { - return false; - } - } - ); + return m_operator_matches.any_of(t_precedence, [&oper, this](const auto &elem) { + if (Symbol(elem)) { + oper = elem.c_str(); + return true; + } else { + return false; + } + }); } - bool Operator(const size_t t_precedence = 0) { Depth_Counter dc{this}; bool retval = false; const auto prev_stack_top = m_match_stack.size(); if (m_operators[t_precedence] != Operator_Precedence::Prefix) { - if (Operator(t_precedence+1)) { + if (Operator(t_precedence + 1)) { retval = true; std::string oper; while (Operator_Helper(t_precedence, oper)) { - while (Eol()) {} - if (!Operator(t_precedence+1)) { + while (Eol()) { + } + if (!Operator(t_precedence + 1)) { throw exception::eval_error("Incomplete '" + oper + "' expression", - File_Position(m_position.line, m_position.col), *m_filename); + File_Position(m_position.line, m_position.col), + *m_filename); } switch (m_operators[t_precedence]) { - case(Operator_Precedence::Ternary_Cond) : + case (Operator_Precedence::Ternary_Cond): if (Symbol(":")) { - if (!Operator(t_precedence+1)) { + if (!Operator(t_precedence + 1)) { throw exception::eval_error("Incomplete '" + oper + "' expression", - File_Position(m_position.line, m_position.col), *m_filename); + File_Position(m_position.line, m_position.col), + *m_filename); } build_match>(prev_stack_top); - } - else { + } else { throw exception::eval_error("Incomplete '" + oper + "' expression", - File_Position(m_position.line, m_position.col), *m_filename); + File_Position(m_position.line, m_position.col), + *m_filename); } break; - case(Operator_Precedence::Addition) : - case(Operator_Precedence::Multiplication) : - case(Operator_Precedence::Shift) : - case(Operator_Precedence::Equality) : - case(Operator_Precedence::Bitwise_And) : - case(Operator_Precedence::Bitwise_Xor) : - case(Operator_Precedence::Bitwise_Or) : - case(Operator_Precedence::Comparison) : + case (Operator_Precedence::Addition): + case (Operator_Precedence::Multiplication): + case (Operator_Precedence::Shift): + case (Operator_Precedence::Equality): + case (Operator_Precedence::Bitwise_And): + case (Operator_Precedence::Bitwise_Xor): + case (Operator_Precedence::Bitwise_Or): + case (Operator_Precedence::Comparison): build_match>(prev_stack_top, oper); break; - case(Operator_Precedence::Logical_And) : + case (Operator_Precedence::Logical_And): build_match>(prev_stack_top, oper); break; - case(Operator_Precedence::Logical_Or) : + case (Operator_Precedence::Logical_Or): build_match>(prev_stack_top, oper); break; - case(Operator_Precedence::Prefix) : + case (Operator_Precedence::Prefix): assert(false); // cannot reach here because of if() statement at the top break; -// default: -// throw exception::eval_error("Internal error: unhandled ast_node", File_Position(m_position.line, m_position.col), *m_filename); + // default: + // throw exception::eval_error("Internal error: unhandled ast_node", + // File_Position(m_position.line, m_position.col), *m_filename); } } } @@ -2546,8 +2540,7 @@ namespace chaiscript } build_match>(prev_stack_top); - } - else { + } else { m_position = prev_pos; while (prev_stack_top != m_match_stack.size()) { m_match_stack.pop_back(); @@ -2574,8 +2567,7 @@ namespace chaiscript } build_match>(prev_stack_top); - } - else { + } else { m_position = prev_pos; while (prev_stack_top != m_match_stack.size()) { m_match_stack.pop_back(); @@ -2594,8 +2586,8 @@ namespace chaiscript using SS = utility::Static_String; if (Operator()) { - for (const auto &sym : {SS{"="}, SS{":="}, SS{"+="}, SS{"-="}, SS{"*="}, SS{"/="}, SS{"%="}, SS{"<<="}, SS{">>="}, SS{"&="}, SS{"^="}, SS{"|="}}) - { + for (const auto &sym : + {SS{"="}, SS{":="}, SS{"+="}, SS{"-="}, SS{"*="}, SS{"/="}, SS{"%="}, SS{"<<="}, SS{">>="}, SS{"&="}, SS{"^="}, SS{"|="}}) { if (Symbol(sym, true)) { SkipWS(true); if (!Equation()) { @@ -2624,7 +2616,9 @@ namespace chaiscript const auto start = m_position; if (Def(true, t_class_name) || Var_Decl(true, t_class_name)) { if (!saw_eol) { - throw exception::eval_error("Two function definitions missing line separator", File_Position(start.line, start.col), *m_filename); + throw exception::eval_error("Two function definitions missing line separator", + File_Position(start.line, start.col), + *m_filename); } has_more = true; retval = true; @@ -2653,26 +2647,25 @@ namespace chaiscript const auto start = m_position; if (Def() || Try() || If() || While() || Class(t_class_allowed) || For() || Switch()) { if (!saw_eol) { - throw exception::eval_error("Two function definitions missing line separator", File_Position(start.line, start.col), *m_filename); + throw exception::eval_error("Two function definitions missing line separator", + File_Position(start.line, start.col), + *m_filename); } has_more = true; retval = true; saw_eol = true; - } - else if (Return() || Break() || Continue() || Equation()) { + } else if (Return() || Break() || Continue() || Equation()) { if (!saw_eol) { throw exception::eval_error("Two expressions missing line separator", File_Position(start.line, start.col), *m_filename); } has_more = true; retval = true; saw_eol = false; - } - else if (Block() || Eol()) { + } else if (Block() || Eol()) { has_more = true; retval = true; saw_eol = true; - } - else { + } else { has_more = false; } } @@ -2680,16 +2673,14 @@ namespace chaiscript return retval; } - AST_NodePtr parse(const std::string &t_input, const std::string &t_fname) override - { + AST_NodePtr parse(const std::string &t_input, const std::string &t_fname) override { ChaiScript_Parser parser(m_tracer, m_optimizer); return parser.parse_internal(t_input, t_fname); } - eval::AST_Node_Impl_Ptr parse_instr_eval(const std::string &t_input) - { - auto last_position = m_position; - auto last_filename = m_filename; + eval::AST_Node_Impl_Ptr parse_instr_eval(const std::string &t_input) { + auto last_position = m_position; + auto last_filename = m_filename; auto last_match_stack = std::exchange(m_match_stack, decltype(m_match_stack){}); auto retval = parse_internal(t_input, "instr eval"); @@ -2698,7 +2689,7 @@ namespace chaiscript m_filename = std::move(last_filename); m_match_stack = std::move(last_match_stack); - return eval::AST_Node_Impl_Ptr(dynamic_cast*>(retval.release())); + return eval::AST_Node_Impl_Ptr(dynamic_cast *>(retval.release())); } /// Parses the given input string, tagging parsed ast_nodes with the given m_filename. @@ -2729,8 +2720,8 @@ namespace chaiscript return retval; } }; - } -} + } // namespace parser +} // namespace chaiscript #if defined(CHAISCRIPT_MSVC) && defined(CHAISCRIPT_PUSHED_MIN_MAX) #undef CHAISCRIPT_PUSHED_MIN_MAX @@ -2738,6 +2729,4 @@ namespace chaiscript #pragma pop_macro("max") #endif - #endif /* CHAISCRIPT_PARSER_HPP_ */ - diff --git a/include/chaiscript/language/chaiscript_posix.hpp b/include/chaiscript/language/chaiscript_posix.hpp index b909347a..48d5eb53 100644 --- a/include/chaiscript/language/chaiscript_posix.hpp +++ b/include/chaiscript/language/chaiscript_posix.hpp @@ -7,62 +7,47 @@ #ifndef CHAISCRIPT_POSIX_HPP_ #define CHAISCRIPT_POSIX_HPP_ -namespace chaiscript -{ - namespace detail - { - struct Loadable_Module - { - struct DLModule - { - explicit DLModule(const std::string &t_filename) - : m_data(dlopen(t_filename.c_str(), RTLD_NOW)) - { - if (m_data == nullptr) - { - throw chaiscript::exception::load_module_error(dlerror()); - } +namespace chaiscript::detail { + struct Loadable_Module { + struct DLModule { + explicit DLModule(const std::string &t_filename) + : m_data(dlopen(t_filename.c_str(), RTLD_NOW)) { + if (m_data == nullptr) { + throw chaiscript::exception::load_module_error(dlerror()); } - - DLModule(DLModule &&) = default; - DLModule &operator=(DLModule &&) = default; - DLModule(const DLModule &) = delete; - DLModule &operator=(const DLModule &) = delete; - - ~DLModule() - { - dlclose(m_data); - } - - void *m_data; - }; - - template - struct DLSym - { - DLSym(DLModule &t_mod, const std::string &t_symbol) - : m_symbol(reinterpret_cast(dlsym(t_mod.m_data, t_symbol.c_str()))) - { - if (!m_symbol) - { - throw chaiscript::exception::load_module_error(dlerror()); - } - } - - T m_symbol; - }; - - 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_moduleptr(m_func.m_symbol()) - { } - DLModule m_dlmodule; - DLSym m_func; - ModulePtr m_moduleptr; - }; - } -} -#endif + DLModule(DLModule &&) = default; + DLModule &operator=(DLModule &&) = default; + DLModule(const DLModule &) = delete; + DLModule &operator=(const DLModule &) = delete; + ~DLModule() { dlclose(m_data); } + + void *m_data; + }; + + template + struct DLSym { + DLSym(DLModule &t_mod, const std::string &t_symbol) + : m_symbol(reinterpret_cast(dlsym(t_mod.m_data, t_symbol.c_str()))) { + if (!m_symbol) { + throw chaiscript::exception::load_module_error(dlerror()); + } + } + + T m_symbol; + }; + + 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_moduleptr(m_func.m_symbol()) { + } + + DLModule m_dlmodule; + DLSym m_func; + ModulePtr m_moduleptr; + }; +} // namespace chaiscript::detail +#endif diff --git a/include/chaiscript/language/chaiscript_prelude.hpp b/include/chaiscript/language/chaiscript_prelude.hpp index 46e3f5d4..b10bec66 100644 --- a/include/chaiscript/language/chaiscript_prelude.hpp +++ b/include/chaiscript/language/chaiscript_prelude.hpp @@ -8,8 +8,9 @@ #define CHAISCRIPT_PRELUDE_HPP_ namespace chaiscript { -struct ChaiScript_Prelude { - static std::string chaiscript_prelude() { return R"chaiscript( + struct ChaiScript_Prelude { + static std::string chaiscript_prelude() { + return R"chaiscript( def lt(l, r) { if (call_exists(`<`, l, r)) { @@ -554,9 +555,8 @@ def find(container, value) { )chaiscript"; -} - -}; -} + } + }; +} // namespace chaiscript #endif /* CHAISCRIPT_PRELUDE_HPP_ */ diff --git a/include/chaiscript/language/chaiscript_prelude_docs.hpp b/include/chaiscript/language/chaiscript_prelude_docs.hpp index 7df56521..c7fe40c7 100644 --- a/include/chaiscript/language/chaiscript_prelude_docs.hpp +++ b/include/chaiscript/language/chaiscript_prelude_docs.hpp @@ -2,26 +2,22 @@ /// 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 -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 -/// -/// 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). -/// - - -/// \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 -{ + /// \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: /// \brief Returns the Type_Info value for this Object Type_Info get_type_info() const; @@ -41,52 +37,49 @@ class Object /// \brief Returns true if the Object is stored as a pointer bool is_var_pointer() const; - /// \brief Returns true if the Object is stored as a reference + /// \brief Returns true if the Object is stored as a reference bool is_var_reference() const; /// \brief Returns true if the Object does not contain a value is is undefined. bool is_var_undef() const; - /// \brief Returns the registered name of the type of the object. + /// \brief Returns the registered name of the type of the object. /// /// \sa Type_Info::name(); string type_name() const; -}; + }; -/// \brief Item returned from a Range object from a Map -class Map_Pair -{ + /// \brief Item returned from a Range object from a Map + class Map_Pair { public: /// \brief Returns the key of the Map entry const string first(); - /// \brief Returns the value Object of the Map entry + /// \brief Returns the value Object of the Map entry Object second(); -}; + }; - -/// \brief Maps strings to Objects -/// -/// ChaiScript has a built in shortcut for generating Map objects: -/// -/// Example: -/// \code -/// eval> var m = ["a":1, "b":2]; -/// [, ] -/// eval> m.count("a"); -/// 1 -/// eval> m.count("c"); -/// 0 -/// eval> m.size(); -/// 2 -/// \endcode -/// -/// Implemented as std::map -/// -/// \sa Map_Pair -/// \sa chaiscript::bootstrap::standard_library::map_type -class Map -{ + /// \brief Maps strings to Objects + /// + /// ChaiScript has a built in shortcut for generating Map objects: + /// + /// Example: + /// \code + /// eval> var m = ["a":1, "b":2]; + /// [, ] + /// eval> m.count("a"); + /// 1 + /// eval> m.count("c"); + /// 0 + /// eval> m.size(); + /// 2 + /// \endcode + /// + /// Implemented as std::map + /// + /// \sa Map_Pair + /// \sa chaiscript::bootstrap::standard_library::map_type + class Map { public: /// \brief Returns an object that implements the Range concept for the Map_Pair's in this Map Range range(); @@ -108,64 +101,57 @@ class Map /// \brief Returns true if the map contains no items 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: void push_back(Object); Range range(); Const_Range range() const; -}; + }; + /// \brief Converts o into a string. + /// + /// \code + /// eval> to_string(3).is_type("string")
+ /// true
+ /// \endcode + string to_string(Object o); -/// \brief Converts o into a string. -/// -/// \code -/// eval> to_string(3).is_type("string")
-/// true
-/// \endcode -string to_string(Object o); + /// \brief Prints o to the terminal, without a trailing carriage return. Applies conversions to string automatically. + /// \code + /// eval> puts("hi, "); puts("there") + /// hi, thereeval> + /// \endcode + /// \sa to_string + /// \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. -/// \code -/// eval> puts("hi, "); puts("there") -/// hi, thereeval> -/// \endcode -/// \sa to_string -/// \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 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 -{ + /// \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: /// \brief Finds the first instance of substr. /// \code @@ -174,7 +160,6 @@ class string /// \endcode int find(string s) const; - /// \brief Finds the last instance of substr. /// \code /// eval> rfind("abab", "ab") @@ -211,7 +196,7 @@ class string /// \code /// eval> find_last_not_of("abcd", "fec") /// 3 - /// \endcode + /// \endcode int find_last_not_of(string list) const; /// \brief Removes whitespace from the front of the string, returning a new string @@ -246,7 +231,7 @@ class string /// eval> trim(" bob ") + "|" /// bob| /// \endcode - /// + /// /// Equivalent to rtrim(ltrim(" bob ")); /// /// \sa \ref keyworddef @@ -281,16 +266,15 @@ class string /// \brief Returns an object that implements the Const_Range concept for the characters of this string Const_Range range() 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. -/// -/// Implemented by the template chaiscript::bootstrap::standard_library::Bidir_Range -/// -/// \sa Const_Range -class Range -{ + /// \brief A concept in ChaiScript that is implemented by \ref string, Vector and Map. It provides + /// easy iteration over the elements in a container. + /// + /// Implemented by the template chaiscript::bootstrap::standard_library::Bidir_Range + /// + /// \sa Const_Range + class Range { public: /// \brief Returns the last item of the range Object back(); @@ -303,25 +287,23 @@ class Range Object front(); /// \brief Moves the back pointer back one. - /// + /// /// \post back() returns the element at back() - 1; void pop_back(); /// \brief Moves the front pointer forward one - /// + /// /// \post front() returns the element at front() + 1; 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. -/// -/// Implemented by the template chaiscript::bootstrap::standard_library::Const_Bidir_Range -/// -/// \sa Range -class Const_Range -{ + /// \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 + /// + /// \sa Range + class Const_Range { public: /// \brief Returns the last item of the range const Object back(); @@ -334,36 +316,34 @@ class Const_Range const Object front(); /// \brief Moves the back pointer back one. - /// + /// /// \post back() returns the element at back() - 1; void pop_back(); /// \brief Moves the front pointer forward one - /// + /// /// \post front() returns the element at front() + 1; void pop_front(); + }; -}; - -/// \brief A vector of Objects -/// -/// ChaiScript includes a shortcut for creating a Vector of Objects -/// -/// Example: -/// \code -/// eval> var v = [1,2,3,4] -/// [1, 2, 3, 4] -/// eval> v[0]; -/// 1 -/// eval> v.size(); -/// 4 -/// \endcode -/// -/// Implemented with std::vector -/// -/// \sa chaiscript::bootstrap::standard_library::vector_type -class Vector -{ + /// \brief A vector of Objects + /// + /// ChaiScript includes a shortcut for creating a Vector of Objects + /// + /// Example: + /// \code + /// eval> var v = [1,2,3,4] + /// [1, 2, 3, 4] + /// eval> v[0]; + /// 1 + /// eval> v.size(); + /// 4 + /// \endcode + /// + /// Implemented with std::vector + /// + /// \sa chaiscript::bootstrap::standard_library::vector_type + class Vector { public: /// \brief returns the Object at the given index. Throws an exception if the index does not exist Object operator[](int t_index); @@ -387,15 +367,15 @@ class Vector Object front(); /// \brief Inserts a new item in the Vector at the given index. The item is not cloned on insert - /// + /// /// \sa insert_ref void insert_ref_at(int, Object); /// \brief Inserts a new item in the Vector at the given index. The item is cloned on insert - /// + /// /// \sa insert_ref void insert_at(int, Object); - + /// \brief Removes the last item from the Vector void pop_back(); @@ -417,11 +397,9 @@ class Vector /// \brief Returns the number of elements in the Vector int size() const; + }; -}; - -class Type_Info -{ + class Type_Info { public: /// \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. @@ -439,10 +417,10 @@ class Type_Info /// \brief Returns true if the type is a pointer bool is_type_pointer() const; - /// \brief Returns true if the type is a reference + /// \brief Returns true if the type is a reference bool is_type_reference() const; - /// \brief Returns true if the type is undefined + /// \brief Returns true if the type is undefined bool is_type_undef() const; /// \brief Returns true if the type is "void" @@ -450,32 +428,29 @@ class Type_Info /// \brief Returns the ChaiScript registered name for the type if one exists. string name() const; + }; -}; - - -/// \brief Represents a function object in ChaiScript -/// -/// A function object may be one function, such as: -/// \code -/// var f = fun(x) { return x; } -/// \endcode -/// -/// Or it may represent multiple functions -/// \code -/// var f2 = `-`; // represents the unary - as well as the set of binary - operators -/// \endcode -/// -/// Guarded function example -/// \code -/// def f3(x) : x > 2 { -/// return x; -/// } -/// \endcode -/// -/// Examples in the function definitions below will reference these examples -class Function -{ + /// \brief Represents a function object in ChaiScript + /// + /// A function object may be one function, such as: + /// \code + /// var f = fun(x) { return x; } + /// \endcode + /// + /// Or it may represent multiple functions + /// \code + /// var f2 = `-`; // represents the unary - as well as the set of binary - operators + /// \endcode + /// + /// Guarded function example + /// \code + /// def f3(x) : x > 2 { + /// return x; + /// } + /// \endcode + /// + /// Examples in the function definitions below will reference these examples + class Function { public: /// \brief Returns the annotation description of the function string get_annotation() const; @@ -492,7 +467,7 @@ class Function int get_arity() const; /// \brief Returns a vector of the contained functions - /// + /// /// Example: /// \code /// eval> f.get_contained_functions().size() @@ -506,7 +481,7 @@ class Function Vector get_contained_functions() const; /// \brief Returns a function guard as function - /// + /// /// Example: /// \code /// eval> f.get_guard() // Throws exception @@ -518,12 +493,12 @@ class Function /// \brief Returns a vector of Type_Info objects that represent the param types for this function. /// The first value in the list is the return type. - /// + /// /// If this function is a conglomerate of several functions (get_contained_values().size() > 0) /// then the function returns as many Type_Info objects as it can. If the functions contained all have /// the same arity, then it represents the arity. If they have different arities, it returns only - /// one value - the return type. - /// + /// one value - the return type. + /// /// For each parameter that is the same type, the type is returned. If the types are different /// then a Type_Info for Object is returned. /// @@ -538,293 +513,271 @@ class Function bool has_guard() const; /// \brief Calls the function with the given set of parameters and returns the value; - /// + /// /// Example: /// \code /// eval> `-`.call([2,1]); /// 1 /// \endcode 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 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 -/// 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 true if x is an even integer. + /// + /// Will also work on any non-integer type for which an operator%(x, int) exists + /// + /// Example: + /// \code + /// eval> even(4) + /// true + /// \endcode + bool even(Object x); -/// \brief Returns the min of a or b. Requires that operator<(a, b) exists -/// -/// Equivalent to -/// \code -/// return a min(4, 10) -/// 4 -/// \endcode -Object min(Object a, Object b); + /// \brief Returns true if x is an odd integer. + /// + /// Will also work on any non-integer type for which an operator%(x, int) exists + /// + /// Example: + /// \code + /// eval> odd(4) + /// false + /// \endcode + bool even(Object x); -/// \brief Returns true if x is an even integer. -/// -/// Will also work on any non-integer type for which an operator%(x, int) exists -/// -/// Example: -/// \code -/// eval> even(4) -/// true -/// \endcode -bool even(Object x); + /// \brief Applies the function f over each element in the Range c. + /// + /// Example: + /// \code + /// eval> for_each([1, 2, 3], print) + /// 1 + /// 2 + /// 3 + /// \endcode + void for_each(Range c, Function f); -/// \brief Returns true if x is an odd integer. -/// -/// Will also work on any non-integer type for which an operator%(x, int) exists -/// -/// Example: -/// \code -/// eval> odd(4) -/// false -/// \endcode -bool even(Object x); + /// \brief Applies f over each element in the Range c, joining all the results. + /// + /// Example: + /// \code + /// eval> map([1, 2, 3], odd) + /// [true, false, true] + /// \endcode + Object map(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. + /// 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. -/// -/// Example: -/// \code -/// eval> for_each([1, 2, 3], print) -/// 1 -/// 2 -/// 3 -/// \endcode -void for_each(Range c, Function f); + /// \brief Returns the sum total of the values in the Range c. + /// + /// Example: + /// \code + /// eval> sum([1, 2, 3, 4]) + /// 10 + /// \endcode + /// + /// Equivalent to: + /// \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. -/// -/// Example: -/// \code -/// eval> map([1, 2, 3], odd) -/// [true, false, true] -/// \endcode -Object map(Range c, Function f); + /// \brief Takes num elements from the Range c, returning them. + /// + /// Example: + /// \code + /// eval> take([1, 2, 3, 4], 2) + /// [1, 2] + /// \endcode + /// + /// \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. -/// 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 Drops num elements from the Range c, returning the remainder. + /// + /// Example: + /// \code + /// eval> drop([1, 2, 3, 4], 2) + /// [3, 4] + /// \endcode + /// + /// \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. -/// -/// Example: -/// \code -/// eval> sum([1, 2, 3, 4]) -/// 10 -/// \endcode -/// -/// Equivalent to: -/// \code -/// foldl(c, `+`, 0.0); -/// \endcode -Numeric sum(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: + /// \code + /// eval> reduce([1, 2, 3, 4], `+`) + /// 10 + /// \endcode + Object reduce(Range c, Function f); + /// \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. -/// -/// Example: -/// \code -/// eval> product([1, 2, 3, 4]) -/// 24 -/// \endcode -/// -/// Equivalent to: -/// \code -/// foldl(c, `*`, 1.0); -/// \endcode -Numeric product(Range c); + /// \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 Takes num elements from the Range c, returning them. -/// -/// Example: -/// \code -/// eval> take([1, 2, 3, 4], 2) -/// [1, 2] -/// \endcode -/// -/// \returns A container of the same type that was passed in -Object take(Range c, int num); + /// \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 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 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 Drops num elements from the Range c, returning the remainder. -/// -/// Example: -/// \code -/// eval> drop([1, 2, 3, 4], 2) -/// [3, 4] -/// \endcode -/// -/// \returns A container of the same type that was passed in -Object drop(Range c, int num); + /// \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 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 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 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: -/// \code -/// eval> reduce([1, 2, 3, 4], `+`) -/// 10 -/// \endcode -Object reduce(Range c, Function f); - - -/// \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 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); -} - + /// \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); +} // namespace ChaiScript_Language diff --git a/include/chaiscript/language/chaiscript_tracer.hpp b/include/chaiscript/language/chaiscript_tracer.hpp index 331c5e5e..c265dadd 100644 --- a/include/chaiscript/language/chaiscript_tracer.hpp +++ b/include/chaiscript/language/chaiscript_tracer.hpp @@ -7,40 +7,31 @@ #ifndef CHAISCRIPT_TRACER_HPP_ #define CHAISCRIPT_TRACER_HPP_ -namespace chaiscript { - namespace eval { +namespace chaiscript::eval { + struct Noop_Tracer_Detail { + template + constexpr void trace(const chaiscript::detail::Dispatch_State &, const AST_Node_Impl *) noexcept { + } + }; + template + struct Tracer : T... { + Tracer() = default; + constexpr explicit Tracer(T... t) + : T(std::move(t))... { + } - struct Noop_Tracer_Detail - { - template - constexpr void trace(const chaiscript::detail::Dispatch_State &, const AST_Node_Impl *) noexcept - { - } - }; + void do_trace(const chaiscript::detail::Dispatch_State &ds, const AST_Node_Impl> *node) { + (static_cast(*this).trace(ds, node), ...); + } - template - struct Tracer : T... - { - Tracer() = default; - constexpr explicit Tracer(T ... t) - : T(std::move(t))... - { - } + static void trace(const chaiscript::detail::Dispatch_State &ds, const AST_Node_Impl> *node) { + ds->get_parser().get_tracer>().do_trace(ds, node); + } + }; - void do_trace(const chaiscript::detail::Dispatch_State &ds, const AST_Node_Impl> *node) { - (static_cast(*this).trace(ds, node), ... ); - } + using Noop_Tracer = Tracer; - static void trace(const chaiscript::detail::Dispatch_State &ds, const AST_Node_Impl> *node) { - ds->get_parser().get_tracer>().do_trace(ds, node); - } - }; - - using Noop_Tracer = Tracer; - - } -} +} // namespace chaiscript::eval #endif - diff --git a/include/chaiscript/language/chaiscript_unknown.hpp b/include/chaiscript/language/chaiscript_unknown.hpp index be63ddef..e2a64707 100644 --- a/include/chaiscript/language/chaiscript_unknown.hpp +++ b/include/chaiscript/language/chaiscript_unknown.hpp @@ -7,15 +7,10 @@ #ifndef CHAISCRIPT_UNKNOWN_HPP_ #define CHAISCRIPT_UNKNOWN_HPP_ - -namespace chaiscript -{ - namespace detail - { - struct Loadable_Module - { - Loadable_Module(const std::string &, const std::string &) - { +namespace chaiscript { + namespace detail { + struct Loadable_Module { + Loadable_Module(const std::string &, const std::string &) { #ifdef CHAISCRIPT_NO_DYNLOAD throw chaiscript::exception::load_module_error("Loadable module support was disabled (CHAISCRIPT_NO_DYNLOAD)"); #else @@ -25,7 +20,6 @@ namespace chaiscript ModulePtr m_moduleptr; }; - } -} + } // namespace detail +} // namespace chaiscript #endif - diff --git a/include/chaiscript/language/chaiscript_windows.hpp b/include/chaiscript/language/chaiscript_windows.hpp index b5f1639b..5e2b6e88 100644 --- a/include/chaiscript/language/chaiscript_windows.hpp +++ b/include/chaiscript/language/chaiscript_windows.hpp @@ -17,41 +17,32 @@ #include #endif - -namespace chaiscript -{ - namespace detail - { - struct Loadable_Module - { +namespace chaiscript { + namespace detail { + struct Loadable_Module { template - static std::wstring to_wstring(const T &t_str) - { - return std::wstring(t_str.begin(), t_str.end()); - } + static std::wstring to_wstring(const T &t_str) { + return std::wstring(t_str.begin(), t_str.end()); + } template - static std::string to_string(const T &t_str) - { - return std::string(t_str.begin(), t_str.end()); - } + static std::string to_string(const T &t_str) { + return std::string(t_str.begin(), t_str.end()); + } #if defined(_UNICODE) || defined(UNICODE) - template - static std::wstring to_proper_string(const T &t_str) - { - return to_wstring(t_str); - } + template + static std::wstring to_proper_string(const T &t_str) { + return to_wstring(t_str); + } #else template - static std::string to_proper_string(const T &t_str) - { - return to_string(t_str); - } + static std::string to_proper_string(const T &t_str) { + return to_string(t_str); + } #endif - static std::string get_error_message(DWORD t_err) - { + static std::string get_error_message(DWORD t_err) { using StringType = LPTSTR; #if defined(_UNICODE) || defined(UNICODE) @@ -61,16 +52,15 @@ namespace chaiscript #endif StringType lpMsgBuf = nullptr; - if (FormatMessage( - FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - nullptr, - t_err, - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - reinterpret_cast(&lpMsgBuf), - 0, nullptr ) != 0 && lpMsgBuf) - { + if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + nullptr, + t_err, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + reinterpret_cast(&lpMsgBuf), + 0, + nullptr) + != 0 + && lpMsgBuf) { retval = lpMsgBuf; LocalFree(lpMsgBuf); } @@ -78,13 +68,10 @@ namespace chaiscript return to_string(retval); } - struct DLModule - { + struct DLModule { explicit DLModule(const std::string &t_filename) - : m_data(LoadLibrary(to_proper_string(t_filename).c_str())) - { - if (!m_data) - { + : m_data(LoadLibrary(to_proper_string(t_filename).c_str())) { + if (!m_data) { throw chaiscript::exception::load_module_error(get_error_message(GetLastError())); } } @@ -94,40 +81,33 @@ namespace chaiscript DLModule(const DLModule &) = delete; DLModule &operator=(const DLModule &) = delete; - ~DLModule() - { - FreeLibrary(m_data); - } + ~DLModule() { FreeLibrary(m_data); } HMODULE m_data; }; template - struct DLSym - { - DLSym(DLModule &t_mod, const std::string &t_symbol) - : m_symbol(reinterpret_cast(GetProcAddress(t_mod.m_data, t_symbol.c_str()))) - { - if (!m_symbol) - { - throw chaiscript::exception::load_module_error(get_error_message(GetLastError())); - } + struct DLSym { + DLSym(DLModule &t_mod, const std::string &t_symbol) + : m_symbol(reinterpret_cast(GetProcAddress(t_mod.m_data, t_symbol.c_str()))) { + if (!m_symbol) { + throw chaiscript::exception::load_module_error(get_error_message(GetLastError())); } + } - T m_symbol; - }; + T m_symbol; + }; 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_moduleptr(m_func.m_symbol()) - { + : m_dlmodule(t_filename) + , m_func(m_dlmodule, "create_chaiscript_module_" + t_module_name) + , m_moduleptr(m_func.m_symbol()) { } DLModule m_dlmodule; DLSym m_func; ModulePtr m_moduleptr; }; - } -} -#endif - + } // namespace detail +} // namespace chaiscript +#endif diff --git a/include/chaiscript/utility/fnv1a.hpp b/include/chaiscript/utility/fnv1a.hpp index 1d7f378d..7ebd12dc 100644 --- a/include/chaiscript/utility/fnv1a.hpp +++ b/include/chaiscript/utility/fnv1a.hpp @@ -7,19 +7,11 @@ #ifndef CHAISCRIPT_UTILITY_FNV1A_HPP_ #define CHAISCRIPT_UTILITY_FNV1A_HPP_ - -#include #include "../chaiscript_defines.hpp" +#include - -namespace chaiscript -{ - - - namespace utility - { - - +namespace chaiscript { + namespace utility { static constexpr std::uint32_t fnv1a_32(const char *s, std::uint32_t h = 0x811c9dc5) { #ifdef __GNUC__ #pragma GCC diagnostic push @@ -30,7 +22,7 @@ namespace chaiscript #pragma warning(push) #pragma warning(disable : 4307) #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 #pragma warning(pop) #endif @@ -38,13 +30,9 @@ namespace chaiscript #ifdef __GNUC__ #pragma GCC diagnostic pop #endif - } - - } - - -} + } // namespace utility +} // namespace chaiscript #endif diff --git a/include/chaiscript/utility/hash.hpp b/include/chaiscript/utility/hash.hpp index f1252b2c..15bc4d9c 100644 --- a/include/chaiscript/utility/hash.hpp +++ b/include/chaiscript/utility/hash.hpp @@ -7,18 +7,14 @@ #ifndef CHAISCRIPT_UTILITY_FNV1A_HPP_ #define CHAISCRIPT_UTILITY_FNV1A_HPP_ - -#include #include "../chaiscript_defines.hpp" +#include - -namespace chaiscript -{ - namespace utility - { +namespace chaiscript { + namespace utility { namespace fnv1a { template - static constexpr std::uint32_t hash(Itr begin, Itr end) noexcept { + static constexpr std::uint32_t hash(Itr begin, Itr end) noexcept { #ifdef __GNUC__ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wsign-conversion" @@ -28,13 +24,13 @@ namespace chaiscript #pragma warning(push) #pragma warning(disable : 4307) #endif - std::uint32_t h = 0x811c9dc5; + std::uint32_t h = 0x811c9dc5; - while (begin != end) { - h = (h ^ (*begin)) * 0x01000193; - ++begin; - } - return h; + while (begin != end) { + h = (h ^ (*begin)) * 0x01000193; + ++begin; + } + return h; #ifdef CHAISCRIPT_MSVC #pragma warning(pop) @@ -43,14 +39,12 @@ namespace chaiscript #ifdef __GNUC__ #pragma GCC diagnostic pop #endif - - } - + } template - static constexpr std::uint32_t hash(const char (&str)[N]) noexcept { - return hash(std::begin(str), std::end(str)-1); - } + static constexpr std::uint32_t hash(const char (&str)[N]) noexcept { + return hash(std::begin(str), std::end(str) - 1); + } static constexpr std::uint32_t hash(std::string_view sv) noexcept { return hash(sv.begin(), sv.end()); @@ -59,30 +53,30 @@ namespace chaiscript static inline std::uint32_t hash(const std::string &s) noexcept { return hash(s.begin(), s.end()); } - } + } // namespace fnv1a namespace jenkins_one_at_a_time { template - static constexpr std::uint32_t hash(Itr begin, Itr end) noexcept { - std::uint32_t hash = 0; + static constexpr std::uint32_t hash(Itr begin, Itr end) noexcept { + std::uint32_t hash = 0; - while (begin != end) { - hash += std::uint32_t(*begin); - hash += hash << 10; - hash ^= hash >> 6; - ++begin; - } - - hash += hash << 3; - hash ^= hash >> 11; - hash += hash << 15; - return hash; + while (begin != end) { + hash += std::uint32_t(*begin); + hash += hash << 10; + hash ^= hash >> 6; + ++begin; } + hash += hash << 3; + hash ^= hash >> 11; + hash += hash << 15; + return hash; + } + template - static constexpr std::uint32_t hash(const char (&str)[N]) noexcept { - return hash(std::begin(str), std::end(str)-1); - } + static constexpr std::uint32_t hash(const char (&str)[N]) noexcept { + return hash(std::begin(str), std::end(str) - 1); + } static constexpr std::uint32_t hash(std::string_view sv) noexcept { return hash(sv.begin(), sv.end()); @@ -91,11 +85,10 @@ namespace chaiscript static inline std::uint32_t hash(const std::string &s) noexcept { return hash(s.begin(), s.end()); } - } + } // namespace jenkins_one_at_a_time using fnv1a::hash; - } - -} + } // namespace utility +} // namespace chaiscript #endif diff --git a/include/chaiscript/utility/json.hpp b/include/chaiscript/utility/json.hpp index 4943bcb4..6bc57613 100644 --- a/include/chaiscript/utility/json.hpp +++ b/include/chaiscript/utility/json.hpp @@ -1,41 +1,33 @@ -// From github.com/nbsdx/SimpleJSON. +// From github.com/nbsdx/SimpleJSON. // Released under the DWTFYW PL // - - #ifndef SIMPLEJSON_HPP #define SIMPLEJSON_HPP - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include "../chaiscript_defines.hpp" #include "quick_flat_map.hpp" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include 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; -using std::initializer_list; -using std::is_same; -using std::is_convertible; -using std::is_integral; -using std::is_floating_point; - - - - -class JSON -{ + class JSON { public: enum class Class { Null = 0, @@ -48,26 +40,40 @@ class JSON }; private: + using Data + = std::variant, std::vector, std::string, double, std::int64_t, bool>; - - using Data = std::variant, std::vector, std::string, double, std::int64_t, bool>; - - struct Internal - { - Internal(std::nullptr_t) : d(nullptr) { } - Internal() : d(nullptr) { } - Internal(Class c) : d(make_type(c)) { } - template Internal(T t) : d(std::move(t)) { } + struct Internal { + Internal(std::nullptr_t) + : d(nullptr) { + } + Internal() + : d(nullptr) { + } + Internal(Class c) + : d(make_type(c)) { + } + template + Internal(T t) + : d(std::move(t)) { + } static Data make_type(Class c) { switch (c) { - case Class::Null: return nullptr; - case Class::Object: return chaiscript::utility::QuickFlatMap{}; - case Class::Array: return std::vector{}; - case Class::String: return std::string{}; - case Class::Floating: return double{}; - case Class::Integral: return std::int64_t{}; - case Class::Boolean: return bool{}; + case Class::Null: + return nullptr; + case Class::Object: + return chaiscript::utility::QuickFlatMap{}; + case Class::Array: + return std::vector{}; + 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"); } @@ -78,14 +84,10 @@ class JSON } } - Class type() const noexcept { - return Class(d.index()); - } - + Class type() const noexcept { return Class(d.index()); } template - decltype(auto) visit_or(Visitor &&visitor, Or &&other) const - { + decltype(auto) visit_or(Visitor &&visitor, Or &&other) const { if (type() == Class(ClassValue)) { return visitor(std::get(ClassValue)>(d)); } else { @@ -99,164 +101,132 @@ class JSON return (std::get(ClassValue)>(d)); } - auto &Map() { - return get_set_type(); - } - auto &Vector() { - return get_set_type(); - } - auto &String() { - return get_set_type(); - } - auto &Int() { - return get_set_type(); - } - auto &Float() { - return get_set_type(); - } - auto &Bool() { - return get_set_type(); - } + auto &Map() { return get_set_type(); } + auto &Vector() { return get_set_type(); } + auto &String() { return get_set_type(); } + auto &Int() { return get_set_type(); } + auto &Float() { return get_set_type(); } + auto &Bool() { return get_set_type(); } - auto Map() const noexcept { - return std::get_if(Class::Object)>(&d); - } - auto Vector() const noexcept { - return std::get_if(Class::Array)>(&d); - } - auto String() const noexcept { - return std::get_if(Class::String)>(&d); - } - auto Int() const noexcept { - return std::get_if(Class::Integral)>(&d); - } - auto Float() const noexcept { - return std::get_if(Class::Floating)>(&d); - } - auto Bool() const noexcept { - return std::get_if(Class::Boolean)>(&d); - } + auto Map() const noexcept { return std::get_if(Class::Object)>(&d); } + auto Vector() const noexcept { return std::get_if(Class::Array)>(&d); } + auto String() const noexcept { return std::get_if(Class::String)>(&d); } + auto Int() const noexcept { return std::get_if(Class::Integral)>(&d); } + auto Float() const noexcept { return std::get_if(Class::Floating)>(&d); } + auto Bool() const noexcept { return std::get_if(Class::Boolean)>(&d); } Data d; }; - Internal internal; public: + template + class JSONWrapper { + Container *object = nullptr; - template - class JSONWrapper { - Container *object = nullptr; + public: + JSONWrapper(Container *val) + : object(val) { + } + JSONWrapper(std::nullptr_t) {} - public: - JSONWrapper( Container *val ) : object( val ) {} - JSONWrapper( std::nullptr_t ) {} + typename Container::iterator begin() { return object ? object->begin() : typename Container::iterator(); } + typename Container::iterator end() { return object ? object->end() : typename Container::iterator(); } + typename Container::const_iterator begin() const { return object ? object->begin() : typename Container::iterator(); } + typename Container::const_iterator end() const { return object ? object->end() : 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::const_iterator begin() const { return object ? object->begin() : typename Container::iterator(); } - typename Container::const_iterator end() const { return object ? object->end() : typename Container::iterator(); } - }; + template + class JSONConstWrapper { + const Container *object = nullptr; - template - class JSONConstWrapper { - const Container *object = nullptr; + public: + JSONConstWrapper(const Container *val) + : object(val) { + } + JSONConstWrapper(std::nullptr_t) {} - public: - JSONConstWrapper( const Container *val ) : 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 end() const noexcept { return object ? object->end() : typename Container::const_iterator(); } - }; + typename Container::const_iterator begin() const noexcept { + return object ? object->begin() : typename Container::const_iterator(); + } + typename Container::const_iterator end() const noexcept { return object ? object->end() : typename Container::const_iterator(); } + }; JSON() = default; - JSON( std::nullptr_t ) {} + JSON(std::nullptr_t) {} explicit JSON(Class type) - : internal(type) - { + : internal(type) { } - JSON( initializer_list list ) - : internal(Class::Object) - { - for( auto i = list.begin(), e = list.end(); i != e; ++i, ++i ) { - operator[]( i->to_string() ) = *std::next( i ); + JSON(initializer_list list) + : internal(Class::Object) { + for (auto i = list.begin(), e = list.end(); i != e; ++i, ++i) { + operator[](i->to_string()) = *std::next(i); } } - template - explicit JSON( T b, typename enable_if::value>::type* = nullptr ) noexcept : internal( static_cast(b) ) {} - - template - explicit JSON( T i, typename enable_if::value && !is_same::value>::type* = nullptr ) noexcept : internal( static_cast(i) ) {} - - template - explicit JSON( T f, typename enable_if::value>::type* = nullptr ) noexcept : internal( static_cast(f) ) {} - - template - explicit JSON( T s, typename enable_if::value>::type* = nullptr ) : internal( static_cast(s) ) {} - - - - static JSON Load( const std::string & ); - - JSON& operator[]( const std::string &key ) { - return internal.Map().operator[]( key ); + template + explicit JSON(T b, typename enable_if::value>::type * = nullptr) noexcept + : internal(static_cast(b)) { } - JSON& operator[]( const size_t index ) { + template + explicit JSON(T i, typename enable_if::value && !is_same::value>::type * = nullptr) noexcept + : internal(static_cast(i)) { + } + + template + explicit JSON(T f, typename enable_if::value>::type * = nullptr) noexcept + : internal(static_cast(f)) { + } + + template + explicit JSON(T s, typename enable_if::value>::type * = nullptr) + : internal(static_cast(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(); - if( index >= vec.size() ) { - vec.resize( index + 1 ); + if (index >= vec.size()) { + 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 ) { - return operator[]( key ); + const JSON &at(const std::string &key) const { + return internal.visit_or([&](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 { - return internal.visit_or( - [&](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) { return operator[](index); } - JSON &at( size_t index ) { - return operator[]( index ); - } - - const JSON &at( size_t index ) const { - return internal.visit_or( - [&](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([&](const auto &m) -> const JSON & { return m.at(index); }, + []() -> const JSON & { throw std::range_error("Not an array, no indexes"); }); } auto length() const noexcept { - return internal.visit_or( - [&](const auto &m){ return static_cast(m.size()); }, - [](){ return -1; } - ); + return internal.visit_or([&](const auto &m) { return static_cast(m.size()); }, []() { return -1; }); } - bool has_key( const std::string &key ) const noexcept { - return internal.visit_or( - [&](const auto &m){ return m.count(key) != 0; }, - [](){ return false; } - ); + bool has_key(const std::string &key) const noexcept { + return internal.visit_or([&](const auto &m) { return m.count(key) != 0; }, []() { return false; }); } int size() const noexcept { if (auto m = internal.Map(); m != nullptr) { return static_cast(m->size()); - } if (auto v = internal.Vector(); v != nullptr) { + } + if (auto v = internal.Vector(); v != nullptr) { return static_cast(v->size()); } else { return -1; @@ -268,337 +238,361 @@ class JSON /// Functions for getting primitives from the JSON object. bool is_null() const noexcept { return internal.type() == Class::Null; } - std::string to_string() const noexcept { - return internal.visit_or( - [](const auto &o){ return o; }, - [](){ return std::string{}; } - ); + std::string to_string() const noexcept { + return internal.visit_or([](const auto &o) { return o; }, []() { return std::string{}; }); } - double to_float() const noexcept { - return internal.visit_or( - [](const auto &o){ return o; }, - [](){ return double{}; } - ); + double to_float() const noexcept { + return internal.visit_or([](const auto &o) { return o; }, []() { return double{}; }); } - std::int64_t to_int() const noexcept { - return internal.visit_or( - [](const auto &o){ return o; }, - [](){ return std::int64_t{}; } - ); + std::int64_t to_int() const noexcept { + return internal.visit_or([](const auto &o) { return o; }, []() { return std::int64_t{}; }); } - bool to_bool() const noexcept { - return internal.visit_or( - [](const auto &o){ return o; }, - [](){ return false; } - ); + bool to_bool() const noexcept { + return internal.visit_or([](const auto &o) { return o; }, []() { return false; }); } JSONWrapper> object_range() { return std::get_if(Class::Object)>(&internal.d); } - JSONWrapper> array_range() { - return std::get_if(Class::Array)>(&internal.d); - } + JSONWrapper> array_range() { return std::get_if(Class::Array)>(&internal.d); } JSONConstWrapper> object_range() const { return std::get_if(Class::Object)>(&internal.d); } - JSONConstWrapper> array_range() const { - return std::get_if(Class::Array)>(&internal.d); - } + JSONConstWrapper> array_range() const { return std::get_if(Class::Array)>(&internal.d); } - std::string dump( long depth = 1, std::string tab = " ") const { - switch( internal.type() ) { + std::string dump(long depth = 1, std::string tab = " ") const { + switch (internal.type()) { case Class::Null: return "null"; case Class::Object: { - std::string pad = ""; - for( long i = 0; i < depth; ++i, pad += tab ) { } + std::string pad = ""; + for (long i = 0; i < depth; ++i, pad += tab) { + } - std::string s = "{\n"; - bool skip = true; - for( auto &p : *internal.Map() ) { - if( !skip ) { s += ",\n"; } - s += ( pad + "\"" + json_escape(p.first) + "\" : " + p.second.dump( depth + 1, tab ) ); - skip = false; - } - s += ( "\n" + pad.erase( 0, 2 ) + "}" ) ; - return s; - } + std::string s = "{\n"; + bool skip = true; + for (auto &p : *internal.Map()) { + if (!skip) { + s += ",\n"; + } + s += (pad + "\"" + json_escape(p.first) + "\" : " + p.second.dump(depth + 1, tab)); + skip = false; + } + s += ("\n" + pad.erase(0, 2) + "}"); + return s; + } case Class::Array: { - std::string s = "["; - bool skip = true; - for( auto &p : *internal.Vector() ) { - if( !skip ) { s += ", "; } - s += p.dump( depth + 1, tab ); - skip = false; - } - s += "]"; - return s; - } + std::string s = "["; + bool skip = true; + for (auto &p : *internal.Vector()) { + if (!skip) { + s += ", "; + } + s += p.dump(depth + 1, tab); + skip = false; + } + s += "]"; + return s; + } case Class::String: - return "\"" + json_escape( *internal.String() ) + "\""; + return "\"" + json_escape(*internal.String()) + "\""; case Class::Floating: - return std::to_string( *internal.Float() ); + return std::to_string(*internal.Float()); case Class::Integral: - return std::to_string( *internal.Int() ); + return std::to_string(*internal.Int()); case Class::Boolean: - return *internal.Bool() ? "true" : "false"; + return *internal.Bool() ? "true" : "false"; } throw std::runtime_error("Unhandled JSON type"); } - private: - static std::string json_escape( const std::string &str ) { + static std::string json_escape(const std::string &str) { std::string output; - for(char i : str) { - switch( i ) { - case '\"': output += "\\\""; break; - case '\\': output += "\\\\"; break; - case '\b': 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; + for (char i : str) { + switch (i) { + case '\"': + output += "\\\""; + break; + case '\\': + output += "\\\\"; + break; + case '\b': + 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; } - private: -}; + }; - -struct JSONParser { - static bool isspace(const char c) noexcept - { + struct JSONParser { + static bool isspace(const char c) noexcept { #ifdef CHAISCRIPT_MSVC - // MSVC warns on these line in some circumstances +// MSVC warns on these line in some circumstances #pragma warning(push) #pragma warning(disable : 6330) #endif - return ::isspace(c) != 0; + return ::isspace(c) != 0; #ifdef CHAISCRIPT_MSVC #pragma warning(pop) #endif - - - } - - static void consume_ws( const std::string &str, size_t &offset ) { - while( isspace( str.at(offset) ) && offset <= str.size() ) { ++offset; } - } - - static JSON parse_object( const std::string &str, size_t &offset ) { - JSON Object( JSON::Class::Object ); - - ++offset; - consume_ws( str, offset ); - if( str.at(offset) == '}' ) { - ++offset; return Object; } - for (;offset= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F') ) { - val += c; - } else { - throw std::runtime_error(std::string("JSON ERROR: String: Expected hex character in unicode escape, found '") + c + "'"); - } - } - offset += 4; - } break; - default : val += '\\'; break; - } - } else { - val += c; - } - } - ++offset; - return JSON(val); - } - - static JSON parse_number( const std::string &str, size_t &offset ) { - std::string val, exp_str; - char c = '\0'; - bool isDouble = false; - bool isNegative = false; - std::int64_t exp = 0; - bool isExpNegative = false; - if( offset < str.size() && str.at(offset) == '-' ) { - isNegative = true; ++offset; - } - for (; offset < str.size() ;) { - c = str.at(offset++); - if( c >= '0' && c <= '9' ) { - val += c; - } else if( c == '.' && !isDouble ) { - val += c; - isDouble = true; - } else { - break; - } - } - if( offset < str.size() && (c == 'E' || c == 'e' )) { - c = str.at(offset++); - if( c == '-' ) { - isExpNegative = true; - } else if( c == '+' ) { - // do nothing - } else { - --offset; + consume_ws(str, offset); + if (str.at(offset) == '}') { + ++offset; + return Object; } - for (; offset < str.size() ;) { - c = str.at(offset++); - if( c >= '0' && c <= '9' ) { - exp_str += c; - } else if( !isspace( c ) && c != ',' && c != ']' && c != '}' ) { - throw std::runtime_error(std::string("JSON ERROR: Number: Expected a number for exponent, found '") + c + "'"); + for (; offset < str.size();) { + JSON Key = parse_next(str, offset); + consume_ws(str, offset); + if (str.at(offset) != ':') { + throw std::runtime_error(std::string("JSON ERROR: Object: Expected colon, found '") + str.at(offset) + "'\n"); } - else { + consume_ws(str, ++offset); + JSON Value = parse_next(str, offset); + Object[Key.to_string()] = Value; + + consume_ws(str, offset); + if (str.at(offset) == ',') { + ++offset; + continue; + } else if (str.at(offset) == '}') { + ++offset; + break; + } else { + throw std::runtime_error(std::string("JSON ERROR: Object: Expected comma, found '") + str.at(offset) + "'\n"); + } + } + + return Object; + } + + static JSON parse_array(const std::string &str, size_t &offset) { + JSON Array(JSON::Class::Array); + size_t index = 0; + + ++offset; + consume_ws(str, offset); + if (str.at(offset) == ']') { + ++offset; + return Array; + } + + for (; offset < str.size();) { + Array[index++] = parse_next(str, offset); + consume_ws(str, offset); + + if (str.at(offset) == ',') { + ++offset; + continue; + } else if (str.at(offset) == ']') { + ++offset; + break; + } else { + throw std::runtime_error(std::string("JSON ERROR: Array: Expected ',' or ']', found '") + str.at(offset) + "'\n"); + } + } + + return Array; + } + + static JSON parse_string(const std::string &str, size_t &offset) { + std::string val; + for (char c = str.at(++offset); c != '\"'; c = str.at(++offset)) { + if (c == '\\') { + switch (str.at(++offset)) { + case '\"': + val += '\"'; + break; + case '\\': + val += '\\'; + break; + case '/': + val += '/'; + break; + case 'b': + val += '\b'; + break; + 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; + } else { + throw std::runtime_error( + std::string("JSON ERROR: String: Expected hex character in unicode escape, found '") + c + "'"); + } + } + offset += 4; + } break; + default: + val += '\\'; + break; + } + } else { + val += c; + } + } + ++offset; + return JSON(val); + } + + static JSON parse_number(const std::string &str, size_t &offset) { + std::string val, exp_str; + char c = '\0'; + bool isDouble = false; + bool isNegative = false; + std::int64_t exp = 0; + bool isExpNegative = false; + if (offset < str.size() && str.at(offset) == '-') { + isNegative = true; + ++offset; + } + for (; offset < str.size();) { + c = str.at(offset++); + if (c >= '0' && c <= '9') { + val += c; + } else if (c == '.' && !isDouble) { + val += c; + isDouble = true; + } else { break; } } - exp = chaiscript::parse_num( exp_str ) * (isExpNegative?-1:1); - } - else if( offset < str.size() && (!isspace( c ) && c != ',' && c != ']' && c != '}' )) { - throw std::runtime_error(std::string("JSON ERROR: Number: unexpected character '") + c + "'"); - } - --offset; + if (offset < str.size() && (c == 'E' || c == 'e')) { + c = str.at(offset++); + if (c == '-') { + isExpNegative = true; + } else if (c == '+') { + // do nothing + } else { + --offset; + } - if( isDouble ) { - return JSON((isNegative?-1:1) * chaiscript::parse_num( val ) * std::pow( 10, exp )); - } else { - if( !exp_str.empty() ) { - return JSON((isNegative?-1:1) * static_cast(chaiscript::parse_num( val )) * std::pow( 10, exp )); + for (; offset < str.size();) { + c = str.at(offset++); + if (c >= '0' && c <= '9') { + exp_str += c; + } else if (!isspace(c) && c != ',' && c != ']' && c != '}') { + throw std::runtime_error(std::string("JSON ERROR: Number: Expected a number for exponent, found '") + c + "'"); + } else { + break; + } + } + exp = chaiscript::parse_num(exp_str) * (isExpNegative ? -1 : 1); + } else if (offset < str.size() && (!isspace(c) && c != ',' && c != ']' && c != '}')) { + throw std::runtime_error(std::string("JSON ERROR: Number: unexpected character '") + c + "'"); + } + --offset; + + if (isDouble) { + return JSON((isNegative ? -1 : 1) * chaiscript::parse_num(val) * std::pow(10, exp)); } else { - return JSON((isNegative?-1:1) * chaiscript::parse_num( val )); + if (!exp_str.empty()) { + return JSON((isNegative ? -1 : 1) * static_cast(chaiscript::parse_num(val)) * std::pow(10, exp)); + } else { + return JSON((isNegative ? -1 : 1) * chaiscript::parse_num(val)); + } } } - } - static JSON parse_bool( const std::string &str, size_t &offset ) { - if( str.substr( offset, 4 ) == "true" ) { + static JSON parse_bool(const std::string &str, size_t &offset) { + if (str.substr(offset, 4) == "true") { + offset += 4; + return JSON(true); + } else if (str.substr(offset, 5) == "false") { + offset += 5; + return JSON(false); + } else { + 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) { + if (str.substr(offset, 4) != "null") { + throw std::runtime_error(std::string("JSON ERROR: Null: Expected 'null', found '") + str.substr(offset, 4) + "'"); + } offset += 4; - return JSON(true); - } else if( str.substr( offset, 5 ) == "false" ) { - offset += 5; - return JSON(false); - } else { - throw std::runtime_error(std::string("JSON ERROR: Bool: Expected 'true' or 'false', found '") + str.substr( offset, 5 ) + "'"); + return JSON(); } - } - static JSON parse_null( const std::string &str, size_t &offset ) { - if( str.substr( offset, 4 ) != "null" ) { - throw std::runtime_error(std::string("JSON ERROR: Null: Expected 'null', found '") + str.substr( offset, 4 ) + "'"); + static JSON parse_next(const std::string &str, size_t &offset) { + char value; + consume_ws(str, offset); + value = str.at(offset); + switch (value) { + case '[': + return parse_array(str, offset); + case '{': + return parse_object(str, offset); + case '\"': + return parse_string(str, offset); + case 't': + 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 + "'"); } - offset += 4; - return JSON(); + }; + + inline JSON JSON::Load(const std::string &str) { + size_t offset = 0; + return JSONParser::parse_next(str, offset); } - static JSON parse_next( const std::string &str, size_t &offset ) { - char value; - consume_ws( str, offset ); - value = str.at(offset); - switch( value ) { - case '[' : return parse_array( str, offset ); - case '{' : return parse_object( str, offset ); - case '\"': return parse_string( str, offset ); - case 't' : - 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 + "'"); - } - -}; - -inline JSON JSON::Load( const std::string &str ) { - size_t offset = 0; - return JSONParser::parse_next( str, offset ); -} - } // End Namespace json - -#endif +#endif diff --git a/include/chaiscript/utility/json_wrap.hpp b/include/chaiscript/utility/json_wrap.hpp index 656bf21d..d478f407 100644 --- a/include/chaiscript/utility/json_wrap.hpp +++ b/include/chaiscript/utility/json_wrap.hpp @@ -3,154 +3,129 @@ #include "json.hpp" -namespace chaiscript -{ - class json_wrap - { - public: +namespace chaiscript { + class json_wrap { + public: + 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(&json_wrap::to_json), "to_json"); - static Module& library(Module& m) - { + return m; + } - 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"); + private: + static Boxed_Value from_json(const json::JSON &t_json) { + switch (t_json.JSONType()) { + case json::JSON::Class::Null: + return Boxed_Value(); + case json::JSON::Class::Object: { + std::map m; - return m; - - } - - private: - - static Boxed_Value from_json(const json::JSON &t_json) - { - switch( t_json.JSONType() ) { - case json::JSON::Class::Null: - return Boxed_Value(); - case json::JSON::Class::Object: - { - std::map m; - - for (const auto &p : t_json.object_range()) - { - m.insert(std::make_pair(p.first, from_json(p.second))); - } - - return Boxed_Value(m); - } - case json::JSON::Class::Array: - { - std::vector vec; - - for (const auto &p : t_json.array_range()) - { - vec.emplace_back(from_json(p)); - } - - return Boxed_Value(vec); - } - case json::JSON::Class::String: - return Boxed_Value(t_json.to_string()); - case json::JSON::Class::Floating: - return Boxed_Value(t_json.to_float()); - case json::JSON::Class::Integral: - return Boxed_Value(t_json.to_int()); - case json::JSON::Class::Boolean: - return Boxed_Value(t_json.to_bool()); - } - - throw std::runtime_error("Unknown JSON type"); - } - - static Boxed_Value from_json(const std::string &t_json) - { - try { - return from_json( json::JSON::Load(t_json) ); - } catch (const std::out_of_range& ) { - throw std::runtime_error("Unparsed JSON input"); - } - } - - static std::string to_json(const Boxed_Value &t_bv) - { - return to_json_object(t_bv).dump(); - } - - static json::JSON to_json_object(const Boxed_Value &t_bv) - { - try { - const std::map m = chaiscript::boxed_cast &>(t_bv); - - json::JSON obj(json::JSON::Class::Object); - for (const auto &o : m) - { - obj[o.first] = to_json_object(o.second); + for (const auto &p : t_json.object_range()) { + m.insert(std::make_pair(p.first, from_json(p.second))); } - return obj; - } catch (const chaiscript::exception::bad_boxed_cast &) { - // not a map + + return Boxed_Value(m); } + case json::JSON::Class::Array: { + std::vector vec; - try { - const std::vector v = chaiscript::boxed_cast &>(t_bv); - - json::JSON obj(json::JSON::Class::Array); - for (size_t i = 0; i < v.size(); ++i) - { - obj[i] = to_json_object(v[i]); + for (const auto &p : t_json.array_range()) { + vec.emplace_back(from_json(p)); } - return obj; - } catch (const chaiscript::exception::bad_boxed_cast &) { - // not a vector + + return Boxed_Value(vec); } - - - try { - Boxed_Number bn(t_bv); - if (Boxed_Number::is_floating_point(t_bv)) - { - return json::JSON(bn.get_as()); - } else { - return json::JSON(bn.get_as()); - } - } catch (const chaiscript::detail::exception::bad_any_cast &) { - // not a number - } - - try { - return json::JSON(boxed_cast(t_bv)); - } catch (const chaiscript::exception::bad_boxed_cast &) { - // not a bool - } - - try { - return json::JSON(boxed_cast(t_bv)); - } catch (const chaiscript::exception::bad_boxed_cast &) { - // not a string - } - - - try { - const chaiscript::dispatch::Dynamic_Object &o = boxed_cast(t_bv); - - json::JSON obj(json::JSON::Class::Object); - for (const auto &attr : o.get_attrs()) - { - obj[attr.first] = to_json_object(attr.second); - } - return obj; - } catch (const chaiscript::exception::bad_boxed_cast &) { - // not a dynamic object - } - - if (t_bv.is_null()) return json::JSON(); // a null value - - throw std::runtime_error("Unknown object type to convert to JSON"); + case json::JSON::Class::String: + return Boxed_Value(t_json.to_string()); + case json::JSON::Class::Floating: + return Boxed_Value(t_json.to_float()); + case json::JSON::Class::Integral: + return Boxed_Value(t_json.to_int()); + case json::JSON::Class::Boolean: + return Boxed_Value(t_json.to_bool()); } + throw std::runtime_error("Unknown JSON type"); + } + static Boxed_Value from_json(const std::string &t_json) { + try { + return from_json(json::JSON::Load(t_json)); + } catch (const std::out_of_range &) { + throw std::runtime_error("Unparsed JSON input"); + } + } + + static std::string to_json(const Boxed_Value &t_bv) { return to_json_object(t_bv).dump(); } + + static json::JSON to_json_object(const Boxed_Value &t_bv) { + try { + const std::map m = chaiscript::boxed_cast &>(t_bv); + + json::JSON obj(json::JSON::Class::Object); + for (const auto &o : m) { + obj[o.first] = to_json_object(o.second); + } + return obj; + } catch (const chaiscript::exception::bad_boxed_cast &) { + // not a map + } + + try { + const std::vector v = chaiscript::boxed_cast &>(t_bv); + + json::JSON obj(json::JSON::Class::Array); + for (size_t i = 0; i < v.size(); ++i) { + obj[i] = to_json_object(v[i]); + } + return obj; + } catch (const chaiscript::exception::bad_boxed_cast &) { + // not a vector + } + + try { + Boxed_Number bn(t_bv); + if (Boxed_Number::is_floating_point(t_bv)) { + return json::JSON(bn.get_as()); + } else { + return json::JSON(bn.get_as()); + } + } catch (const chaiscript::detail::exception::bad_any_cast &) { + // not a number + } + + try { + return json::JSON(boxed_cast(t_bv)); + } catch (const chaiscript::exception::bad_boxed_cast &) { + // not a bool + } + + try { + return json::JSON(boxed_cast(t_bv)); + } catch (const chaiscript::exception::bad_boxed_cast &) { + // not a string + } + + try { + const chaiscript::dispatch::Dynamic_Object &o = boxed_cast(t_bv); + + json::JSON obj(json::JSON::Class::Object); + for (const auto &attr : o.get_attrs()) { + obj[attr.first] = to_json_object(attr.second); + } + return obj; + } catch (const chaiscript::exception::bad_boxed_cast &) { + // not a dynamic object + } + + if (t_bv.is_null()) + return json::JSON(); // a null value + + throw std::runtime_error("Unknown object type to convert to JSON"); + } }; - -} +} // namespace chaiscript #endif diff --git a/include/chaiscript/utility/quick_flat_map.hpp b/include/chaiscript/utility/quick_flat_map.hpp index 35bc089d..bf189a8f 100644 --- a/include/chaiscript/utility/quick_flat_map.hpp +++ b/include/chaiscript/utility/quick_flat_map.hpp @@ -2,10 +2,8 @@ #define CHAISCRIPT_UTILITY_QUICK_FLAT_MAP_HPP namespace chaiscript::utility { - - template> - struct QuickFlatMap - { + template> + struct QuickFlatMap { Comparator comparator; template @@ -28,35 +26,19 @@ namespace chaiscript::utility { } } - auto size() const noexcept { - return data.size(); - } + auto size() const noexcept { return data.size(); } - auto begin() const noexcept { - return data.begin(); - } + auto begin() const noexcept { return data.begin(); } - auto end() const noexcept { - return data.end(); - } + auto end() const noexcept { return data.end(); } + auto begin() noexcept { return data.begin(); } - auto begin() noexcept { - return data.begin(); - } + auto end() noexcept { return data.end(); } - auto end() noexcept { - return data.end(); - } - - auto &back() noexcept { - return data.back(); - } - - const auto &back() const noexcept { - return data.back(); - } + auto &back() noexcept { return data.back(); } + const auto &back() const noexcept { return data.back(); } Value &operator[](const Key &s) { const auto itr = find(s); @@ -68,24 +50,14 @@ namespace chaiscript::utility { } } - Value &at_index(const std::size_t idx) noexcept - { - return data[idx].second; - } + Value &at_index(const std::size_t idx) noexcept { return data[idx].second; } - const Value &at_index(const std::size_t idx) const noexcept - { - return data[idx].second; - } + const Value &at_index(const std::size_t idx) const noexcept { return data[idx].second; } - bool empty() const noexcept - { - return data.empty(); - } + bool empty() const noexcept { return data.empty(); } template - void assign(Itr begin, Itr end) - { + void assign(Itr begin, Itr end) { data.assign(begin, end); } @@ -98,10 +70,8 @@ namespace chaiscript::utility { } } - template - auto insert_or_assign(Key &&key, M &&m) - { + auto insert_or_assign(Key &&key, M &&m) { if (auto itr = find(key); itr != data.end()) { *itr = std::forward(m); return std::pair{itr, false}; @@ -111,10 +81,8 @@ namespace chaiscript::utility { } } - template - 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()) { itr->second = std::forward(m); return std::pair{itr, false}; @@ -135,7 +103,7 @@ namespace chaiscript::utility { template size_t count(const Lookup &s) const noexcept { - return (find(s) != data.end())?1:0; + return (find(s) != data.end()) ? 1 : 0; } std::vector> data; @@ -144,8 +112,7 @@ namespace chaiscript::utility { using iterator = typename decltype(data)::iterator; using const_iterator = typename decltype(data)::const_iterator; - std::pair insert( value_type&& value ) - { + std::pair insert(value_type &&value) { if (const auto itr = find(value.first); itr != data.end()) { return std::pair{itr, false}; } else { @@ -159,11 +126,8 @@ namespace chaiscript::utility { data.reserve(data.size() + 2); } } - - }; -} +} // namespace chaiscript::utility #endif - diff --git a/include/chaiscript/utility/stack_vector.hpp b/include/chaiscript/utility/stack_vector.hpp index c72bfe6c..3b1e11ab 100644 --- a/include/chaiscript/utility/stack_vector.hpp +++ b/include/chaiscript/utility/stack_vector.hpp @@ -7,47 +7,36 @@ // This is an open source non-commercial project. Dear PVS-Studio, please check it. // PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com - #ifndef CHAISCRIPT_STACK_VECTOR_HPP_ #define CHAISCRIPT_STACK_VECTOR_HPP_ #include -#include #include - - +#include template -struct Stack_Vector -{ +struct Stack_Vector { constexpr static auto aligned_size = sizeof(T) + (sizeof(T) & std::alignment_of_v) > 0 ? std::alignment_of_v : 0; alignas(std::alignment_of_v) char data[aligned_size * MaxSize]; - [[nodiscard]] T & operator[](const std::size_t idx) noexcept { - return *reinterpret_cast(&data + aligned_size * idx); + [[nodiscard]] T &operator[](const std::size_t idx) noexcept { return *reinterpret_cast(&data + aligned_size * idx); } + + [[nodiscard]] const T &operator[](const std::size_t idx) const noexcept { + return *reinterpret_cast(&data + aligned_size * idx); } - [[nodiscard]] const T & operator[](const std::size_t idx) const noexcept { - return *reinterpret_cast(&data + aligned_size * idx); - } - - template - T& emplace_back(Param && ... param) { - auto *p = new(&(*this)[m_size++]) T(std::forward(param)...); + template + T &emplace_back(Param &&...param) { + auto *p = new (&(*this)[m_size++]) T(std::forward(param)...); return *p; }; - auto size() const noexcept { - return m_size; - }; + auto size() const noexcept { return m_size; }; - void pop_back() noexcept(std::is_nothrow_destructible_v) { - (*this)[--m_size].~T(); - } + void pop_back() noexcept(std::is_nothrow_destructible_v) { (*this)[--m_size].~T(); } - ~Stack_Vector() noexcept(std::is_nothrow_destructible_v) - { + ~Stack_Vector() noexcept(std::is_nothrow_destructible_v) { auto loc = m_size - 1; for (std::size_t pos = 0; pos < m_size; ++pos) { (*this)[loc--].~T(); @@ -55,9 +44,6 @@ struct Stack_Vector } std::size_t m_size{0}; - }; #endif CHAISCRIPT_STACK_VECTOR_HPP_ - - diff --git a/include/chaiscript/utility/static_string.hpp b/include/chaiscript/utility/static_string.hpp index 6152288d..8613fd31 100644 --- a/include/chaiscript/utility/static_string.hpp +++ b/include/chaiscript/utility/static_string.hpp @@ -7,59 +7,48 @@ #ifndef CHAISCRIPT_UTILITY_STATIC_STRING_HPP_ #define CHAISCRIPT_UTILITY_STATIC_STRING_HPP_ -namespace chaiscript -{ - namespace utility - { +namespace chaiscript::utility { + struct Static_String { + template + constexpr Static_String(const char (&str)[N]) noexcept + : m_size(N - 1) + , data(&str[0]) { + } - struct Static_String - { - template - constexpr Static_String(const char (&str)[N]) noexcept - : m_size(N-1), data(&str[0]) - { + constexpr size_t size() const noexcept { return m_size; } + + constexpr const char *c_str() const noexcept { return data; } + + constexpr auto begin() const noexcept { return data; } + + constexpr auto end() const noexcept { return data + m_size; } + + constexpr bool operator==(std::string_view other) const noexcept { + // return std::string_view(data, m_size) == other; + auto b1 = begin(); + const auto e1 = end(); + auto b2 = other.begin(); + const auto e2 = other.end(); + + if (e1 - b1 != e2 - b2) { + return false; + } + + while (b1 != e1) { + if (*b1 != *b2) { + return false; } - - constexpr size_t size() const noexcept { - return m_size; + ++b1; + ++b2; } + return true; + } - constexpr const char *c_str() const noexcept { - return data; - } + bool operator==(const std::string &t_str) const noexcept { return std::equal(begin(), end(), std::cbegin(t_str), std::cend(t_str)); } - constexpr auto begin() const noexcept { - return data; - } - - constexpr auto end() const noexcept { - return data + m_size; - } - - constexpr bool operator==(std::string_view other) const noexcept { - //return std::string_view(data, m_size) == other; - auto b1 = begin(); - const auto e1 = end(); - auto b2 = other.begin(); - const auto e2 = other.end(); - - if (e1 - b1 != e2 - b2) { return false; } - - while (b1 != e1) { - if (*b1 != *b2) { return false; } - ++b1; ++b2; - } - return true; - } - - bool operator==(const std::string &t_str) const noexcept { - return std::equal(begin(), end(), std::cbegin(t_str), std::cend(t_str)); - } - - const size_t m_size; - const char *data = nullptr; - }; - } -} + const size_t m_size; + const char *data = nullptr; + }; +} // namespace chaiscript::utility #endif diff --git a/include/chaiscript/utility/utility.hpp b/include/chaiscript/utility/utility.hpp index b57d4d01..22a1ff01 100644 --- a/include/chaiscript/utility/utility.hpp +++ b/include/chaiscript/utility/utility.hpp @@ -7,7 +7,6 @@ // This is an open source non-commercial project. Dear PVS-Studio, please check it. // PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com - #ifndef CHAISCRIPT_UTILITY_UTILITY_HPP_ #define CHAISCRIPT_UTILITY_UTILITY_HPP_ @@ -16,108 +15,90 @@ #include #include -#include "../language/chaiscript_common.hpp" -#include "../dispatchkit/register_function.hpp" #include "../dispatchkit/operators.hpp" +#include "../dispatchkit/register_function.hpp" +#include "../language/chaiscript_common.hpp" +namespace chaiscript::utility { + /// Single step command for registering a class with ChaiScript + /// + /// \param[in,out] t_module Model to add class to + /// \param[in] t_class_name Name of the class being registered + /// \param[in] t_constructors Vector of constructors to add + /// \param[in] t_funcs Vector of methods to add + /// + /// \example Adding a basic class to ChaiScript in one step + /// + /// \code + /// chaiscript::utility::add_class(*m, + /// "test", + /// { constructor(), + /// constructor() }, + /// { {fun(&test::function), "function"}, + /// {fun(&test::function2), "function2"}, + /// {fun(&test::function3), "function3"}, + /// {fun(static_cast(&test::function_overload)), "function_overload" }, + /// {fun(static_cast(&test::function_overload)), "function_overload" }, + /// {fun(static_cast(&test::operator=)), "=" } + /// } + /// ); + /// + template + void add_class(ModuleType &t_module, + const std::string &t_class_name, + const std::vector &t_constructors, + const std::vector> &t_funcs) { + t_module.add(chaiscript::user_type(), t_class_name); -namespace chaiscript -{ - namespace utility - { + for (const chaiscript::Proxy_Function &ctor : t_constructors) { + t_module.add(ctor, t_class_name); + } - /// Single step command for registering a class with ChaiScript - /// - /// \param[in,out] t_module Model to add class to - /// \param[in] t_class_name Name of the class being registered - /// \param[in] t_constructors Vector of constructors to add - /// \param[in] t_funcs Vector of methods to add - /// - /// \example Adding a basic class to ChaiScript in one step - /// - /// \code - /// chaiscript::utility::add_class(*m, - /// "test", - /// { constructor(), - /// constructor() }, - /// { {fun(&test::function), "function"}, - /// {fun(&test::function2), "function2"}, - /// {fun(&test::function3), "function3"}, - /// {fun(static_cast(&test::function_overload)), "function_overload" }, - /// {fun(static_cast(&test::function_overload)), "function_overload" }, - /// {fun(static_cast(&test::operator=)), "=" } - /// } - /// ); - /// - template - void add_class(ModuleType &t_module, - const std::string &t_class_name, - const std::vector &t_constructors, - const std::vector> &t_funcs) - { - t_module.add(chaiscript::user_type(), t_class_name); - - for(const chaiscript::Proxy_Function &ctor: t_constructors) - { - t_module.add(ctor, t_class_name); - } - - for(const auto &fun: t_funcs) - { - t_module.add(fun.first, fun.second); - } - } - - template - typename std::enable_if::value, void>::type - add_class(ModuleType &t_module, - const std::string &t_class_name, - const std::vector::type, std::string>> &t_constants - ) - { - t_module.add(chaiscript::user_type(), t_class_name); - - t_module.add(chaiscript::constructor(), t_class_name); - t_module.add(chaiscript::constructor(), t_class_name); - - using namespace chaiscript::bootstrap::operators; - equal(t_module); - not_equal(t_module); - assign(t_module); - - 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; }), "=="); - - for (const auto &constant : t_constants) - { - t_module.add_global_const(chaiscript::const_var(Enum(constant.first)), constant.second); - } - } - - template - typename std::enable_if::value, void>::type - add_class(ModuleType &t_module, - const std::string &t_class_name, - const std::vector> &t_constants - ) - { - t_module.add(chaiscript::user_type(), t_class_name); - - t_module.add(chaiscript::constructor(), t_class_name); - t_module.add(chaiscript::constructor(), t_class_name); - - using namespace chaiscript::bootstrap::operators; - equal(t_module); - not_equal(t_module); - assign(t_module); - - for (const auto &constant : t_constants) - { - t_module.add_global_const(chaiscript::const_var(EnumClass(constant.first)), constant.second); - } - } + for (const auto &fun : t_funcs) { + t_module.add(fun.first, fun.second); + } } -} + + template + typename std::enable_if::value, void>::type + add_class(ModuleType &t_module, + const std::string &t_class_name, + const std::vector::type, std::string>> &t_constants) { + t_module.add(chaiscript::user_type(), t_class_name); + + t_module.add(chaiscript::constructor(), t_class_name); + t_module.add(chaiscript::constructor(), t_class_name); + + using namespace chaiscript::bootstrap::operators; + equal(t_module); + not_equal(t_module); + assign(t_module); + + 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; }), "=="); + + for (const auto &constant : t_constants) { + t_module.add_global_const(chaiscript::const_var(Enum(constant.first)), constant.second); + } + } + + template + typename std::enable_if::value, void>::type + add_class(ModuleType &t_module, const std::string &t_class_name, const std::vector> &t_constants) { + t_module.add(chaiscript::user_type(), t_class_name); + + t_module.add(chaiscript::constructor(), t_class_name); + t_module.add(chaiscript::constructor(), t_class_name); + + using namespace chaiscript::bootstrap::operators; + equal(t_module); + not_equal(t_module); + assign(t_module); + + for (const auto &constant : t_constants) { + t_module.add_global_const(chaiscript::const_var(EnumClass(constant.first)), constant.second); + } + } +} // namespace chaiscript::utility #endif - diff --git a/performance_tests/profile_cpp_calls_2.cpp b/performance_tests/profile_cpp_calls_2.cpp index aa87fc03..3cf355b3 100644 --- a/performance_tests/profile_cpp_calls_2.cpp +++ b/performance_tests/profile_cpp_calls_2.cpp @@ -5,8 +5,7 @@ double f(const std::string &, double, bool) noexcept { return .0; } -int main() -{ +int main() { chaiscript::ChaiScript chai; chai.add(chaiscript::fun(&f), "f"); @@ -16,5 +15,4 @@ int main() f("str", 1.2, false); } )"); - } diff --git a/performance_tests/profile_fun_wrappers.cpp b/performance_tests/profile_fun_wrappers.cpp index 119f6929..f71aae3f 100644 --- a/performance_tests/profile_fun_wrappers.cpp +++ b/performance_tests/profile_fun_wrappers.cpp @@ -5,16 +5,14 @@ double f(const std::string &, double, bool) noexcept { return .0; } -int main() -{ +int main() { chaiscript::ChaiScript chai; chai.add(chaiscript::fun(&f), "f"); - const auto f = chai.eval>(R"(fun(){ f("str", 1.2, false); })"); + const auto f = chai.eval>(R"(fun(){ f("str", 1.2, false); })"); for (int i = 0; i < 100000; ++i) { f(); } - } diff --git a/samples/factory.cpp b/samples/factory.cpp index 976868b5..6ddb77b4 100644 --- a/samples/factory.cpp +++ b/samples/factory.cpp @@ -1,61 +1,53 @@ #include -class Entity -{ - public: - int width; - int height; - int x; - int y; - std::string name; +class Entity { +public: + int width; + int height; + int x; + int y; + std::string name; - std::function updater; + std::function updater; - 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)) - { - } + 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)) { + } }; -class Factory -{ - public: - // we may as well pass the parameters for the entity to the factory method, this does the initialization - // in one step. - 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}}); - return &(entity.first->second); - } +class Factory { +public: + // we may as well pass the parameters for the entity to the factory method, this does the initialization + // in one step. + 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}}); + return &(entity.first->second); + } - Entity *get_entity(const std::string &name) - { - return &entities.at(name); - } + Entity *get_entity(const std::string &name) { return &entities.at(name); } - - // loop over all entities and all their updater function (if it exists) - void update_entities() - { - for (auto &entity : entities) - { - if (entity.second.updater) { - entity.second.updater(entity.second); - } + // loop over all entities and all their updater function (if it exists) + void update_entities() { + for (auto &entity : entities) { + if (entity.second.updater) { + entity.second.updater(entity.second); } } + } - - private: - // 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. - // using a map guarantees that the memory assigned to the entity will never change, plus - // lets us easily look up an entity by name - std::map entities; +private: + // 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. + // using a map guarantees that the memory assigned to the entity will never change, plus + // lets us easily look up an entity by name + std::map entities; }; -int main() -{ +int main() { chaiscript::ChaiScript chai; 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::user_type(), "Factory"); // this isn't strictly necessary but makes error messages nicer - Factory 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 )""; - chai.eval(script); - - - } - - diff --git a/samples/fun_call_performance.cpp b/samples/fun_call_performance.cpp index e68ee0d6..da5417ce 100644 --- a/samples/fun_call_performance.cpp +++ b/samples/fun_call_performance.cpp @@ -7,7 +7,6 @@ // 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 - #include #include #include @@ -19,43 +18,38 @@ #include #ifdef READLINE_AVAILABLE -#include #include +#include #else char *mystrdup(const char *s) { size_t len = strlen(s); // Space for length plus nul - char *d = static_cast(malloc(len + 1)); - if (d == nullptr) return nullptr; // No memory + char *d = static_cast(malloc(len + 1)); + if (d == nullptr) + return nullptr; // No memory #ifdef CHAISCRIPT_MSVC - strcpy_s(d, len + 1, s); // Copy the characters + strcpy_s(d, len + 1, s); // Copy the characters #else - strncpy(d, s, len); // Copy the characters + strncpy(d, s, len); // Copy the characters #endif 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::cout << p; std::getline(std::cin, retval); return std::cin.eof() ? nullptr : mystrdup(retval.c_str()); } - -void add_history(const char*){} -void using_history(){} +void add_history(const char *) {} +void using_history() {} #endif - - -void *cast_module_symbol(std::vector(*t_path)()) -{ - union cast_union - { - std::vector(*in_ptr)(); +void *cast_module_symbol(std::vector (*t_path)()) { + union cast_union { + std::vector (*in_ptr)(); void *out_ptr; }; @@ -64,12 +58,11 @@ void *cast_module_symbol(std::vector(*t_path)()) return c.out_ptr; } -std::vector default_search_paths() -{ +std::vector default_search_paths() { std::vector paths; #ifndef CHAISCRIPT_NO_DYNLOAD -#ifdef CHAISCRIPT_WINDOWS // force no unicode +#ifdef CHAISCRIPT_WINDOWS // force no unicode CHAR path[4096]; int size = GetModuleFileNameA(0, path, sizeof(path) - 1); @@ -77,14 +70,12 @@ std::vector default_search_paths() size_t lastslash = exepath.rfind('\\'); size_t secondtolastslash = exepath.rfind('\\', lastslash - 1); - if (lastslash != std::string::npos) - { + if (lastslash != std::string::npos) { paths.push_back(exepath.substr(0, lastslash)); } - if (secondtolastslash != std::string::npos) - { - return{ exepath.substr(0, secondtolastslash) + "\\lib\\chaiscript\\" }; + if (secondtolastslash != std::string::npos) { + return {exepath.substr(0, secondtolastslash) + "\\lib\\chaiscript\\"}; } #else @@ -93,29 +84,23 @@ std::vector default_search_paths() std::vector buf(2048); 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)); } - if (exepath.empty()) - { - if ((size = readlink("/proc/curproc/file", &buf.front(), buf.size())) > 0) - { + if (exepath.empty()) { + if ((size = readlink("/proc/curproc/file", &buf.front(), buf.size())) > 0) { exepath = std::string(&buf.front(), static_cast(size)); } } - if (exepath.empty()) - { - if ((size = readlink("/proc/self/path/a.out", &buf.front(), buf.size())) > 0) - { + if (exepath.empty()) { + if ((size = readlink("/proc/self/path/a.out", &buf.front(), buf.size())) > 0) { exepath = std::string(&buf.front(), static_cast(size)); } } - if (exepath.empty()) - { + if (exepath.empty()) { Dl_info rInfo; memset(&rInfo, 0, sizeof(rInfo)); if (!dladdr(cast_module_symbol(&default_search_paths), &rInfo) || !rInfo.dli_fname) { @@ -128,13 +113,11 @@ std::vector default_search_paths() size_t lastslash = exepath.rfind('/'); size_t secondtolastslash = exepath.rfind('/', lastslash - 1); - if (lastslash != std::string::npos) - { + if (lastslash != std::string::npos) { 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/"); } #endif @@ -149,8 +132,7 @@ void help(int n) { std::cout << "Additionally, you can inspect the runtime system using:\n"; std::cout << " dump_system() - outputs all functions registered to the system\n"; std::cout << " dump_object(x) - dumps information about the given symbol\n"; - } - else { + } else { std::cout << "usage : chai [option]+\n"; std::cout << "option:\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 + "!"; } -bool throws_exception(const std::function &f) -{ +bool throws_exception(const std::function &f) { try { f(); - } - catch (...) { + } catch (...) { return true; } return false; } -chaiscript::exception::eval_error get_eval_error(const std::function &f) -{ +chaiscript::exception::eval_error get_eval_error(const std::function &f) { try { f(); - } - catch (const chaiscript::exception::eval_error &e) { + } catch (const chaiscript::exception::eval_error &e) { return e; } @@ -200,13 +177,11 @@ std::string get_next_command() { std::string val(input_raw); size_t pos = val.find_first_not_of("\t \n"); - if (pos != std::string::npos) - { + if (pos != std::string::npos) { val.erase(0, pos); } 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); } @@ -215,11 +190,7 @@ std::string get_next_command() { ::free(input_raw); } } - if (retval == "quit" - || retval == "exit" - || retval == "help" - || retval == "version") - { + if (retval == "quit" || retval == "exit" || retval == "help" || retval == "version") { retval += "(0)"; } return retval; @@ -231,8 +202,7 @@ void myexit(int return_val) { exit(return_val); } -void interactive(chaiscript::ChaiScript& chai) -{ +void interactive(chaiscript::ChaiScript &chai) { using_history(); for (;;) { @@ -241,32 +211,28 @@ void interactive(chaiscript::ChaiScript& chai) // evaluate 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())) { try { - std::cout << chai.eval >("to_string")(val) << '\n'; - } - catch (...) {} //If we can't, do nothing + std::cout << chai.eval>("to_string")(val) << '\n'; + } 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(); if (ee.call_stack.size() > 0) { std::cout << "during evaluation at (" << ee.call_stack[0].start().line << ", " << ee.call_stack[0].start().column << ")"; } std::cout << '\n'; - } - catch (const std::exception &e) { + } catch (const std::exception &e) { std::cout << e.what(); std::cout << std::endl; } } } -int main(int argc, char *argv[]) -{ - - // Disable deprecation warning for getenv call. +int main(int argc, char *argv[]) { +// Disable deprecation warning for getenv call. #ifdef CHAISCRIPT_MSVC #pragma warning(push) #pragma warning(disable : 4996) @@ -281,8 +247,7 @@ int main(int argc, char *argv[]) std::vector usepaths; usepaths.push_back(""); - if (usepath) - { + if (usepath) { usepaths.push_back(usepath); } @@ -290,12 +255,11 @@ int main(int argc, char *argv[]) std::vector searchpaths = default_search_paths(); modulepaths.insert(modulepaths.end(), searchpaths.begin(), searchpaths.end()); modulepaths.push_back(""); - if (modulepath) - { + if (modulepath) { modulepaths.push_back(modulepath); } - //chaiscript::ChaiScript chai(modulepaths, usepaths); + // chaiscript::ChaiScript chai(modulepaths, usepaths); chaiscript::ChaiScript chai(usepaths); chai.add(chaiscript::fun(&myexit), "exit"); @@ -308,8 +272,7 @@ int main(int argc, char *argv[]) clock_t begin = clock(); - for (int i = 0; i < 1000; i++) - { + for (int i = 0; i < 1000; i++) { std::string str = helloWorld("Bob12345"); fwrite(str.c_str(), 1, str.size(), stdout); } @@ -317,17 +280,17 @@ int main(int argc, char *argv[]) clock_t end = clock(); double elapsed_secs = double(end - begin) / CLOCKS_PER_SEC; - //begin = clock(); + // begin = clock(); ////for (int i = 0; i < 1000; i++) ////{ //// chai.eval("puts(helloWorld(\"Bob12345\"));"); ////} - //chai.eval_file("E:\\C++\\ChaiScript - 5.4.0\\samples\forx.chai"); + // chai.eval_file("E:\\C++\\ChaiScript - 5.4.0\\samples\forx.chai"); - //end = clock(); - //elapsed_secs = double(end - begin) / CLOCKS_PER_SEC; - //printf("**MyProgram::time= %lf\n", elapsed_secs); + // end = clock(); + // elapsed_secs = double(end - begin) / CLOCKS_PER_SEC; + // printf("**MyProgram::time= %lf\n", elapsed_secs); for (int i = 0; i < argc; ++i) { if (i == 0 && argc > 1) { @@ -337,69 +300,64 @@ int main(int argc, char *argv[]) std::string arg(i ? argv[i] : "--interactive"); enum { - eInteractive - , eCommand - , eFile - } mode = eCommand; + eInteractive, + eCommand, + eFile + } mode + = eCommand; if (arg == "-c" || arg == "--command") { if ((i + 1) >= argc) { std::cout << "insufficient input following " << arg << std::endl; return EXIT_FAILURE; - } - else { + } else { arg = argv[++i]; } - } - else if (arg == "-" || arg == "--stdin") { + } else if (arg == "-" || arg == "--stdin") { arg = ""; std::string line; while (std::getline(std::cin, line)) { arg += line + '\n'; } - } - else if (arg == "-v" || arg == "--version") { + } else if (arg == "-v" || arg == "--version") { arg = "version()"; - } - else if (arg == "-h" || arg == "--help") { + } else if (arg == "-h" || arg == "--help") { arg = "help(-1)"; - } - else if (arg == "-i" || arg == "--interactive") { + } else if (arg == "-i" || arg == "--interactive") { mode = eInteractive; - } - else if (arg.find('-') == 0) { + } else if (arg.find('-') == 0) { std::cout << "unrecognised argument " << arg << std::endl; return EXIT_FAILURE; - } - else { + } else { mode = eFile; } chaiscript::Boxed_Value val; try { switch (mode) { - case eInteractive: interactive(chai); break; - case eCommand: val = chai.eval(arg); break; + case eInteractive: + interactive(chai); + break; + case eCommand: + val = chai.eval(arg); + break; case eFile: { - begin = clock(); + begin = clock(); - val = chai.eval_file(arg); - - end = clock(); - double elapsed_secs1 = double(end - begin) / CLOCKS_PER_SEC; - printf("**C++::time= %.10f\n", elapsed_secs); - printf("**ChaiScript::time= %.10f\n", elapsed_secs1); - break; - } + val = chai.eval_file(arg); + end = clock(); + double elapsed_secs1 = double(end - begin) / CLOCKS_PER_SEC; + printf("**C++::time= %.10f\n", elapsed_secs); + printf("**ChaiScript::time= %.10f\n", elapsed_secs1); + break; + } } - } - catch (const chaiscript::exception::eval_error &ee) { + } catch (const chaiscript::exception::eval_error &ee) { std::cout << ee.pretty_print(); std::cout << std::endl; return EXIT_FAILURE; - } - catch (std::exception &e) { + } catch (std::exception &e) { std::cout << e.what() << std::endl; return EXIT_FAILURE; } @@ -407,4 +365,3 @@ int main(int argc, char *argv[]) return EXIT_SUCCESS; } - diff --git a/samples/inheritance.cpp b/samples/inheritance.cpp index 1c9ddb63..616d773f 100644 --- a/samples/inheritance.cpp +++ b/samples/inheritance.cpp @@ -1,79 +1,66 @@ #include -class BaseClass -{ - public: - BaseClass() - { +class BaseClass { +public: + BaseClass() = default; + + BaseClass(const BaseClass &) = default; + + virtual ~BaseClass() = default; + + virtual std::string doSomething(float, double) const = 0; + + void setValue(const std::string &t_val) { + if (validateValue(t_val)) { + m_value = t_val; } + } - BaseClass(const BaseClass &) = default; + std::string getValue() const { return m_value; } - virtual ~BaseClass() {} +protected: + virtual bool validateValue(const std::string &t_val) = 0; - virtual std::string doSomething(float, double) const = 0; - - - void setValue(const std::string &t_val) { - if (validateValue(t_val)) - { - m_value = t_val; - } - } - - std::string getValue() const { - return m_value; - } - - protected: - virtual bool validateValue(const std::string &t_val) = 0; - - private: - std::string m_value; +private: + std::string m_value; }; -class ChaiScriptDerived : public BaseClass -{ - public: - ChaiScriptDerived(const std::vector &t_funcs) - { - // using the range-checked .at() methods to give us an exception - // instead of a crash if the user passed in too-few params - tie(t_funcs.at(0), m_doSomethingImpl); - tie(t_funcs.at(1), m_validateValueImpl); - } +class ChaiScriptDerived : public BaseClass { +public: + ChaiScriptDerived(const std::vector &t_funcs) { + // using the range-checked .at() methods to give us an exception + // instead of a crash if the user passed in too-few params + tie(t_funcs.at(0), m_doSomethingImpl); + tie(t_funcs.at(1), m_validateValueImpl); + } - std::string doSomething(float f, double d) const override - { - assert(m_doSomethingImpl); - return m_doSomethingImpl(*this, f, d); - } + std::string doSomething(float f, double d) const override { + assert(m_doSomethingImpl); + return m_doSomethingImpl(*this, f, d); + } - protected: - bool validateValue(const std::string &t_val) override - { - assert(m_validateValueImpl); - return m_validateValueImpl(*this, t_val); - } +protected: + bool validateValue(const std::string &t_val) override { + assert(m_validateValueImpl); + return m_validateValueImpl(*this, t_val); + } - private: - template - void tie(const chaiscript::Boxed_Value &t_func, Param &t_param) - { - t_param = chaiscript::boxed_cast(t_func); - } +private: + template + void tie(const chaiscript::Boxed_Value &t_func, Param &t_param) { + t_param = chaiscript::boxed_cast(t_func); + } - std::function m_doSomethingImpl; - std::function m_validateValueImpl; + std::function m_doSomethingImpl; + std::function m_validateValueImpl; }; -int main() -{ +int main() { chaiscript::ChaiScript chai; chai.add(chaiscript::fun(&BaseClass::doSomething), "doSomething"); chai.add(chaiscript::fun(&BaseClass::setValue), "setValue"); chai.add(chaiscript::fun(&BaseClass::getValue), "getValue"); - chai.add(chaiscript::constructor &)>(), "ChaiScriptDerived"); + chai.add(chaiscript::constructor &)>(), "ChaiScriptDerived"); chai.add(chaiscript::base_class()); chai.add(chaiscript::user_type(), "BaseClass"); chai.add(chaiscript::user_type(), "ChaiScriptDerived"); @@ -105,8 +92,8 @@ int main() )""; chai.eval(script); - - BaseClass &myderived = chai.eval("myderived"); + + BaseClass &myderived = chai.eval("myderived"); // 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 @@ -121,7 +108,6 @@ int main() myderived.setValue("12345"); assert(myderived.getValue() == "1234"); - chai.eval(R"(myderived.setValue("new"))"); // set the value via chaiscript assert(myderived.getValue() == "new"); @@ -131,5 +117,3 @@ int main() // The whole process is fully orthogonal } - - diff --git a/samples/memory_leak_test.cpp b/samples/memory_leak_test.cpp index 513656b7..8cea1cdb 100644 --- a/samples/memory_leak_test.cpp +++ b/samples/memory_leak_test.cpp @@ -3,12 +3,10 @@ #include #ifdef READLINE_AVAILABLE -#include #include +#include #endif - - std::string get_next_command() { #ifdef READLINE_AVAILABLE char *input_raw; @@ -23,42 +21,32 @@ std::string get_next_command() { #endif } -void function(void) -{ +void function(void) { // do nothing } -class test -{ +class test { chaiscript::ChaiScript chai; chaiscript::ChaiScript::State backupState = chai.get_state(); - public: - void ResetState() - { +public: + void ResetState() { 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 { chaiscript::Boxed_Value val = chai.eval_file(sFile); - } - catch (std::exception &e) { + } catch (std::exception &e) { std::cout << e.what() << '\n'; } } - }; - - int main(int /*argc*/, char * /*argv*/[]) { - test myChai; - 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 // low as in case 1 scenario3 : - while(command != "quit") - { - for(int i = 1; i < 200; i++) + while (command != "quit") { + for (int i = 1; i < 200; i++) myChai.ResetState(); - if(command == "runfile") + if (command == "runfile") myChai.RunFile("Test.chai"); command = get_next_command(); diff --git a/samples/test_num_exceptions.cpp b/samples/test_num_exceptions.cpp index 8347c4a0..59d816fa 100644 --- a/samples/test_num_exceptions.cpp +++ b/samples/test_num_exceptions.cpp @@ -2,15 +2,12 @@ #include #include -int main( int /*argc*/ , char * /*argv*/[] ) -{ +int main(int /*argc*/, char * /*argv*/[]) { chaiscript::ChaiScript ch; - - try - { - static const char script[ ] = - R""( + try { + static const char script[] = + R""( class Rectangle { @@ -21,12 +18,9 @@ int main( int /*argc*/ , char * /*argv*/[] ) )""; - - ch.eval( script ); - } - catch ( const std::exception &e ) - { - printf( " >>> Exception thrown: %s \n" , e.what( ) ); + ch.eval(script); + } catch (const std::exception &e) { + printf(" >>> Exception thrown: %s \n", e.what()); } return 1; diff --git a/src/chaiscript_stdlib_module.cpp b/src/chaiscript_stdlib_module.cpp index d4ea13e8..f7224d40 100644 --- a/src/chaiscript_stdlib_module.cpp +++ b/src/chaiscript_stdlib_module.cpp @@ -1,7 +1,6 @@ #include - // 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 #ifdef CHAISCRIPT_MSVC @@ -14,13 +13,10 @@ #pragma clang diagnostic ignored "-Wreturn-type-c-linkage" #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(); } - #ifdef __llvm__ #pragma clang diagnostic pop #endif diff --git a/src/libfuzzer_client.cpp b/src/libfuzzer_client.cpp index 4dec4560..39ebe2f4 100644 --- a/src/libfuzzer_client.cpp +++ b/src/libfuzzer_client.cpp @@ -7,7 +7,6 @@ // 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 - #include #include #include @@ -16,49 +15,45 @@ #define _CRT_SECURE_NO_WARNINGS #endif -#include #include "../static_libs/chaiscript_parser.hpp" #include "../static_libs/chaiscript_stdlib.hpp" +#include #include "sha3.h" #ifdef READLINE_AVAILABLE -#include #include +#include #else -char *mystrdup (const char *s) { +char *mystrdup(const char *s) { size_t len = strlen(s); // Space for length plus nul - char *d = static_cast(malloc (len+1)); - if (d == nullptr) { return nullptr; } // No memory + char *d = static_cast(malloc(len + 1)); + if (d == nullptr) { + return nullptr; + } // No memory #ifdef CHAISCRIPT_MSVC - strcpy_s(d, len+1, s); // Copy the characters + strcpy_s(d, len + 1, s); // Copy the characters #else - strncpy(d,s,len); // Copy the characters + strncpy(d, s, len); // Copy the characters #endif 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::cout << p ; + std::cout << p; std::getline(std::cin, retval); return std::cin.eof() ? nullptr : mystrdup(retval.c_str()); } - -void add_history(const char* /*unused*/){} -void using_history(){} +void add_history(const char * /*unused*/) {} +void using_history() {} #endif - - -void *cast_module_symbol(std::vector (*t_path)()) -{ - union cast_union - { +void *cast_module_symbol(std::vector (*t_path)()) { + union cast_union { std::vector (*in_ptr)(); void *out_ptr; }; @@ -68,26 +63,23 @@ void *cast_module_symbol(std::vector (*t_path)()) return c.out_ptr; } -std::vector default_search_paths() -{ +std::vector default_search_paths() { std::vector paths; #ifndef CHAISCRIPT_NO_DYNLOAD -#ifdef CHAISCRIPT_WINDOWS // force no unicode +#ifdef CHAISCRIPT_WINDOWS // force no unicode CHAR path[4096]; - int size = GetModuleFileNameA(nullptr, path, sizeof(path)-1); + int size = GetModuleFileNameA(nullptr, path, sizeof(path) - 1); std::string exepath(path, size); size_t lastslash = exepath.rfind('\\'); size_t secondtolastslash = exepath.rfind('\\', lastslash - 1); - if (lastslash != std::string::npos) - { + if (lastslash != std::string::npos) { paths.push_back(exepath.substr(0, lastslash)); } - if (secondtolastslash != std::string::npos) - { + if (secondtolastslash != std::string::npos) { return {exepath.substr(0, secondtolastslash) + "\\lib\\chaiscript\\"}; } #else @@ -97,32 +89,26 @@ std::vector default_search_paths() std::vector buf(2048); 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)); } - if (exepath.empty()) - { - if ((size = readlink("/proc/curproc/file", &buf.front(), buf.size())) >= 0) - { + if (exepath.empty()) { + if ((size = readlink("/proc/curproc/file", &buf.front(), buf.size())) >= 0) { exepath = std::string(&buf.front(), static_cast(size)); } } - if (exepath.empty()) - { - if ((size = readlink("/proc/self/path/a.out", &buf.front(), buf.size())) >= 0) - { + if (exepath.empty()) { + if ((size = readlink("/proc/self/path/a.out", &buf.front(), buf.size())) >= 0) { exepath = std::string(&buf.front(), static_cast(size)); } } - if (exepath.empty()) - { + if (exepath.empty()) { Dl_info rInfo; - memset( &rInfo, 0, sizeof(rInfo) ); - if ( dladdr(cast_module_symbol(&default_search_paths), &rInfo) == 0 || rInfo.dli_fname == nullptr ) { + memset(&rInfo, 0, sizeof(rInfo)); + if (dladdr(cast_module_symbol(&default_search_paths), &rInfo) == 0 || rInfo.dli_fname == nullptr) { return paths; } @@ -132,13 +118,11 @@ std::vector default_search_paths() size_t lastslash = exepath.rfind('/'); size_t secondtolastslash = exepath.rfind('/', lastslash - 1); - if (lastslash != std::string::npos) - { - paths.push_back(exepath.substr(0, lastslash+1)); + if (lastslash != std::string::npos) { + 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/"); } #endif @@ -148,25 +132,24 @@ std::vector default_search_paths() } void help(int n) { - if ( n >= 0 ) { + if (n >= 0) { std::cout << "ChaiScript evaluator. To evaluate an expression, type it and press .\n"; std::cout << "Additionally, you can inspect the runtime system using:\n"; std::cout << " dump_system() - outputs all functions registered to the system\n"; std::cout << " dump_object(x) - dumps information about the given symbol\n"; } else { std::cout << "usage : chai [option]+\n"; - std::cout << "option:" << '\n'; - std::cout << " -h | --help" << '\n'; - std::cout << " -i | --interactive" << '\n'; - std::cout << " -c | --command cmd" << '\n'; - std::cout << " -v | --version" << '\n'; - std::cout << " - --stdin" << '\n'; - std::cout << " filepath" << '\n'; + std::cout << "option:" << '\n'; + std::cout << " -h | --help" << '\n'; + std::cout << " -i | --interactive" << '\n'; + std::cout << " -c | --command cmd" << '\n'; + std::cout << " -v | --version" << '\n'; + std::cout << " - --stdin" << '\n'; + std::cout << " filepath" << '\n'; } } -bool throws_exception(const std::function &f) -{ +bool throws_exception(const std::function &f) { try { f(); } catch (...) { @@ -176,8 +159,7 @@ bool throws_exception(const std::function &f) return false; } -chaiscript::exception::eval_error get_eval_error(const std::function &f) -{ +chaiscript::exception::eval_error get_eval_error(const std::function &f) { try { f(); } catch (const chaiscript::exception::eval_error &e) { @@ -189,21 +171,19 @@ chaiscript::exception::eval_error get_eval_error(const std::function &f std::string get_next_command() { std::string retval("quit"); - if ( ! std::cin.eof() ) { + if (!std::cin.eof()) { char *input_raw = readline("eval> "); - if ( input_raw != nullptr ) { + if (input_raw != nullptr) { add_history(input_raw); std::string val(input_raw); size_t pos = val.find_first_not_of("\t \n"); - if (pos != std::string::npos) - { + if (pos != std::string::npos) { val.erase(0, pos); } pos = val.find_last_not_of("\t \n"); - if (pos != std::string::npos) - { - val.erase(pos+1, std::string::npos); + if (pos != std::string::npos) { + val.erase(pos + 1, std::string::npos); } retval = val; @@ -211,11 +191,7 @@ std::string get_next_command() { ::free(input_raw); } } - if( retval == "quit" - || retval == "exit" - || retval == "help" - || retval == "version") - { + if (retval == "quit" || retval == "exit" || retval == "help" || retval == "version") { retval += "(0)"; } return retval; @@ -227,8 +203,7 @@ void myexit(int return_val) { exit(return_val); } -void interactive(chaiscript::ChaiScript_Basic& chai) -{ +void interactive(chaiscript::ChaiScript_Basic &chai) { using_history(); for (;;) { @@ -237,30 +212,27 @@ void interactive(chaiscript::ChaiScript_Basic& chai) // evaluate 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())) { try { - std::cout << chai.eval >("to_string")(val) << '\n'; - } - catch (...) {} //If we can't, do nothing + std::cout << chai.eval>("to_string")(val) << '\n'; + } 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(); - 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 << '\n'; - } - catch (const std::exception &e) { + } catch (const std::exception &e) { std::cout << e.what(); std::cout << '\n'; } } } -double now() -{ +double now() { using namespace std::chrono; auto now = high_resolution_clock::now(); return duration_cast>(now.time_since_epoch()).count(); @@ -269,7 +241,7 @@ double now() extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { chaiscript::ChaiScript chai; - chai.eval( R"chaiscript( + chai.eval(R"chaiscript( def assert_equal(x, y) { if (x == y) @@ -339,7 +311,8 @@ def assert_throws(desc, x) std::ofstream ofs("BOXED_VALUE/" + sha); ofs << input; } 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 &) { std::ofstream ofs("STD_EXCEPTION/" + sha); ofs << input; @@ -350,5 +323,3 @@ def assert_throws(desc, x) return 0; } - - diff --git a/src/main.cpp b/src/main.cpp index 0c045c6e..6ec746fb 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -7,7 +7,6 @@ // 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 - #include #include #include @@ -16,48 +15,43 @@ #define _CRT_SECURE_NO_WARNINGS #endif -#include #include "../static_libs/chaiscript_parser.hpp" #include "../static_libs/chaiscript_stdlib.hpp" - +#include #ifdef READLINE_AVAILABLE -#include #include +#include #else -char *mystrdup (const char *s) { +char *mystrdup(const char *s) { size_t len = strlen(s); // Space for length plus nul - char *d = static_cast(malloc (len+1)); - if (d == nullptr) { return nullptr; } // No memory + char *d = static_cast(malloc(len + 1)); + if (d == nullptr) { + return nullptr; + } // No memory #ifdef CHAISCRIPT_MSVC - strcpy_s(d, len+1, s); // Copy the characters + strcpy_s(d, len + 1, s); // Copy the characters #else - strncpy(d,s,len); // Copy the characters + strncpy(d, s, len); // Copy the characters #endif 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::cout << p ; + std::cout << p; std::getline(std::cin, retval); return std::cin.eof() ? nullptr : mystrdup(retval.c_str()); } - -void add_history(const char* /*unused*/){} -void using_history(){} +void add_history(const char * /*unused*/) {} +void using_history() {} #endif - - -void *cast_module_symbol(std::vector (*t_path)()) -{ - union cast_union - { +void *cast_module_symbol(std::vector (*t_path)()) { + union cast_union { std::vector (*in_ptr)(); void *out_ptr; }; @@ -67,26 +61,23 @@ void *cast_module_symbol(std::vector (*t_path)()) return c.out_ptr; } -std::vector default_search_paths() -{ +std::vector default_search_paths() { std::vector paths; #ifndef CHAISCRIPT_NO_DYNLOAD -#ifdef CHAISCRIPT_WINDOWS // force no unicode +#ifdef CHAISCRIPT_WINDOWS // force no unicode CHAR path[4096]; - int size = GetModuleFileNameA(nullptr, path, sizeof(path)-1); + int size = GetModuleFileNameA(nullptr, path, sizeof(path) - 1); std::string exepath(path, size); size_t lastslash = exepath.rfind('\\'); size_t secondtolastslash = exepath.rfind('\\', lastslash - 1); - if (lastslash != std::string::npos) - { + if (lastslash != std::string::npos) { paths.push_back(exepath.substr(0, lastslash)); } - if (secondtolastslash != std::string::npos) - { + if (secondtolastslash != std::string::npos) { return {exepath.substr(0, secondtolastslash) + "\\lib\\chaiscript\\"}; } #else @@ -96,32 +87,26 @@ std::vector default_search_paths() std::vector buf(2048); 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)); } - if (exepath.empty()) - { - if ((size = readlink("/proc/curproc/file", &buf.front(), buf.size())) >= 0) - { + if (exepath.empty()) { + if ((size = readlink("/proc/curproc/file", &buf.front(), buf.size())) >= 0) { exepath = std::string(&buf.front(), static_cast(size)); } } - if (exepath.empty()) - { - if ((size = readlink("/proc/self/path/a.out", &buf.front(), buf.size())) >= 0) - { + if (exepath.empty()) { + if ((size = readlink("/proc/self/path/a.out", &buf.front(), buf.size())) >= 0) { exepath = std::string(&buf.front(), static_cast(size)); } } - if (exepath.empty()) - { + if (exepath.empty()) { Dl_info rInfo; - memset( &rInfo, 0, sizeof(rInfo) ); - if ( dladdr(cast_module_symbol(&default_search_paths), &rInfo) == 0 || rInfo.dli_fname == nullptr ) { + memset(&rInfo, 0, sizeof(rInfo)); + if (dladdr(cast_module_symbol(&default_search_paths), &rInfo) == 0 || rInfo.dli_fname == nullptr) { return paths; } @@ -131,13 +116,11 @@ std::vector default_search_paths() size_t lastslash = exepath.rfind('/'); size_t secondtolastslash = exepath.rfind('/', lastslash - 1); - if (lastslash != std::string::npos) - { - paths.push_back(exepath.substr(0, lastslash+1)); + if (lastslash != std::string::npos) { + 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/"); } #endif @@ -147,25 +130,24 @@ std::vector default_search_paths() } void help(int n) { - if ( n >= 0 ) { + if (n >= 0) { std::cout << "ChaiScript evaluator. To evaluate an expression, type it and press .\n"; std::cout << "Additionally, you can inspect the runtime system using:\n"; std::cout << " dump_system() - outputs all functions registered to the system\n"; std::cout << " dump_object(x) - dumps information about the given symbol\n"; } else { std::cout << "usage : chai [option]+\n"; - std::cout << "option:" << '\n'; - std::cout << " -h | --help" << '\n'; - std::cout << " -i | --interactive" << '\n'; - std::cout << " -c | --command cmd" << '\n'; - std::cout << " -v | --version" << '\n'; - std::cout << " - --stdin" << '\n'; - std::cout << " filepath" << '\n'; + std::cout << "option:" << '\n'; + std::cout << " -h | --help" << '\n'; + std::cout << " -i | --interactive" << '\n'; + std::cout << " -c | --command cmd" << '\n'; + std::cout << " -v | --version" << '\n'; + std::cout << " - --stdin" << '\n'; + std::cout << " filepath" << '\n'; } } -std::string throws_exception(const std::function &f) -{ +std::string throws_exception(const std::function &f) { try { f(); } catch (const std::exception &e) { @@ -175,8 +157,7 @@ std::string throws_exception(const std::function &f) return ""; } -chaiscript::exception::eval_error get_eval_error(const std::function &f) -{ +chaiscript::exception::eval_error get_eval_error(const std::function &f) { try { f(); } catch (const chaiscript::exception::eval_error &e) { @@ -188,21 +169,19 @@ chaiscript::exception::eval_error get_eval_error(const std::function &f std::string get_next_command() { std::string retval("quit"); - if ( ! std::cin.eof() ) { + if (!std::cin.eof()) { char *input_raw = readline("eval> "); - if ( input_raw != nullptr ) { + if (input_raw != nullptr) { add_history(input_raw); std::string val(input_raw); size_t pos = val.find_first_not_of("\t \n"); - if (pos != std::string::npos) - { + if (pos != std::string::npos) { val.erase(0, pos); } pos = val.find_last_not_of("\t \n"); - if (pos != std::string::npos) - { - val.erase(pos+1, std::string::npos); + if (pos != std::string::npos) { + val.erase(pos + 1, std::string::npos); } retval = val; @@ -210,11 +189,7 @@ std::string get_next_command() { ::free(input_raw); } } - if( retval == "quit" - || retval == "exit" - || retval == "help" - || retval == "version") - { + if (retval == "quit" || retval == "exit" || retval == "help" || retval == "version") { retval += "(0)"; } return retval; @@ -226,8 +201,7 @@ void myexit(int return_val) { exit(return_val); } -void interactive(chaiscript::ChaiScript_Basic& chai) -{ +void interactive(chaiscript::ChaiScript_Basic &chai) { using_history(); for (;;) { @@ -236,39 +210,34 @@ void interactive(chaiscript::ChaiScript_Basic& chai) // evaluate 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())) { try { - std::cout << chai.eval >("to_string")(val) << '\n'; - } - catch (...) {} //If we can't, do nothing + std::cout << chai.eval>("to_string")(val) << '\n'; + } 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(); - 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 << '\n'; - } - catch (const std::exception &e) { + } catch (const std::exception &e) { std::cout << e.what(); std::cout << '\n'; } } } -double now() -{ +double now() { using namespace std::chrono; auto now = high_resolution_clock::now(); return duration_cast>(now.time_since_epoch()).count(); } -int main(int argc, char *argv[]) -{ - - // Disable deprecation warning for getenv call. +int main(int argc, char *argv[]) { +// Disable deprecation warning for getenv call. #ifdef CHAISCRIPT_MSVC #pragma warning(push) #pragma warning(disable : 4996) @@ -283,8 +252,7 @@ int main(int argc, char *argv[]) std::vector usepaths; usepaths.emplace_back(""); - if (usepath != nullptr) - { + if (usepath != nullptr) { usepaths.emplace_back(usepath); } @@ -292,12 +260,11 @@ int main(int argc, char *argv[]) std::vector searchpaths = default_search_paths(); modulepaths.insert(modulepaths.end(), searchpaths.begin(), searchpaths.end()); modulepaths.emplace_back(""); - if (modulepath != nullptr) - { + if (modulepath != nullptr) { 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), "quit"); @@ -311,46 +278,48 @@ int main(int argc, char *argv[]) bool any_exception_ok = false; for (int i = 0; i < argc; ++i) { - if ( i == 0 && argc > 1 ) { + if (i == 0 && argc > 1) { ++i; } - std::string arg( i != 0 ? argv[i] : "--interactive" ); + std::string arg(i != 0 ? argv[i] : "--interactive"); - enum { eInteractive - , eCommand - , eFile - } mode = eCommand ; + enum { + eInteractive, + eCommand, + eFile + } mode + = eCommand; - if ( arg == "-c" || arg == "--command" ) { - if ( (i+1) >= argc ) { + if (arg == "-c" || arg == "--command") { + if ((i + 1) >= argc) { std::cout << "insufficient input following " << arg << '\n'; return EXIT_FAILURE; - } - arg = argv[++i]; - - } else if ( arg == "-" || arg == "--stdin" ) { - arg = "" ; - std::string line; - while ( std::getline(std::cin, line) ) { - arg += line + '\n' ; } - } else if ( arg == "-v" || arg == "--version" ) { - arg = "print(version())" ; - } else if ( arg == "-h" || arg == "--help" ) { + arg = argv[++i]; + + } else if (arg == "-" || arg == "--stdin") { + arg = ""; + std::string line; + while (std::getline(std::cin, line)) { + arg += line + '\n'; + } + } else if (arg == "-v" || arg == "--version") { + arg = "print(version())"; + } else if (arg == "-h" || arg == "--help") { arg = "help(-1)"; - } else if ( arg == "-e" || arg == "--evalerrorok" ) { + } else if (arg == "-e" || arg == "--evalerrorok") { eval_error_ok = true; continue; - } else if ( arg == "--exception" ) { + } else if (arg == "--exception") { boxed_exception_ok = true; continue; - } else if ( arg == "--any-exception" ) { + } else if (arg == "--any-exception") { any_exception_ok = true; continue; - } else if ( arg == "-i" || arg == "--interactive" ) { - mode = eInteractive ; - } else if ( arg.find('-') == 0 ) { + } else if (arg == "-i" || arg == "--interactive") { + mode = eInteractive; + } else if (arg.find('-') == 0) { std::cout << "unrecognised argument " << arg << '\n'; return EXIT_FAILURE; } else { @@ -358,7 +327,7 @@ int main(int argc, char *argv[]) } try { - switch ( mode ) { + switch (mode) { case eInteractive: interactive(chai); break; @@ -368,32 +337,28 @@ int main(int argc, char *argv[]) case eFile: 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 << '\n'; if (!eval_error_ok) { 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'; if (!boxed_exception_ok) { return EXIT_FAILURE; } - } - catch (const chaiscript::exception::load_module_error &e) { - std::cout << "Unhandled module load error\n" << e.what() << '\n'; - } - catch (std::exception &e) { + } catch (const chaiscript::exception::load_module_error &e) { + std::cout << "Unhandled module load error\n" + << e.what() << '\n'; + } catch (std::exception &e) { std::cout << "Unhandled standard exception: " << e.what() << '\n'; if (!any_exception_ok) { throw; } - } - catch (...) { + } catch (...) { std::cout << "Unhandled unknown exception" << '\n'; if (!any_exception_ok) { throw; diff --git a/src/sanity_checks.cpp b/src/sanity_checks.cpp index 1a0922bc..9d87b5d9 100644 --- a/src/sanity_checks.cpp +++ b/src/sanity_checks.cpp @@ -4,67 +4,52 @@ // and Jason Turner (jason@emptycrate.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 - -#include #include +#include #include #include #include -void log(const std::string &msg) -{ +void log(const std::string &msg) { 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'; } -void bound_log(const std::string &msg) -{ +void bound_log(const std::string &msg) { log(msg); } -void hello_world(const chaiscript::Boxed_Value & /*o*/) -{ +void hello_world(const chaiscript::Boxed_Value & /*o*/) { 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"; } +struct System { + std::map> m_callbacks; -struct System -{ - std::map > m_callbacks; - - void add_callback(const std::string &t_name, - const std::function &t_func) - { + void add_callback(const std::string &t_name, const std::function &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); - for (auto & m_callback : m_callbacks) - { + for (auto &m_callback : m_callbacks) { log("Callback: " + m_callback.first, m_callback.second(inp)); } } }; -void take_shared_ptr(const std::shared_ptr &p) -{ +void take_shared_ptr(const std::shared_ptr &p) { std::cout << *p << '\n'; } @@ -72,27 +57,26 @@ int main(int /*argc*/, char * /*argv*/[]) { using namespace chaiscript; 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; 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"); - //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::do_callbacks), "do_callbacks"); chai.add(fun(&take_shared_ptr), "take_shared_ptr"); - // Let's use chaiscript to add a new lambda callback to our system. + // Let's use chaiscript to add a new lambda callback to our system. // The function "{ 'Callback1' + x }" is created in chaiscript and passed into our C++ application - // in the "add_callback" function of struct System the chaiscript function is converted into a + // in the "add_callback" function of struct System the chaiscript function is converted into a // std::function, so it can be handled and called easily and type-safely chai.eval(R"(system.add_callback("#1", fun(x) { "Callback1 " + x });)"); - + // Because we are sharing the "system" object with the chaiscript engine we have equal // access to it both from within chaiscript and from C++ code system.do_callbacks("TestString"); @@ -111,29 +95,26 @@ int main(int /*argc*/, char * /*argv*/[]) { // A shortcut to using eval is just to use the chai operator() chai(R"(log("Test Module", "Test Message");)"); - //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 - chai.add(fun([&system](){ return system.do_callbacks("Bound Test"); }), "do_callbacks"); + // 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 + 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()"); - std::function caller = chai.eval >( - R"(fun() { system.do_callbacks("From Functor"); })" - ); + std::function caller = chai.eval>(R"(fun() { system.do_callbacks("From Functor"); })"); caller(); - - //If we would like a type-safe return value from all call, we can use - //the templated version of eval: + // If we would like a type-safe return value from all call, we can use + // the templated version of eval: int i = chai.eval("5+5"); std::cout << "5+5: " << i << '\n'; - //Add a new variable + // Add a new variable 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("scripti"); std::cout << "scripti: " << scripti << '\n'; @@ -141,10 +122,10 @@ int main(int /*argc*/, char * /*argv*/[]) { std::cout << "scripti (updated): " << scripti << '\n'; 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 - int x = chai.eval >("fun (x, y) { return x + y; }")(5, 6); + // Creating a functor on the stack and using it immediately + int x = chai.eval>("fun (x, y) { return x + y; }")(5, 6); std::stringstream ss; ss << x; @@ -158,25 +139,23 @@ int main(int /*argc*/, char * /*argv*/[]) { chai("def getvar() { return constvar; }"); chai("print( getvar() )"); - - //Ability to create our own container types when needed. std::vector and std::map are - //mostly supported currently - //chai.add(bootstrap::standard_library::vector_type >("IntVector")); - + // Ability to create our own container types when needed. std::vector and std::map are + // mostly supported currently + // chai.add(bootstrap::standard_library::vector_type >("IntVector")); // 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.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_Constructor("TestType", fun(&hello_constructor))), "TestType"); -// chai.add(fun(std::function(std::bind(&dispatch::detail::Dynamic_Object_Attribute::func, "TestType", "attr", std::placeholders::_1))), "attr"); + // chai.add(fun(std::function(std::bind(&dispatch::detail::Dynamic_Object_Attribute::func, + // "TestType", "attr", std::placeholders::_1))), "attr"); chai.eval("var x = TestType()"); -// chai.eval("x.attr = \"hi\""); -// chai.eval("print(x.attr)"); + // chai.eval("x.attr = \"hi\""); + // chai.eval("print(x.attr)"); chai.eval("x.hello_world()"); } - diff --git a/src/sha3.cpp b/src/sha3.cpp index f962512e..ea16f57b 100644 --- a/src/sha3.cpp +++ b/src/sha3.cpp @@ -11,52 +11,35 @@ #include #endif - /// same as reset() SHA3::SHA3(Bits bits) -: m_blockSize(200 - 2 * (bits / 8)), - m_bits(bits) -{ + : m_blockSize(200 - 2 * (bits / 8)) + , m_bits(bits) { reset(); } - /// restart -void SHA3::reset() -{ +void SHA3::reset() { for (size_t i = 0; i < StateSize; i++) m_hash[i] = 0; - m_numBytes = 0; + m_numBytes = 0; m_bufferSize = 0; } - /// constants and local helper functions -namespace -{ +namespace { const unsigned int Rounds = 24; - 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 - }; + 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}; /// 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)); } /// convert litte vs big endian - inline uint64_t swap(uint64_t x) - { + inline uint64_t swap(uint64_t x) { #if defined(__GNUC__) || defined(__clang__) return __builtin_bswap64(x); #endif @@ -64,55 +47,43 @@ namespace return _byteswap_uint64(x); #endif - return (x >> 56) | - ((x >> 40) & 0x000000000000FF00ULL) | - ((x >> 24) & 0x0000000000FF0000ULL) | - ((x >> 8) & 0x00000000FF000000ULL) | - ((x << 8) & 0x000000FF00000000ULL) | - ((x << 24) & 0x0000FF0000000000ULL) | - ((x << 40) & 0x00FF000000000000ULL) | - (x << 56); + return (x >> 56) | ((x >> 40) & 0x000000000000FF00ULL) | ((x >> 24) & 0x0000000000FF0000ULL) | ((x >> 8) & 0x00000000FF000000ULL) + | ((x << 8) & 0x000000FF00000000ULL) | ((x << 24) & 0x0000FF0000000000ULL) | ((x << 40) & 0x00FF000000000000ULL) | (x << 56); } - /// return x % 5 for 0 <= x <= 9 - unsigned int mod5(unsigned int x) - { + unsigned int mod5(unsigned int x) { if (x < 5) return x; return x - 5; } -} - +} // namespace /// 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) #define LITTLEENDIAN(x) swap(x) #else #define LITTLEENDIAN(x) (x) #endif - const uint64_t* data64 = (const uint64_t*) data; + const uint64_t *data64 = (const uint64_t *)data; // mix data into state for (unsigned int i = 0; i < m_blockSize / 8; i++) m_hash[i] ^= LITTLEENDIAN(data64[i]); // re-compute state - for (unsigned int round = 0; round < Rounds; round++) - { + for (unsigned int round = 0; round < Rounds; round++) { // Theta uint64_t coefficients[5]; 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]; - 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); - m_hash[i ] ^= one; - m_hash[i + 5] ^= one; + m_hash[i] ^= one; + m_hash[i + 5] ^= one; m_hash[i + 10] ^= one; m_hash[i + 15] ^= one; m_hash[i + 20] ^= one; @@ -123,43 +94,88 @@ void SHA3::processBlock(const void* data) // Rho Pi uint64_t last = m_hash[1]; - one = m_hash[10]; m_hash[10] = rotateLeft(last, 1); last = one; - one = m_hash[ 7]; m_hash[ 7] = rotateLeft(last, 3); last = one; - one = m_hash[11]; m_hash[11] = rotateLeft(last, 6); last = one; - one = m_hash[17]; m_hash[17] = rotateLeft(last, 10); last = one; - one = m_hash[18]; m_hash[18] = rotateLeft(last, 15); last = one; - one = m_hash[ 3]; m_hash[ 3] = rotateLeft(last, 21); last = one; - one = m_hash[ 5]; m_hash[ 5] = rotateLeft(last, 28); last = one; - one = m_hash[16]; m_hash[16] = rotateLeft(last, 36); 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); + one = m_hash[10]; + m_hash[10] = rotateLeft(last, 1); + last = one; + one = m_hash[7]; + m_hash[7] = rotateLeft(last, 3); + last = one; + one = m_hash[11]; + m_hash[11] = rotateLeft(last, 6); + last = one; + one = m_hash[17]; + m_hash[17] = rotateLeft(last, 10); + last = one; + one = m_hash[18]; + m_hash[18] = rotateLeft(last, 15); + last = one; + one = m_hash[3]; + m_hash[3] = rotateLeft(last, 21); + last = one; + one = m_hash[5]; + m_hash[5] = rotateLeft(last, 28); + last = one; + one = m_hash[16]; + m_hash[16] = rotateLeft(last, 36); + 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 - for (unsigned int j = 0; j < 25; j += 5) - { + for (unsigned int j = 0; j < 25; j += 5) { // temporaries uint64_t one = m_hash[j]; uint64_t two = m_hash[j + 1]; - m_hash[j] ^= m_hash[j + 2] & ~two; + m_hash[j] ^= m_hash[j + 2] & ~two; m_hash[j + 1] ^= m_hash[j + 3] & ~m_hash[j + 2]; m_hash[j + 2] ^= m_hash[j + 4] & ~m_hash[j + 3]; - m_hash[j + 3] ^= one & ~m_hash[j + 4]; - m_hash[j + 4] ^= two & ~one; + m_hash[j + 3] ^= one & ~m_hash[j + 4]; + m_hash[j + 4] ^= two & ~one; } // Iota @@ -167,27 +183,22 @@ void SHA3::processBlock(const void* data) } } - /// add arbitrary number of bytes -void SHA3::add(const void* data, size_t numBytes) -{ - const uint8_t* current = (const uint8_t*) data; +void SHA3::add(const void *data, size_t numBytes) { + const uint8_t *current = (const uint8_t *)data; // copy data to buffer - if (m_bufferSize > 0) - { - while (numBytes > 0 && m_bufferSize < m_blockSize) - { + if (m_bufferSize > 0) { + while (numBytes > 0 && m_bufferSize < m_blockSize) { m_buffer[m_bufferSize++] = *current++; numBytes--; } } // full buffer - if (m_bufferSize == m_blockSize) - { - processBlock((void*)m_buffer); - m_numBytes += m_blockSize; + if (m_bufferSize == m_blockSize) { + processBlock((void *)m_buffer); + m_numBytes += m_blockSize; m_bufferSize = 0; } @@ -196,26 +207,22 @@ void SHA3::add(const void* data, size_t numBytes) return; // process full blocks - while (numBytes >= m_blockSize) - { + while (numBytes >= m_blockSize) { processBlock(current); - current += m_blockSize; + current += m_blockSize; m_numBytes += m_blockSize; - numBytes -= m_blockSize; + numBytes -= m_blockSize; } // keep remaining bytes in buffer - while (numBytes > 0) - { + while (numBytes > 0) { m_buffer[m_bufferSize++] = *current++; numBytes--; } } - /// process everything left in the internal buffer -void SHA3::processBuffer() -{ +void SHA3::processBuffer() { // add padding size_t offset = m_bufferSize; // add a "1" byte @@ -230,10 +237,8 @@ void SHA3::processBuffer() processBlock(m_buffer); } - /// return latest hash as 16 hex characters -std::string SHA3::getHash() -{ +std::string SHA3::getHash() { // process remaining bytes processBuffer(); @@ -249,7 +254,7 @@ std::string SHA3::getHash() for (unsigned int j = 0; j < 8; j++) // 64 bits => 8 bytes { // 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 & 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 unsigned int remainder = m_bits - hashLength * 64; unsigned int processed = 0; - while (processed < remainder) - { + while (processed < remainder) { // 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 & 15]; @@ -270,19 +274,15 @@ std::string SHA3::getHash() return result; } - /// 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(); add(data, numBytes); return getHash(); } - /// 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(); add(text.c_str(), text.size()); return getHash(); diff --git a/src/stl_extra.cpp b/src/stl_extra.cpp index 90657580..0f456b09 100644 --- a/src/stl_extra.cpp +++ b/src/stl_extra.cpp @@ -7,7 +7,6 @@ // 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 - #include #include #include @@ -25,11 +24,10 @@ #pragma clang diagnostic ignored "-Wreturn-type-c-linkage" #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::bootstrap::standard_library::list_type >("List", *module); - chaiscript::bootstrap::standard_library::vector_type >("u16vector", *module); + chaiscript::bootstrap::standard_library::list_type>("List", *module); + chaiscript::bootstrap::standard_library::vector_type>("u16vector", *module); module->add(chaiscript::vector_conversion>()); return module; } diff --git a/src/test_module.cpp b/src/test_module.cpp index 4d1bc55d..6568b9b2 100644 --- a/src/test_module.cpp +++ b/src/test_module.cpp @@ -3,138 +3,121 @@ #include #include +class TestBaseType { +public: + TestBaseType() + : 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) + : val(other.val) + , const_val(other.const_val) + , const_val_ptr(&const_val) + , func_member(other.func_member) { + } -class TestBaseType -{ - public: - TestBaseType() : val(10), const_val(15), mdarray{} { } - TestBaseType(int) : val(10), const_val(15), mdarray{} { } - TestBaseType(int *) : val(10), const_val(15), mdarray{} { } + TestBaseType(TestBaseType &&other) + : val(other.val) + , const_val(other.const_val) + , const_val_ptr(&const_val) + , func_member(std::move(other.func_member)) { + } - TestBaseType(const TestBaseType &other) - : val(other.val), const_val(other.const_val), const_val_ptr(&const_val), - func_member(other.func_member) - { - } + TestBaseType &operator=(TestBaseType &&) = delete; + TestBaseType &operator=(const TestBaseType &) = delete; - TestBaseType(TestBaseType &&other) - : val(other.val), const_val(other.const_val), const_val_ptr(&const_val), - func_member(std::move(other.func_member)) - { - } + virtual ~TestBaseType() = default; + virtual int func() { return 0; } + int base_only_func() { return -9; } - TestBaseType &operator=(TestBaseType &&) = delete; - TestBaseType &operator=(const TestBaseType &) = delete; + const TestBaseType &constMe() const { return *this; } - virtual ~TestBaseType() = default; - virtual int func() { return 0; } + int val; + const int const_val; + const int *const_val_ptr = &const_val; - int base_only_func() { return -9; } + const int *get_const_val_ptr() { return const_val_ptr; } - const TestBaseType &constMe() const { return *this; } - - int val; - const int const_val; - const int *const_val_ptr = &const_val; - - const int *get_const_val_ptr() { - return const_val_ptr; - } - - int mdarray[2][3][5]; - std::function func_member; - - void set_string_val(std::string &t_str) - { - t_str = "42"; - } + int mdarray[2][3][5]; + std::function func_member; + void set_string_val(std::string &t_str) { t_str = "42"; } }; -class Type2 -{ - public: - Type2(TestBaseType t_bt) - : m_bt(std::move(t_bt)), - m_str("Hello World") - { - } +class Type2 { +public: + Type2(TestBaseType t_bt) + : m_bt(std::move(t_bt)) + , m_str("Hello World") { + } - int get_val() const - { - return m_bt.val; - } + int get_val() const { return m_bt.val; } + const char *get_str() const { return m_str.c_str(); } - const char *get_str() const - { - return m_str.c_str(); - } - - private: - TestBaseType m_bt; - std::string m_str; +private: + TestBaseType m_bt; + std::string m_str; }; -enum TestEnum -{ +enum TestEnum { TestValue1 = 1 }; -int to_int(TestEnum t) -{ +int to_int(TestEnum t) { return t; } -class TestDerivedType : public TestBaseType -{ - public: - int func() override { return 1; } - int derived_only_func() { return 19; } - +class TestDerivedType : public TestBaseType { +public: + int func() override { return 1; } + int derived_only_func() { return 19; } }; -class TestMoreDerivedType : public TestDerivedType -{ - public: +class TestMoreDerivedType : public TestDerivedType { +public: }; -std::shared_ptr derived_type_factory() -{ +std::shared_ptr derived_type_factory() { return std::make_shared(); } -std::shared_ptr more_derived_type_factory() -{ +std::shared_ptr more_derived_type_factory() { return std::make_shared(); } -std::shared_ptr null_factory() -{ +std::shared_ptr null_factory() { return std::shared_ptr(); } -void update_shared_ptr(std::shared_ptr &ptr) -{ +void update_shared_ptr(std::shared_ptr &ptr) { ptr = std::make_shared(); } -void nullify_shared_ptr(std::shared_ptr &ptr) -{ +void nullify_shared_ptr(std::shared_ptr &ptr) { ptr = nullptr; } -std::string hello_world() -{ +std::string hello_world() { return "Hello World"; } static int global_i = 1; -int *get_new_int() -{ +int *get_new_int() { return &global_i; } @@ -150,8 +133,7 @@ int *get_new_int() #pragma clang diagnostic ignored "-Wreturn-type-c-linkage" #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()); 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"); m->add(chaiscript::user_type(), "Type2"); - m->add(chaiscript::constructor(), "TestBaseType"); -// m->add(chaiscript::constructor(), "TestBaseType"); - m->add(chaiscript::constructor(), "TestBaseType"); - m->add(chaiscript::constructor(), "TestBaseType"); + m->add(chaiscript::constructor(), "TestBaseType"); + // m->add(chaiscript::constructor(), "TestBaseType"); + m->add(chaiscript::constructor(), "TestBaseType"); + m->add(chaiscript::constructor(), "TestBaseType"); - m->add(chaiscript::constructor(), "TestDerivedType"); - m->add(chaiscript::constructor(), "TestDerivedType"); + m->add(chaiscript::constructor(), "TestDerivedType"); + m->add(chaiscript::constructor(), "TestDerivedType"); - m->add(chaiscript::constructor(), "TestMoreDerivedType"); - m->add(chaiscript::constructor(), "TestMoreDerivedType"); + m->add(chaiscript::constructor(), "TestMoreDerivedType"); + m->add(chaiscript::constructor(), "TestMoreDerivedType"); /// \todo automatic chaining of base classes? m->add(chaiscript::base_class()); @@ -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(&get_new_int), "get_new_int"); - m->add_global_const(chaiscript::const_var(TestValue1), "TestValue1"); m->add(chaiscript::user_type(), "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_str), "get_str"); m->add(chaiscript::type_conversion()); - m->add(chaiscript::constructor(), "Type2"); + m->add(chaiscript::constructor(), "Type2"); m->add(chaiscript::fun(&update_shared_ptr), "update_shared_ptr"); m->add(chaiscript::fun(&nullify_shared_ptr), "nullify_shared_ptr"); - return m; } - #ifdef __llvm__ #pragma clang diagnostic pop #endif diff --git a/static_libs/chaiscript_parser.cpp b/static_libs/chaiscript_parser.cpp index 15199bf3..e8a780a6 100644 --- a/static_libs/chaiscript_parser.cpp +++ b/static_libs/chaiscript_parser.cpp @@ -1,8 +1,6 @@ #include "../include/chaiscript/language/chaiscript_parser.hpp" #include "chaiscript_parser.hpp" -std::unique_ptr create_chaiscript_parser() -{ +std::unique_ptr create_chaiscript_parser() { return std::make_unique>(); } - diff --git a/static_libs/chaiscript_parser.hpp b/static_libs/chaiscript_parser.hpp index 6086749d..c463ae29 100644 --- a/static_libs/chaiscript_parser.hpp +++ b/static_libs/chaiscript_parser.hpp @@ -2,11 +2,13 @@ #ifndef CHAISCRIPT_PARSER_LIB #define CHAISCRIPT_PARSER_LIB +#include + namespace chaiscript { namespace parser { class ChaiScript_Parser_Base; } -} +} // namespace chaiscript std::unique_ptr create_chaiscript_parser(); diff --git a/static_libs/chaiscript_stdlib.cpp b/static_libs/chaiscript_stdlib.cpp index c786ece8..8c99a768 100644 --- a/static_libs/chaiscript_stdlib.cpp +++ b/static_libs/chaiscript_stdlib.cpp @@ -1,8 +1,6 @@ #include "../include/chaiscript/chaiscript_stdlib.hpp" #include "chaiscript_stdlib.hpp" -std::shared_ptr create_chaiscript_stdlib() -{ +std::shared_ptr create_chaiscript_stdlib() { return chaiscript::Std_Lib::library(); } - diff --git a/unittests/boxed_cast_test.cpp b/unittests/boxed_cast_test.cpp index ec7baeae..2f9261e6 100644 --- a/unittests/boxed_cast_test.cpp +++ b/unittests/boxed_cast_test.cpp @@ -1,15 +1,13 @@ #include - using namespace chaiscript; - template -void use(T){} +void use(T) { +} template -bool run_test_type_conversion(const Boxed_Value &bv, bool expectedpass) -{ +bool run_test_type_conversion(const Boxed_Value &bv, bool expectedpass) { try { To ret = chaiscript::boxed_cast(bv); use(ret); @@ -26,36 +24,52 @@ bool run_test_type_conversion(const Boxed_Value &bv, bool expectedpass) std::cerr << "Unexpected unknown exception when attempting cast_conversion.\n"; return false; } - + return expectedpass; } template -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(bv, expectedpass); - if (!ret) - { - std::cerr << "Error with type conversion test. From: " - << (bv.is_const()?(std::string("const ")):(std::string())) << bv.get_type_info().name() - << " To: " - << (std::is_const::value?(std::string("const ")):(std::string())) << typeid(To).name() - << " test was expected to " << ((expectedpass)?(std::string("succeed")):(std::string("fail"))) << " but did not\n"; + if (!ret) { + std::cerr << "Error with type conversion test. From: " << (bv.is_const() ? "const " : "") + << bv.get_type_info().name() << " To: " << (std::is_const::value ? "const " : "") + << typeid(To).name() << " test was expected to " << (expectedpass ? "succeed" : "fail") + << " but did not\n"; } return ret; } template -bool do_test(const Boxed_Value &bv, - bool T, bool ConstT, bool TRef, bool ConstTRef, bool TPtr, - 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 do_test(const Boxed_Value &bv, + bool T, + bool ConstT, + bool TRef, + bool ConstTRef, + bool TPtr, + 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; passed &= test_type_conversion(bv, T); passed &= test_type_conversion(bv, ConstT); @@ -63,22 +77,22 @@ bool do_test(const Boxed_Value &bv, passed &= test_type_conversion(bv, ConstTRef); passed &= test_type_conversion(bv, TPtr); passed &= test_type_conversion(bv, ConstTPtr); - passed &= test_type_conversion(bv, TPtrConst); - passed &= test_type_conversion(bv, ConstTPtrConst); - passed &= test_type_conversion >(bv, SharedPtrT); - passed &= test_type_conversion >(bv, SharedConstPtrT); + passed &= test_type_conversion(bv, TPtrConst); + passed &= test_type_conversion(bv, ConstTPtrConst); + passed &= test_type_conversion>(bv, SharedPtrT); + passed &= test_type_conversion>(bv, SharedConstPtrT); passed &= test_type_conversion &>(bv, SharedPtrTRef); - //passed &= test_type_conversion &>(bv, false); - passed &= test_type_conversion >(bv, ConstSharedPtrT); - passed &= test_type_conversion >(bv, ConstSharedConstPtrT); + // passed &= test_type_conversion &>(bv, false); + passed &= test_type_conversion>(bv, ConstSharedPtrT); + passed &= test_type_conversion>(bv, ConstSharedConstPtrT); passed &= test_type_conversion &>(bv, ConstSharedPtrTRef); passed &= test_type_conversion &>(bv, ConstSharedPtrTConstRef); - passed &= test_type_conversion >(bv, WrappedRef); - passed &= test_type_conversion >(bv, WrappedConstRef); + passed &= test_type_conversion>(bv, WrappedRef); + passed &= test_type_conversion>(bv, WrappedConstRef); passed &= test_type_conversion &>(bv, false); passed &= test_type_conversion &>(bv, false); - passed &= test_type_conversion >(bv, ConstWrappedRef); - passed &= test_type_conversion >(bv, ConstWrappedConstRef); + passed &= test_type_conversion>(bv, ConstWrappedRef); + passed &= test_type_conversion>(bv, ConstWrappedConstRef); passed &= test_type_conversion &>(bv, ConstWrappedRefRef); passed &= test_type_conversion &>(bv, ConstWrappedConstRefRef); passed &= test_type_conversion(bv, Number); @@ -87,12 +101,12 @@ bool do_test(const Boxed_Value &bv, passed &= test_type_conversion(bv, ConstNumberRef); passed &= test_type_conversion(bv, false); passed &= test_type_conversion(bv, false); - passed &= test_type_conversion(bv, false); + passed &= test_type_conversion(bv, false); passed &= test_type_conversion(bv, false); passed &= test_type_conversion(bv, false); passed &= test_type_conversion(bv, false); - passed &= test_type_conversion(bv, TPtrConstRef); - passed &= test_type_conversion(bv, ConstTPtrConstRef); + passed &= test_type_conversion(bv, TPtrConstRef); + passed &= test_type_conversion(bv, ConstTPtrConstRef); passed &= test_type_conversion(bv, true); passed &= test_type_conversion(bv, true); passed &= test_type_conversion(bv, true); @@ -102,154 +116,524 @@ bool do_test(const Boxed_Value &bv, /** Tests intended for built int types **/ template -bool built_in_type_test(const T &initial, bool ispod) -{ +bool built_in_type_test(const T &initial, bool ispod) { bool passed = true; /** value tests **/ T i = T(initial); - passed &= do_test(var(i), true, 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(var(i), + true, + 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(const_var(i), true, true, false, 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(const_var(i), + true, + true, + false, + 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(var(&i), true, 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(var(&i), + true, + 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(const_var(&i), true, true, false, 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(const_var(&i), + true, + true, + false, + 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(var(std::ref(i)), true, 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(var(std::ref(i)), + true, + 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(var(std::cref(i)), true, true, false, 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(var(std::cref(i)), + true, + true, + false, + 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 */ // This reference will be copied on input, which is expected const T &ir = i; - passed &= do_test(var(i), true, 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(var(i), + true, + 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 - passed &= do_test(var(&ir), true, true, false, 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(var(&ir), + true, + true, + false, + 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(var(std::ref(ir)), true, true, false, 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(var(std::ref(ir)), + true, + true, + false, + 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 - passed &= do_test(const_var(&ir), true, true, false, 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(const_var(&ir), + true, + true, + false, + 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(const_var(std::ref(ir)), true, true, false, 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(const_var(std::ref(ir)), + true, + true, + false, + 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 */ // This will always be seen as a const - const T*cip = &i; - passed &= do_test(var(cip), true, true, false, true, false, - true, false, true, false, false, - false, false, false, false, false, false, - true, false, true, false, true, - ispod, ispod, ispod, false, true); + const T *cip = &i; + passed &= do_test(var(cip), + true, + true, + false, + 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 - passed &= do_test(const_var(cip), true, true, false, 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(const_var(cip), + true, + true, + false, + 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 **/ auto ip = std::make_shared(initial); - passed &= do_test(var(ip), true, 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(var(ip), + true, + 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(const_var(ip), true, true, false, 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(const_var(ip), + true, + true, + false, + 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 **/ auto ipc = std::make_shared(T(initial)); - passed &= do_test(var(ipc), true, true, false, 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(var(ipc), + true, + true, + false, + 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 - passed &= do_test(const_var(ipc), true, true, false, 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(const_var(ipc), + true, + true, + false, + 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 **/ /* - T **doublep; + T **doublep; - passed &= do_test(var(doublep), true, true, false, true, false, - true, false, true, false, true, - false, true, false, true, false, - true, false, true, false, true, - ispod, ispod, ispod, false, true); -*/ + passed &= do_test(var(doublep), true, true, false, true, false, + true, false, true, false, true, + false, true, false, true, false, + true, false, true, false, true, + ispod, ispod, ispod, false, true); + */ return passed; } - template -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); // 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(var(&p)); *(*result) = new_value; - - if (p != (*result) ) { + if (p != (*result)) { std::cerr << "Pointer passed in different than one returned\n"; delete p; return false; } - if (*p != *(*result) ) { + if (*p != *(*result)) { std::cerr << "Somehow dereferenced pointer values are not the same?\n"; delete p; return false; @@ -283,18 +666,16 @@ bool pointer_test(const T& default_value, const T& new_value) } } - -int main() -{ +int main() { bool passed = true; /* - bool T, bool ConstT, bool TRef, bool ConstTRef, bool TPtr, - bool ConstTPtr, bool TPtrConst, bool ConstTPtrConst, bool SharedPtrT, bool SharedConstPtrT, - 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 T, bool ConstT, bool TRef, bool ConstTRef, bool TPtr, + bool ConstTPtr, bool TPtrConst, bool ConstTPtrConst, bool SharedPtrT, bool SharedConstPtrT, + 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 + */ passed &= built_in_type_test(5, true); passed &= built_in_type_test(1.1, true); @@ -303,8 +684,8 @@ int main() passed &= built_in_type_test('a', true); passed &= built_in_type_test(false, false); passed &= built_in_type_test("Hello World", false); - - // storing a pointer + + // storing a pointer passed &= pointer_test(1, 0); if (passed) { diff --git a/unittests/c_linkage_test.cpp b/unittests/c_linkage_test.cpp index 180686af..f4ef9f77 100644 --- a/unittests/c_linkage_test.cpp +++ b/unittests/c_linkage_test.cpp @@ -1,21 +1,16 @@ -#include #include "../static_libs/chaiscript_parser.hpp" #include "../static_libs/chaiscript_stdlib.hpp" +#include - -extern "C" -{ - int do_something(int i) - { - return i % 2; - } +extern "C" { +int do_something(int i) { + return i % 2; +} } -int main() -{ - chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser()); +int main() { + chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(), create_chaiscript_parser()); chai.add(chaiscript::fun(&do_something), "do_something"); - return chai.eval("do_something(101)") == 101 % 2?EXIT_SUCCESS:EXIT_FAILURE; - + return chai.eval("do_something(101)") == 101 % 2 ? EXIT_SUCCESS : EXIT_FAILURE; } diff --git a/unittests/catch.hpp b/unittests/catch.hpp index 36eaeb27..2e78ece8 100644 --- a/unittests/catch.hpp +++ b/unittests/catch.hpp @@ -12,55 +12,54 @@ #define TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED // start catch.hpp - #define CATCH_VERSION_MAJOR 2 #define CATCH_VERSION_MINOR 13 #define CATCH_VERSION_PATCH 6 #ifdef __clang__ -# pragma clang system_header +#pragma clang system_header #elif defined __GNUC__ -# pragma GCC system_header +#pragma GCC system_header #endif // start catch_suppress_warnings.h #ifdef __clang__ -# ifdef __ICC // icpc defines the __clang__ macro -# pragma warning(push) -# pragma warning(disable: 161 1682) -# else // __ICC -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wpadded" -# pragma clang diagnostic ignored "-Wswitch-enum" -# pragma clang diagnostic ignored "-Wcovered-switch-default" -# endif +#ifdef __ICC // icpc defines the __clang__ macro +#pragma warning(push) +#pragma warning(disable : 161 1682) +#else // __ICC +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wpadded" +#pragma clang diagnostic ignored "-Wswitch-enum" +#pragma clang diagnostic ignored "-Wcovered-switch-default" +#endif #elif defined __GNUC__ - // Because REQUIREs trigger GCC's -Wparentheses, and because still - // supported version of g++ have only buggy support for _Pragmas, - // Wparentheses have to be suppressed globally. -# pragma GCC diagnostic ignored "-Wparentheses" // See #674 for details +// Because REQUIREs trigger GCC's -Wparentheses, and because still +// supported version of g++ have only buggy support for _Pragmas, +// Wparentheses have to be suppressed globally. +#pragma GCC diagnostic ignored "-Wparentheses" // See #674 for details -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wunused-variable" -# pragma GCC diagnostic ignored "-Wpadded" +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wpadded" #endif // end catch_suppress_warnings.h #if defined(CATCH_CONFIG_MAIN) || defined(CATCH_CONFIG_RUNNER) -# define CATCH_IMPL -# define CATCH_CONFIG_ALL_PARTS +#define CATCH_IMPL +#define CATCH_CONFIG_ALL_PARTS #endif // In the impl file, we want to have access to all parts of the headers // Can also be used to sanely support PCHs #if defined(CATCH_CONFIG_ALL_PARTS) -# define CATCH_CONFIG_EXTERNAL_INTERFACES -# if defined(CATCH_CONFIG_DISABLE_MATCHERS) -# undef CATCH_CONFIG_DISABLE_MATCHERS -# endif -# if !defined(CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER) -# define CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER -# endif +#define CATCH_CONFIG_EXTERNAL_INTERFACES +#if defined(CATCH_CONFIG_DISABLE_MATCHERS) +#undef CATCH_CONFIG_DISABLE_MATCHERS +#endif +#if !defined(CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER) +#define CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER +#endif #endif #if !defined(CATCH_CONFIG_IMPL_ONLY) @@ -69,34 +68,33 @@ // See e.g.: // https://opensource.apple.com/source/CarbonHeaders/CarbonHeaders-18.1/TargetConditionals.h.auto.html #ifdef __APPLE__ -# include -# if (defined(TARGET_OS_OSX) && TARGET_OS_OSX == 1) || \ - (defined(TARGET_OS_MAC) && TARGET_OS_MAC == 1) -# define CATCH_PLATFORM_MAC -# elif (defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE == 1) -# define CATCH_PLATFORM_IPHONE -# endif +#include +#if (defined(TARGET_OS_OSX) && TARGET_OS_OSX == 1) || (defined(TARGET_OS_MAC) && TARGET_OS_MAC == 1) +#define CATCH_PLATFORM_MAC +#elif (defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE == 1) +#define CATCH_PLATFORM_IPHONE +#endif #elif defined(linux) || defined(__linux) || defined(__linux__) -# define CATCH_PLATFORM_LINUX +#define CATCH_PLATFORM_LINUX #elif defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) || defined(__MINGW32__) -# define CATCH_PLATFORM_WINDOWS +#define CATCH_PLATFORM_WINDOWS #endif // end catch_platform.h #ifdef CATCH_IMPL -# ifndef CLARA_CONFIG_MAIN -# define CLARA_CONFIG_MAIN_NOT_DEFINED -# define CLARA_CONFIG_MAIN -# endif +#ifndef CLARA_CONFIG_MAIN +#define CLARA_CONFIG_MAIN_NOT_DEFINED +#define CLARA_CONFIG_MAIN +#endif #endif // start catch_user_interfaces.h namespace Catch { - unsigned int rngSeed(); + unsigned int rngSeed(); } // end catch_user_interfaces.h @@ -125,30 +123,30 @@ namespace Catch { #ifdef __cplusplus -# if (__cplusplus >= 201402L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201402L) -# define CATCH_CPP14_OR_GREATER -# endif +#if (__cplusplus >= 201402L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201402L) +#define CATCH_CPP14_OR_GREATER +#endif -# if (__cplusplus >= 201703L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) -# define CATCH_CPP17_OR_GREATER -# endif +#if (__cplusplus >= 201703L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) +#define CATCH_CPP17_OR_GREATER +#endif #endif // Only GCC compiler should be used in this block, so other compilers trying to // mask themselves as GCC should be ignored. #if defined(__GNUC__) && !defined(__clang__) && !defined(__ICC) && !defined(__CUDACC__) && !defined(__LCC__) -# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic push" ) -# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic pop" ) +#define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma("GCC diagnostic push") +#define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma("GCC diagnostic pop") -# define CATCH_INTERNAL_IGNORE_BUT_WARN(...) (void)__builtin_constant_p(__VA_ARGS__) +#define CATCH_INTERNAL_IGNORE_BUT_WARN(...) (void)__builtin_constant_p(__VA_ARGS__) #endif #if defined(__clang__) -# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "clang diagnostic push" ) -# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "clang diagnostic pop" ) +#define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma("clang diagnostic push") +#define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma("clang diagnostic pop") // As of this writing, IBM XL's implementation of __builtin_constant_p has a bug // which results in calls to destructors being emitted for each temporary, @@ -161,62 +159,58 @@ namespace Catch { // ``` // // Therefore, `CATCH_INTERNAL_IGNORE_BUT_WARN` is not implemented. -# if !defined(__ibmxl__) && !defined(__CUDACC__) -# define CATCH_INTERNAL_IGNORE_BUT_WARN(...) (void)__builtin_constant_p(__VA_ARGS__) /* NOLINT(cppcoreguidelines-pro-type-vararg, hicpp-vararg) */ -# endif +#if !defined(__ibmxl__) && !defined(__CUDACC__) +#define CATCH_INTERNAL_IGNORE_BUT_WARN(...) \ + (void)__builtin_constant_p(__VA_ARGS__) /* NOLINT(cppcoreguidelines-pro-type-vararg, hicpp-vararg) */ +#endif -# define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ - _Pragma( "clang diagnostic ignored \"-Wexit-time-destructors\"" ) \ - _Pragma( "clang diagnostic ignored \"-Wglobal-constructors\"") +#define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ + _Pragma("clang diagnostic ignored \"-Wexit-time-destructors\"") _Pragma("clang diagnostic ignored \"-Wglobal-constructors\"") -# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ - _Pragma( "clang diagnostic ignored \"-Wparentheses\"" ) +#define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS _Pragma("clang diagnostic ignored \"-Wparentheses\"") -# define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS \ - _Pragma( "clang diagnostic ignored \"-Wunused-variable\"" ) +#define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS _Pragma("clang diagnostic ignored \"-Wunused-variable\"") -# define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \ - _Pragma( "clang diagnostic ignored \"-Wgnu-zero-variadic-macro-arguments\"" ) +#define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS _Pragma("clang diagnostic ignored \"-Wgnu-zero-variadic-macro-arguments\"") -# define CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \ - _Pragma( "clang diagnostic ignored \"-Wunused-template\"" ) +#define CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS _Pragma("clang diagnostic ignored \"-Wunused-template\"") #endif // __clang__ //////////////////////////////////////////////////////////////////////////////// // Assume that non-Windows platforms support posix signals by default #if !defined(CATCH_PLATFORM_WINDOWS) - #define CATCH_INTERNAL_CONFIG_POSIX_SIGNALS +#define CATCH_INTERNAL_CONFIG_POSIX_SIGNALS #endif //////////////////////////////////////////////////////////////////////////////// // We know some environments not to support full POSIX signals #if defined(__CYGWIN__) || defined(__QNX__) || defined(__EMSCRIPTEN__) || defined(__DJGPP__) - #define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS +#define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS #endif #ifdef __OS400__ -# define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS -# define CATCH_CONFIG_COLOUR_NONE +#define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS +#define CATCH_CONFIG_COLOUR_NONE #endif //////////////////////////////////////////////////////////////////////////////// // Android somehow still does not support std::to_string #if defined(__ANDROID__) -# define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING -# define CATCH_INTERNAL_CONFIG_ANDROID_LOGWRITE +#define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING +#define CATCH_INTERNAL_CONFIG_ANDROID_LOGWRITE #endif //////////////////////////////////////////////////////////////////////////////// // Not all Windows environments support SEH properly #if defined(__MINGW32__) -# define CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH +#define CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH #endif //////////////////////////////////////////////////////////////////////////////// // PS4 #if defined(__ORBIS__) -# define CATCH_INTERNAL_CONFIG_NO_NEW_CAPTURE +#define CATCH_INTERNAL_CONFIG_NO_NEW_CAPTURE #endif //////////////////////////////////////////////////////////////////////////////// @@ -225,64 +219,63 @@ namespace Catch { // Required for some versions of Cygwin to declare gettimeofday // see: http://stackoverflow.com/questions/36901803/gettimeofday-not-declared-in-this-scope-cygwin -# define _BSD_SOURCE +#define _BSD_SOURCE // some versions of cygwin (most) do not support std::to_string. Use the libstd check. // https://gcc.gnu.org/onlinedocs/gcc-4.8.2/libstdc++/api/a01053_source.html line 2812-2813 -# if !((__cplusplus >= 201103L) && defined(_GLIBCXX_USE_C99) \ - && !defined(_GLIBCXX_HAVE_BROKEN_VSWPRINTF)) +#if !((__cplusplus >= 201103L) && defined(_GLIBCXX_USE_C99) && !defined(_GLIBCXX_HAVE_BROKEN_VSWPRINTF)) -# define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING +#define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING -# endif +#endif #endif // __CYGWIN__ //////////////////////////////////////////////////////////////////////////////// // Visual C++ #if defined(_MSC_VER) -# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION __pragma( warning(push) ) -# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION __pragma( warning(pop) ) +#define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION __pragma(warning(push)) +#define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION __pragma(warning(pop)) // Universal Windows platform does not support SEH // Or console colours (or console at all...) -# if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP) -# define CATCH_CONFIG_COLOUR_NONE -# else -# define CATCH_INTERNAL_CONFIG_WINDOWS_SEH -# endif +#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP) +#define CATCH_CONFIG_COLOUR_NONE +#else +#define CATCH_INTERNAL_CONFIG_WINDOWS_SEH +#endif // MSVC traditional preprocessor needs some workaround for __VA_ARGS__ // _MSVC_TRADITIONAL == 0 means new conformant preprocessor // _MSVC_TRADITIONAL == 1 means old traditional non-conformant preprocessor -# if !defined(__clang__) // Handle Clang masquerading for msvc -# if !defined(_MSVC_TRADITIONAL) || (defined(_MSVC_TRADITIONAL) && _MSVC_TRADITIONAL) -# define CATCH_INTERNAL_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR -# endif // MSVC_TRADITIONAL -# endif // __clang__ +#if !defined(__clang__) // Handle Clang masquerading for msvc +#if !defined(_MSVC_TRADITIONAL) || (defined(_MSVC_TRADITIONAL) && _MSVC_TRADITIONAL) +#define CATCH_INTERNAL_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR +#endif // MSVC_TRADITIONAL +#endif // __clang__ #endif // _MSC_VER #if defined(_REENTRANT) || defined(_MSC_VER) // Enable async processing, as -pthread is specified or no additional linking is required -# define CATCH_INTERNAL_CONFIG_USE_ASYNC +#define CATCH_INTERNAL_CONFIG_USE_ASYNC #endif // _MSC_VER //////////////////////////////////////////////////////////////////////////////// // Check if we are compiled with -fno-exceptions or equivalent #if defined(__EXCEPTIONS) || defined(__cpp_exceptions) || defined(_CPPUNWIND) -# define CATCH_INTERNAL_CONFIG_EXCEPTIONS_ENABLED +#define CATCH_INTERNAL_CONFIG_EXCEPTIONS_ENABLED #endif //////////////////////////////////////////////////////////////////////////////// // DJGPP #ifdef __DJGPP__ -# define CATCH_INTERNAL_CONFIG_NO_WCHAR +#define CATCH_INTERNAL_CONFIG_NO_WCHAR #endif // __DJGPP__ //////////////////////////////////////////////////////////////////////////////// // Embarcadero C++Build #if defined(__BORLANDC__) - #define CATCH_INTERNAL_CONFIG_POLYFILL_ISNAN +#define CATCH_INTERNAL_CONFIG_POLYFILL_ISNAN #endif //////////////////////////////////////////////////////////////////////////////// @@ -292,8 +285,8 @@ namespace Catch { // handled by it. // Otherwise all supported compilers support COUNTER macro, // but user still might want to turn it off -#if ( !defined(__JETBRAINS_IDE__) || __JETBRAINS_IDE__ >= 20170300L ) - #define CATCH_INTERNAL_CONFIG_COUNTER +#if (!defined(__JETBRAINS_IDE__) || __JETBRAINS_IDE__ >= 20170300L) +#define CATCH_INTERNAL_CONFIG_COUNTER #endif //////////////////////////////////////////////////////////////////////////////// @@ -302,9 +295,9 @@ namespace Catch { // This means that it is detected as Windows, but does not provide // the same set of capabilities as real Windows does. #if defined(UNDER_RTSS) || defined(RTX64_BUILD) - #define CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH - #define CATCH_INTERNAL_CONFIG_NO_ASYNC - #define CATCH_CONFIG_COLOUR_NONE +#define CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH +#define CATCH_INTERNAL_CONFIG_NO_ASYNC +#define CATCH_CONFIG_COLOUR_NONE #endif #if !defined(_GLIBCXX_USE_C99_MATH_TR1) @@ -313,139 +306,147 @@ namespace Catch { // Various stdlib support checks that require __has_include #if defined(__has_include) - // Check if string_view is available and usable - #if __has_include() && defined(CATCH_CPP17_OR_GREATER) - # define CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW - #endif +// Check if string_view is available and usable +#if __has_include() && defined(CATCH_CPP17_OR_GREATER) +#define CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW +#endif - // Check if optional is available and usable - # if __has_include() && defined(CATCH_CPP17_OR_GREATER) - # define CATCH_INTERNAL_CONFIG_CPP17_OPTIONAL - # endif // __has_include() && defined(CATCH_CPP17_OR_GREATER) +// Check if optional is available and usable +#if __has_include() && defined(CATCH_CPP17_OR_GREATER) +#define CATCH_INTERNAL_CONFIG_CPP17_OPTIONAL +#endif // __has_include() && defined(CATCH_CPP17_OR_GREATER) - // Check if byte is available and usable - # if __has_include() && defined(CATCH_CPP17_OR_GREATER) - # include - # if __cpp_lib_byte > 0 - # define CATCH_INTERNAL_CONFIG_CPP17_BYTE - # endif - # endif // __has_include() && defined(CATCH_CPP17_OR_GREATER) +// Check if byte is available and usable +#if __has_include() && defined(CATCH_CPP17_OR_GREATER) +#include +#if __cpp_lib_byte > 0 +#define CATCH_INTERNAL_CONFIG_CPP17_BYTE +#endif +#endif // __has_include() && defined(CATCH_CPP17_OR_GREATER) - // Check if variant is available and usable - # if __has_include() && defined(CATCH_CPP17_OR_GREATER) - # if defined(__clang__) && (__clang_major__ < 8) - // work around clang bug with libstdc++ https://bugs.llvm.org/show_bug.cgi?id=31852 - // fix should be in clang 8, workaround in libstdc++ 8.2 - # include - # if defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9) - # define CATCH_CONFIG_NO_CPP17_VARIANT - # else - # define CATCH_INTERNAL_CONFIG_CPP17_VARIANT - # endif // defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9) - # else - # define CATCH_INTERNAL_CONFIG_CPP17_VARIANT - # endif // defined(__clang__) && (__clang_major__ < 8) - # endif // __has_include() && defined(CATCH_CPP17_OR_GREATER) +// Check if variant is available and usable +#if __has_include() && defined(CATCH_CPP17_OR_GREATER) +#if defined(__clang__) && (__clang_major__ < 8) +// work around clang bug with libstdc++ https://bugs.llvm.org/show_bug.cgi?id=31852 +// fix should be in clang 8, workaround in libstdc++ 8.2 +#include +#if defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9) +#define CATCH_CONFIG_NO_CPP17_VARIANT +#else +#define CATCH_INTERNAL_CONFIG_CPP17_VARIANT +#endif // defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9) +#else +#define CATCH_INTERNAL_CONFIG_CPP17_VARIANT +#endif // defined(__clang__) && (__clang_major__ < 8) +#endif // __has_include() && defined(CATCH_CPP17_OR_GREATER) #endif // defined(__has_include) #if defined(CATCH_INTERNAL_CONFIG_COUNTER) && !defined(CATCH_CONFIG_NO_COUNTER) && !defined(CATCH_CONFIG_COUNTER) -# define CATCH_CONFIG_COUNTER +#define CATCH_CONFIG_COUNTER #endif -#if defined(CATCH_INTERNAL_CONFIG_WINDOWS_SEH) && !defined(CATCH_CONFIG_NO_WINDOWS_SEH) && !defined(CATCH_CONFIG_WINDOWS_SEH) && !defined(CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH) -# define CATCH_CONFIG_WINDOWS_SEH +#if defined(CATCH_INTERNAL_CONFIG_WINDOWS_SEH) && !defined(CATCH_CONFIG_NO_WINDOWS_SEH) && !defined(CATCH_CONFIG_WINDOWS_SEH) \ + && !defined(CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH) +#define CATCH_CONFIG_WINDOWS_SEH #endif // This is set by default, because we assume that unix compilers are posix-signal-compatible by default. -#if defined(CATCH_INTERNAL_CONFIG_POSIX_SIGNALS) && !defined(CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_POSIX_SIGNALS) -# define CATCH_CONFIG_POSIX_SIGNALS +#if defined(CATCH_INTERNAL_CONFIG_POSIX_SIGNALS) && !defined(CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS) \ + && !defined(CATCH_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_POSIX_SIGNALS) +#define CATCH_CONFIG_POSIX_SIGNALS #endif // This is set by default, because we assume that compilers with no wchar_t support are just rare exceptions. #if !defined(CATCH_INTERNAL_CONFIG_NO_WCHAR) && !defined(CATCH_CONFIG_NO_WCHAR) && !defined(CATCH_CONFIG_WCHAR) -# define CATCH_CONFIG_WCHAR +#define CATCH_CONFIG_WCHAR #endif -#if !defined(CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING) && !defined(CATCH_CONFIG_NO_CPP11_TO_STRING) && !defined(CATCH_CONFIG_CPP11_TO_STRING) -# define CATCH_CONFIG_CPP11_TO_STRING +#if !defined(CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING) && !defined(CATCH_CONFIG_NO_CPP11_TO_STRING) \ + && !defined(CATCH_CONFIG_CPP11_TO_STRING) +#define CATCH_CONFIG_CPP11_TO_STRING #endif #if defined(CATCH_INTERNAL_CONFIG_CPP17_OPTIONAL) && !defined(CATCH_CONFIG_NO_CPP17_OPTIONAL) && !defined(CATCH_CONFIG_CPP17_OPTIONAL) -# define CATCH_CONFIG_CPP17_OPTIONAL +#define CATCH_CONFIG_CPP17_OPTIONAL #endif -#if defined(CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW) && !defined(CATCH_CONFIG_NO_CPP17_STRING_VIEW) && !defined(CATCH_CONFIG_CPP17_STRING_VIEW) -# define CATCH_CONFIG_CPP17_STRING_VIEW +#if defined(CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW) && !defined(CATCH_CONFIG_NO_CPP17_STRING_VIEW) \ + && !defined(CATCH_CONFIG_CPP17_STRING_VIEW) +#define CATCH_CONFIG_CPP17_STRING_VIEW #endif #if defined(CATCH_INTERNAL_CONFIG_CPP17_VARIANT) && !defined(CATCH_CONFIG_NO_CPP17_VARIANT) && !defined(CATCH_CONFIG_CPP17_VARIANT) -# define CATCH_CONFIG_CPP17_VARIANT +#define CATCH_CONFIG_CPP17_VARIANT #endif #if defined(CATCH_INTERNAL_CONFIG_CPP17_BYTE) && !defined(CATCH_CONFIG_NO_CPP17_BYTE) && !defined(CATCH_CONFIG_CPP17_BYTE) -# define CATCH_CONFIG_CPP17_BYTE +#define CATCH_CONFIG_CPP17_BYTE #endif #if defined(CATCH_CONFIG_EXPERIMENTAL_REDIRECT) -# define CATCH_INTERNAL_CONFIG_NEW_CAPTURE +#define CATCH_INTERNAL_CONFIG_NEW_CAPTURE #endif -#if defined(CATCH_INTERNAL_CONFIG_NEW_CAPTURE) && !defined(CATCH_INTERNAL_CONFIG_NO_NEW_CAPTURE) && !defined(CATCH_CONFIG_NO_NEW_CAPTURE) && !defined(CATCH_CONFIG_NEW_CAPTURE) -# define CATCH_CONFIG_NEW_CAPTURE +#if defined(CATCH_INTERNAL_CONFIG_NEW_CAPTURE) && !defined(CATCH_INTERNAL_CONFIG_NO_NEW_CAPTURE) \ + && !defined(CATCH_CONFIG_NO_NEW_CAPTURE) && !defined(CATCH_CONFIG_NEW_CAPTURE) +#define CATCH_CONFIG_NEW_CAPTURE #endif #if !defined(CATCH_INTERNAL_CONFIG_EXCEPTIONS_ENABLED) && !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) -# define CATCH_CONFIG_DISABLE_EXCEPTIONS +#define CATCH_CONFIG_DISABLE_EXCEPTIONS #endif #if defined(CATCH_INTERNAL_CONFIG_POLYFILL_ISNAN) && !defined(CATCH_CONFIG_NO_POLYFILL_ISNAN) && !defined(CATCH_CONFIG_POLYFILL_ISNAN) -# define CATCH_CONFIG_POLYFILL_ISNAN +#define CATCH_CONFIG_POLYFILL_ISNAN #endif -#if defined(CATCH_INTERNAL_CONFIG_USE_ASYNC) && !defined(CATCH_INTERNAL_CONFIG_NO_ASYNC) && !defined(CATCH_CONFIG_NO_USE_ASYNC) && !defined(CATCH_CONFIG_USE_ASYNC) -# define CATCH_CONFIG_USE_ASYNC +#if defined(CATCH_INTERNAL_CONFIG_USE_ASYNC) && !defined(CATCH_INTERNAL_CONFIG_NO_ASYNC) && !defined(CATCH_CONFIG_NO_USE_ASYNC) \ + && !defined(CATCH_CONFIG_USE_ASYNC) +#define CATCH_CONFIG_USE_ASYNC #endif -#if defined(CATCH_INTERNAL_CONFIG_ANDROID_LOGWRITE) && !defined(CATCH_CONFIG_NO_ANDROID_LOGWRITE) && !defined(CATCH_CONFIG_ANDROID_LOGWRITE) -# define CATCH_CONFIG_ANDROID_LOGWRITE +#if defined(CATCH_INTERNAL_CONFIG_ANDROID_LOGWRITE) && !defined(CATCH_CONFIG_NO_ANDROID_LOGWRITE) \ + && !defined(CATCH_CONFIG_ANDROID_LOGWRITE) +#define CATCH_CONFIG_ANDROID_LOGWRITE #endif -#if defined(CATCH_INTERNAL_CONFIG_GLOBAL_NEXTAFTER) && !defined(CATCH_CONFIG_NO_GLOBAL_NEXTAFTER) && !defined(CATCH_CONFIG_GLOBAL_NEXTAFTER) -# define CATCH_CONFIG_GLOBAL_NEXTAFTER +#if defined(CATCH_INTERNAL_CONFIG_GLOBAL_NEXTAFTER) && !defined(CATCH_CONFIG_NO_GLOBAL_NEXTAFTER) \ + && !defined(CATCH_CONFIG_GLOBAL_NEXTAFTER) +#define CATCH_CONFIG_GLOBAL_NEXTAFTER #endif // Even if we do not think the compiler has that warning, we still have // to provide a macro that can be used by the code. #if !defined(CATCH_INTERNAL_START_WARNINGS_SUPPRESSION) -# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION +#define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION #endif #if !defined(CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION) -# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION +#define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION #endif #if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS) -# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS +#define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS #endif #if !defined(CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS) -# define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS +#define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS #endif #if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS) -# define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS +#define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS #endif #if !defined(CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS) -# define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS +#define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS #endif // The goal of this macro is to avoid evaluation of the arguments, but // still have the compiler warn on problems inside... #if !defined(CATCH_INTERNAL_IGNORE_BUT_WARN) -# define CATCH_INTERNAL_IGNORE_BUT_WARN(...) +#define CATCH_INTERNAL_IGNORE_BUT_WARN(...) #endif #if defined(__APPLE__) && defined(__apple_build_version__) && (__clang_major__ < 10) -# undef CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS +#undef CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS #elif defined(__clang__) && (__clang_major__ < 5) -# undef CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS +#undef CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS #endif #if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS) -# define CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS +#define CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS #endif #if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) @@ -458,103 +459,105 @@ namespace Catch { #define CATCH_CATCH_ANON(type) catch (type) #endif -#if defined(CATCH_INTERNAL_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR) && !defined(CATCH_CONFIG_NO_TRADITIONAL_MSVC_PREPROCESSOR) && !defined(CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR) +#if defined(CATCH_INTERNAL_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR) && !defined(CATCH_CONFIG_NO_TRADITIONAL_MSVC_PREPROCESSOR) \ + && !defined(CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR) #define CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR #endif // end catch_compiler_capabilities.h -#define INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) name##line -#define INTERNAL_CATCH_UNIQUE_NAME_LINE( name, line ) INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) +#define INTERNAL_CATCH_UNIQUE_NAME_LINE2(name, line) name##line +#define INTERNAL_CATCH_UNIQUE_NAME_LINE(name, line) INTERNAL_CATCH_UNIQUE_NAME_LINE2(name, line) #ifdef CATCH_CONFIG_COUNTER -# define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __COUNTER__ ) +#define INTERNAL_CATCH_UNIQUE_NAME(name) INTERNAL_CATCH_UNIQUE_NAME_LINE(name, __COUNTER__) #else -# define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __LINE__ ) +#define INTERNAL_CATCH_UNIQUE_NAME(name) INTERNAL_CATCH_UNIQUE_NAME_LINE(name, __LINE__) #endif +#include #include #include -#include // We need a dummy global operator<< so we can bring it into Catch namespace later -struct Catch_global_namespace_dummy {}; -std::ostream& operator<<(std::ostream&, Catch_global_namespace_dummy); +struct Catch_global_namespace_dummy { +}; +std::ostream &operator<<(std::ostream &, Catch_global_namespace_dummy); namespace Catch { - - struct CaseSensitive { enum Choice { - Yes, - No - }; }; - - class NonCopyable { - NonCopyable( NonCopyable const& ) = delete; - NonCopyable( NonCopyable && ) = delete; - NonCopyable& operator = ( NonCopyable const& ) = delete; - NonCopyable& operator = ( NonCopyable && ) = delete; - - protected: - NonCopyable(); - virtual ~NonCopyable(); + struct CaseSensitive { + enum Choice { + Yes, + No }; + }; - struct SourceLineInfo { + class NonCopyable { + NonCopyable(NonCopyable const &) = delete; + NonCopyable(NonCopyable &&) = delete; + NonCopyable &operator=(NonCopyable const &) = delete; + NonCopyable &operator=(NonCopyable &&) = delete; - SourceLineInfo() = delete; - SourceLineInfo( char const* _file, std::size_t _line ) noexcept - : file( _file ), - line( _line ) - {} + protected: + NonCopyable(); + virtual ~NonCopyable(); + }; - SourceLineInfo( SourceLineInfo const& other ) = default; - SourceLineInfo& operator = ( SourceLineInfo const& ) = default; - SourceLineInfo( SourceLineInfo&& ) noexcept = default; - SourceLineInfo& operator = ( SourceLineInfo&& ) noexcept = default; - - bool empty() const noexcept { return file[0] == '\0'; } - bool operator == ( SourceLineInfo const& other ) const noexcept; - bool operator < ( SourceLineInfo const& other ) const noexcept; - - char const* file; - std::size_t line; - }; - - std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ); - - // Bring in operator<< from global namespace into Catch namespace - // This is necessary because the overload of operator<< above makes - // lookup stop at namespace Catch - using ::operator<<; - - // Use this in variadic streaming macros to allow - // >> +StreamEndStop - // as well as - // >> stuff +StreamEndStop - struct StreamEndStop { - std::string operator+() const; - }; - template - T const& operator + ( T const& value, StreamEndStop ) { - return value; + struct SourceLineInfo { + SourceLineInfo() = delete; + SourceLineInfo(char const *_file, std::size_t _line) noexcept + : file(_file) + , line(_line) { } -} -#define CATCH_INTERNAL_LINEINFO \ - ::Catch::SourceLineInfo( __FILE__, static_cast( __LINE__ ) ) + SourceLineInfo(SourceLineInfo const &other) = default; + SourceLineInfo &operator=(SourceLineInfo const &) = default; + SourceLineInfo(SourceLineInfo &&) noexcept = default; + SourceLineInfo &operator=(SourceLineInfo &&) noexcept = default; + + bool empty() const noexcept { return file[0] == '\0'; } + bool operator==(SourceLineInfo const &other) const noexcept; + bool operator<(SourceLineInfo const &other) const noexcept; + + char const *file; + std::size_t line; + }; + + std::ostream &operator<<(std::ostream &os, SourceLineInfo const &info); + + // Bring in operator<< from global namespace into Catch namespace + // This is necessary because the overload of operator<< above makes + // lookup stop at namespace Catch + using ::operator<<; + + // Use this in variadic streaming macros to allow + // >> +StreamEndStop + // as well as + // >> stuff +StreamEndStop + struct StreamEndStop { + std::string operator+() const; + }; + template + T const &operator+(T const &value, StreamEndStop) { + return value; + } +} // namespace Catch + +#define CATCH_INTERNAL_LINEINFO ::Catch::SourceLineInfo(__FILE__, static_cast(__LINE__)) // end catch_common.h namespace Catch { - - struct RegistrarForTagAliases { - RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo ); - }; + struct RegistrarForTagAliases { + RegistrarForTagAliases(char const *alias, char const *tag, SourceLineInfo const &lineInfo); + }; } // end namespace Catch -#define CATCH_REGISTER_TAG_ALIAS( alias, spec ) \ - CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ - CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ - namespace{ Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME( AutoRegisterTagAlias )( alias, spec, CATCH_INTERNAL_LINEINFO ); } \ - CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION +#define CATCH_REGISTER_TAG_ALIAS(alias, spec) \ + CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ + CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ + namespace { \ + Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME(AutoRegisterTagAlias)(alias, spec, CATCH_INTERNAL_LINEINFO); \ + } \ + CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION // end catch_tag_alias_autoregistrar.h // start catch_test_registry.h @@ -564,130 +567,117 @@ namespace Catch { #include namespace Catch { + class TestSpec; - class TestSpec; + struct ITestInvoker { + virtual void invoke() const = 0; + virtual ~ITestInvoker(); + }; - struct ITestInvoker { - virtual void invoke () const = 0; - virtual ~ITestInvoker(); - }; + class TestCase; + struct IConfig; - class TestCase; - struct IConfig; + struct ITestCaseRegistry { + virtual ~ITestCaseRegistry(); + virtual std::vector const &getAllTests() const = 0; + virtual std::vector const &getAllTestsSorted(IConfig const &config) const = 0; + }; - struct ITestCaseRegistry { - virtual ~ITestCaseRegistry(); - virtual std::vector const& getAllTests() const = 0; - virtual std::vector const& getAllTestsSorted( IConfig const& config ) const = 0; - }; + bool isThrowSafe(TestCase const &testCase, IConfig const &config); + bool matchTest(TestCase const &testCase, TestSpec const &testSpec, IConfig const &config); + std::vector filterTests(std::vector const &testCases, TestSpec const &testSpec, IConfig const &config); + std::vector const &getAllTestCasesSorted(IConfig const &config); - bool isThrowSafe( TestCase const& testCase, IConfig const& config ); - bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ); - std::vector filterTests( std::vector const& testCases, TestSpec const& testSpec, IConfig const& config ); - std::vector const& getAllTestCasesSorted( IConfig const& config ); - -} +} // namespace Catch // end catch_interfaces_testcase.h // start catch_stringref.h -#include -#include -#include #include +#include +#include +#include namespace Catch { + /// A non-owning string class (similar to the forthcoming std::string_view) + /// Note that, because a StringRef may be a substring of another string, + /// it may not be null terminated. + class StringRef { + public: + using size_type = std::size_t; + using const_iterator = const char *; - /// A non-owning string class (similar to the forthcoming std::string_view) - /// Note that, because a StringRef may be a substring of another string, - /// it may not be null terminated. - class StringRef { - public: - using size_type = std::size_t; - using const_iterator = const char*; + private: + static constexpr char const *const s_empty = ""; - private: - static constexpr char const* const s_empty = ""; + char const *m_start = s_empty; + size_type m_size = 0; - char const* m_start = s_empty; - size_type m_size = 0; + public: // construction + constexpr StringRef() noexcept = default; - public: // construction - constexpr StringRef() noexcept = default; + StringRef(char const *rawChars) noexcept; - StringRef( char const* rawChars ) noexcept; - - constexpr StringRef( char const* rawChars, size_type size ) noexcept - : m_start( rawChars ), - m_size( size ) - {} - - StringRef( std::string const& stdString ) noexcept - : m_start( stdString.c_str() ), - m_size( stdString.size() ) - {} - - explicit operator std::string() const { - return std::string(m_start, m_size); - } - - public: // operators - auto operator == ( StringRef const& other ) const noexcept -> bool; - auto operator != (StringRef const& other) const noexcept -> bool { - return !(*this == other); - } - - auto operator[] ( size_type index ) const noexcept -> char { - assert(index < m_size); - return m_start[index]; - } - - public: // named queries - constexpr auto empty() const noexcept -> bool { - return m_size == 0; - } - constexpr auto size() const noexcept -> size_type { - return m_size; - } - - // Returns the current start pointer. If the StringRef is not - // null-terminated, throws std::domain_exception - auto c_str() const -> char const*; - - public: // substrings and searches - // Returns a substring of [start, start + length). - // If start + length > size(), then the substring is [start, size()). - // If start > size(), then the substring is empty. - auto substr( size_type start, size_type length ) const noexcept -> StringRef; - - // Returns the current start pointer. May not be null-terminated. - auto data() const noexcept -> char const*; - - constexpr auto isNullTerminated() const noexcept -> bool { - return m_start[m_size] == '\0'; - } - - public: // iterators - constexpr const_iterator begin() const { return m_start; } - constexpr const_iterator end() const { return m_start + m_size; } - }; - - auto operator += ( std::string& lhs, StringRef const& sr ) -> std::string&; - auto operator << ( std::ostream& os, StringRef const& sr ) -> std::ostream&; - - constexpr auto operator "" _sr( char const* rawChars, std::size_t size ) noexcept -> StringRef { - return StringRef( rawChars, size ); + constexpr StringRef(char const *rawChars, size_type size) noexcept + : m_start(rawChars) + , m_size(size) { } + + StringRef(std::string const &stdString) noexcept + : m_start(stdString.c_str()) + , m_size(stdString.size()) { + } + + explicit operator std::string() const { return std::string(m_start, m_size); } + + public: // operators + auto operator==(StringRef const &other) const noexcept -> bool; + auto operator!=(StringRef const &other) const noexcept -> bool { return !(*this == other); } + + auto operator[](size_type index) const noexcept -> char { + assert(index < m_size); + return m_start[index]; + } + + public: // named queries + constexpr auto empty() const noexcept -> bool { return m_size == 0; } + constexpr auto size() const noexcept -> size_type { return m_size; } + + // Returns the current start pointer. If the StringRef is not + // null-terminated, throws std::domain_exception + auto c_str() const -> char const *; + + public: // substrings and searches + // Returns a substring of [start, start + length). + // If start + length > size(), then the substring is [start, size()). + // If start > size(), then the substring is empty. + auto substr(size_type start, size_type length) const noexcept -> StringRef; + + // Returns the current start pointer. May not be null-terminated. + auto data() const noexcept -> char const *; + + constexpr auto isNullTerminated() const noexcept -> bool { return m_start[m_size] == '\0'; } + + public: // iterators + constexpr const_iterator begin() const { return m_start; } + constexpr const_iterator end() const { return m_start + m_size; } + }; + + auto operator+=(std::string &lhs, StringRef const &sr) -> std::string &; + auto operator<<(std::ostream &os, StringRef const &sr) -> std::ostream &; + + constexpr auto operator"" _sr(char const *rawChars, std::size_t size) noexcept -> StringRef { + return StringRef(rawChars, size); + } } // namespace Catch -constexpr auto operator "" _catch_sr( char const* rawChars, std::size_t size ) noexcept -> Catch::StringRef { - return Catch::StringRef( rawChars, size ); +constexpr auto operator"" _catch_sr(char const *rawChars, std::size_t size) noexcept -> Catch::StringRef { + return Catch::StringRef(rawChars, size); } // end catch_stringref.h // start catch_preprocessor.hpp - #define CATCH_RECURSION_LEVEL0(...) __VA_ARGS__ #define CATCH_RECURSION_LEVEL1(...) CATCH_RECURSION_LEVEL0(CATCH_RECURSION_LEVEL0(CATCH_RECURSION_LEVEL0(__VA_ARGS__))) #define CATCH_RECURSION_LEVEL2(...) CATCH_RECURSION_LEVEL1(CATCH_RECURSION_LEVEL1(CATCH_RECURSION_LEVEL1(__VA_ARGS__))) @@ -699,9 +689,9 @@ constexpr auto operator "" _catch_sr( char const* rawChars, std::size_t size ) n #define INTERNAL_CATCH_EXPAND_VARGS(...) __VA_ARGS__ // MSVC needs more evaluations #define CATCH_RECURSION_LEVEL6(...) CATCH_RECURSION_LEVEL5(CATCH_RECURSION_LEVEL5(CATCH_RECURSION_LEVEL5(__VA_ARGS__))) -#define CATCH_RECURSE(...) CATCH_RECURSION_LEVEL6(CATCH_RECURSION_LEVEL6(__VA_ARGS__)) +#define CATCH_RECURSE(...) CATCH_RECURSION_LEVEL6(CATCH_RECURSION_LEVEL6(__VA_ARGS__)) #else -#define CATCH_RECURSE(...) CATCH_RECURSION_LEVEL5(__VA_ARGS__) +#define CATCH_RECURSE(...) CATCH_RECURSION_LEVEL5(__VA_ARGS__) #endif #define CATCH_REC_END(...) @@ -714,16 +704,21 @@ constexpr auto operator "" _catch_sr( char const* rawChars, std::size_t size ) n #define CATCH_REC_GET_END1(...) CATCH_REC_GET_END2 #define CATCH_REC_GET_END(...) CATCH_REC_GET_END1 #define CATCH_REC_NEXT0(test, next, ...) next CATCH_REC_OUT -#define CATCH_REC_NEXT1(test, next) CATCH_DEFER ( CATCH_REC_NEXT0 ) ( test, next, 0) -#define CATCH_REC_NEXT(test, next) CATCH_REC_NEXT1(CATCH_REC_GET_END test, next) +#define CATCH_REC_NEXT1(test, next) \ + CATCH_DEFER(CATCH_REC_NEXT0) \ + (test, next, 0) +#define CATCH_REC_NEXT(test, next) CATCH_REC_NEXT1(CATCH_REC_GET_END test, next) -#define CATCH_REC_LIST0(f, x, peek, ...) , f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1) ) ( f, peek, __VA_ARGS__ ) -#define CATCH_REC_LIST1(f, x, peek, ...) , f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST0) ) ( f, peek, __VA_ARGS__ ) -#define CATCH_REC_LIST2(f, x, peek, ...) f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1) ) ( f, peek, __VA_ARGS__ ) +#define CATCH_REC_LIST0(f, x, peek, ...) , f(x) CATCH_DEFER(CATCH_REC_NEXT(peek, CATCH_REC_LIST1))(f, peek, __VA_ARGS__) +#define CATCH_REC_LIST1(f, x, peek, ...) , f(x) CATCH_DEFER(CATCH_REC_NEXT(peek, CATCH_REC_LIST0))(f, peek, __VA_ARGS__) +#define CATCH_REC_LIST2(f, x, peek, ...) f(x) CATCH_DEFER(CATCH_REC_NEXT(peek, CATCH_REC_LIST1))(f, peek, __VA_ARGS__) -#define CATCH_REC_LIST0_UD(f, userdata, x, peek, ...) , f(userdata, x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1_UD) ) ( f, userdata, peek, __VA_ARGS__ ) -#define CATCH_REC_LIST1_UD(f, userdata, x, peek, ...) , f(userdata, x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST0_UD) ) ( f, userdata, peek, __VA_ARGS__ ) -#define CATCH_REC_LIST2_UD(f, userdata, x, peek, ...) f(userdata, x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1_UD) ) ( f, userdata, peek, __VA_ARGS__ ) +#define CATCH_REC_LIST0_UD(f, userdata, x, peek, ...) \ + , f(userdata, x) CATCH_DEFER(CATCH_REC_NEXT(peek, CATCH_REC_LIST1_UD))(f, userdata, peek, __VA_ARGS__) +#define CATCH_REC_LIST1_UD(f, userdata, x, peek, ...) \ + , f(userdata, x) CATCH_DEFER(CATCH_REC_NEXT(peek, CATCH_REC_LIST0_UD))(f, userdata, peek, __VA_ARGS__) +#define CATCH_REC_LIST2_UD(f, userdata, x, peek, ...) \ + f(userdata, x) CATCH_DEFER(CATCH_REC_NEXT(peek, CATCH_REC_LIST1_UD))(f, userdata, peek, __VA_ARGS__) // Applies the function macro `f` to each of the remaining parameters, inserts commas between the results, // and passes userdata as the first parameter to each invocation, @@ -733,7 +728,7 @@ constexpr auto operator "" _catch_sr( char const* rawChars, std::size_t size ) n #define CATCH_REC_LIST(f, ...) CATCH_RECURSE(CATCH_REC_LIST2(f, __VA_ARGS__, ()()(), ()()(), ()()(), 0)) #define INTERNAL_CATCH_EXPAND1(param) INTERNAL_CATCH_EXPAND2(param) -#define INTERNAL_CATCH_EXPAND2(...) INTERNAL_CATCH_NO## __VA_ARGS__ +#define INTERNAL_CATCH_EXPAND2(...) INTERNAL_CATCH_NO##__VA_ARGS__ #define INTERNAL_CATCH_DEF(...) INTERNAL_CATCH_DEF __VA_ARGS__ #define INTERNAL_CATCH_NOINTERNAL_CATCH_DEF #define INTERNAL_CATCH_STRINGIZE(...) INTERNAL_CATCH_STRINGIZE2(__VA_ARGS__) @@ -756,585 +751,1066 @@ constexpr auto operator "" _catch_sr( char const* rawChars, std::size_t size ) n #define INTERNAL_CATCH_MAKE_TYPE_LIST2(...) decltype(get_wrapper()) #define INTERNAL_CATCH_MAKE_TYPE_LIST(...) INTERNAL_CATCH_MAKE_TYPE_LIST2(INTERNAL_CATCH_REMOVE_PARENS(__VA_ARGS__)) #else -#define INTERNAL_CATCH_MAKE_TYPE_LIST2(...) INTERNAL_CATCH_EXPAND_VARGS(decltype(get_wrapper())) -#define INTERNAL_CATCH_MAKE_TYPE_LIST(...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_MAKE_TYPE_LIST2(INTERNAL_CATCH_REMOVE_PARENS(__VA_ARGS__))) +#define INTERNAL_CATCH_MAKE_TYPE_LIST2(...) \ + INTERNAL_CATCH_EXPAND_VARGS(decltype(get_wrapper())) +#define INTERNAL_CATCH_MAKE_TYPE_LIST(...) \ + INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_MAKE_TYPE_LIST2(INTERNAL_CATCH_REMOVE_PARENS(__VA_ARGS__))) #endif -#define INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(...)\ - CATCH_REC_LIST(INTERNAL_CATCH_MAKE_TYPE_LIST,__VA_ARGS__) +#define INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(...) CATCH_REC_LIST(INTERNAL_CATCH_MAKE_TYPE_LIST, __VA_ARGS__) #define INTERNAL_CATCH_REMOVE_PARENS_1_ARG(_0) INTERNAL_CATCH_REMOVE_PARENS(_0) #define INTERNAL_CATCH_REMOVE_PARENS_2_ARG(_0, _1) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_1_ARG(_1) #define INTERNAL_CATCH_REMOVE_PARENS_3_ARG(_0, _1, _2) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_2_ARG(_1, _2) -#define INTERNAL_CATCH_REMOVE_PARENS_4_ARG(_0, _1, _2, _3) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_3_ARG(_1, _2, _3) -#define INTERNAL_CATCH_REMOVE_PARENS_5_ARG(_0, _1, _2, _3, _4) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_4_ARG(_1, _2, _3, _4) -#define INTERNAL_CATCH_REMOVE_PARENS_6_ARG(_0, _1, _2, _3, _4, _5) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_5_ARG(_1, _2, _3, _4, _5) -#define INTERNAL_CATCH_REMOVE_PARENS_7_ARG(_0, _1, _2, _3, _4, _5, _6) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_6_ARG(_1, _2, _3, _4, _5, _6) -#define INTERNAL_CATCH_REMOVE_PARENS_8_ARG(_0, _1, _2, _3, _4, _5, _6, _7) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_7_ARG(_1, _2, _3, _4, _5, _6, _7) -#define INTERNAL_CATCH_REMOVE_PARENS_9_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_8_ARG(_1, _2, _3, _4, _5, _6, _7, _8) -#define INTERNAL_CATCH_REMOVE_PARENS_10_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_9_ARG(_1, _2, _3, _4, _5, _6, _7, _8, _9) -#define INTERNAL_CATCH_REMOVE_PARENS_11_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_10_ARG(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10) +#define INTERNAL_CATCH_REMOVE_PARENS_4_ARG(_0, _1, _2, _3) \ + INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_3_ARG(_1, _2, _3) +#define INTERNAL_CATCH_REMOVE_PARENS_5_ARG(_0, _1, _2, _3, _4) \ + INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_4_ARG(_1, _2, _3, _4) +#define INTERNAL_CATCH_REMOVE_PARENS_6_ARG(_0, _1, _2, _3, _4, _5) \ + INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_5_ARG(_1, _2, _3, _4, _5) +#define INTERNAL_CATCH_REMOVE_PARENS_7_ARG(_0, _1, _2, _3, _4, _5, _6) \ + INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_6_ARG(_1, _2, _3, _4, _5, _6) +#define INTERNAL_CATCH_REMOVE_PARENS_8_ARG(_0, _1, _2, _3, _4, _5, _6, _7) \ + INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_7_ARG(_1, _2, _3, _4, _5, _6, _7) +#define INTERNAL_CATCH_REMOVE_PARENS_9_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8) \ + INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_8_ARG(_1, _2, _3, _4, _5, _6, _7, _8) +#define INTERNAL_CATCH_REMOVE_PARENS_10_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9) \ + INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_9_ARG(_1, _2, _3, _4, _5, _6, _7, _8, _9) +#define INTERNAL_CATCH_REMOVE_PARENS_11_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10) \ + INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_10_ARG(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10) #define INTERNAL_CATCH_VA_NARGS_IMPL(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) N -#define INTERNAL_CATCH_TYPE_GEN\ - template struct TypeList {};\ - template\ - constexpr auto get_wrapper() noexcept -> TypeList { return {}; }\ - template class...> struct TemplateTypeList{};\ - template class...Cs>\ - constexpr auto get_wrapper() noexcept -> TemplateTypeList { return {}; }\ - template\ - struct append;\ - template\ - struct rewrap;\ - template class, typename...>\ - struct create;\ - template class, typename>\ - struct convert;\ - \ - template \ - struct append { using type = T; };\ - template< template class L1, typename...E1, template class L2, typename...E2, typename...Rest>\ - struct append, L2, Rest...> { using type = typename append, Rest...>::type; };\ - template< template class L1, typename...E1, typename...Rest>\ - struct append, TypeList, Rest...> { using type = L1; };\ - \ - template< template class Container, template class List, typename...elems>\ - struct rewrap, List> { using type = TypeList>; };\ - template< template class Container, template class List, class...Elems, typename...Elements>\ - struct rewrap, List, Elements...> { using type = typename append>, typename rewrap, Elements...>::type>::type; };\ - \ - template