Merge branch 'develop' into typed_function_ordering
This commit is contained in:
@@ -249,27 +249,30 @@ set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${LINKER_FLAGS}")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${LINKER_FLAGS}")
|
||||
set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${LINKER_FLAGS}")
|
||||
|
||||
add_library(stdlib STATIC static_libs/chaiscript_stdlib.cpp)
|
||||
add_library(parser STATIC static_libs/chaiscript_parser.cpp)
|
||||
|
||||
add_library(chaiscript_stdlib-${CHAI_VERSION} MODULE src/chaiscript_stdlib.cpp)
|
||||
add_library(chaiscript_stdlib-${CHAI_VERSION} MODULE src/chaiscript_stdlib_module.cpp)
|
||||
target_link_libraries(chaiscript_stdlib-${CHAI_VERSION} ${LIBS} ${CMAKE_THREAD_LIBS_INIT})
|
||||
|
||||
set(CHAISCRIPT_LIBS stdlib parser)
|
||||
|
||||
add_executable(chai src/main.cpp ${Chai_INCLUDES})
|
||||
target_link_libraries(chai ${LIBS})
|
||||
add_dependencies(chai chaiscript_stdlib-${CHAI_VERSION})
|
||||
target_link_libraries(chai ${LIBS} ${CHAISCRIPT_LIBS})
|
||||
|
||||
if(BUILD_SAMPLES)
|
||||
add_executable(example samples/example.cpp)
|
||||
target_link_libraries(example ${LIBS})
|
||||
add_executable(test_num_exceptions samples/test_num_exceptions.cpp)
|
||||
target_link_libraries(test_num_exceptions ${LIBS})
|
||||
target_link_libraries(test_num_exceptions ${LIBS} ${CHAISCRIPT_LIBS})
|
||||
add_executable(memory_leak_test samples/memory_leak_test.cpp)
|
||||
target_link_libraries(memory_leak_test ${LIBS})
|
||||
target_link_libraries(memory_leak_test ${LIBS} ${CHAISCRIPT_LIBS})
|
||||
add_executable(inheritance samples/inheritance.cpp)
|
||||
target_link_libraries(inheritance ${LIBS})
|
||||
target_link_libraries(inheritance ${LIBS} ${CHAISCRIPT_LIBS})
|
||||
add_executable(factory samples/factory.cpp)
|
||||
target_link_libraries(factory ${LIBS})
|
||||
target_link_libraries(factory ${LIBS} ${CHAISCRIPT_LIBS})
|
||||
add_executable(fun_call_performance samples/fun_call_performance.cpp)
|
||||
target_link_libraries(fun_call_performance ${LIBS})
|
||||
target_link_libraries(fun_call_performance ${LIBS} ${CHAISCRIPT_LIBS})
|
||||
endif()
|
||||
|
||||
|
||||
@@ -295,7 +298,7 @@ if (RUN_FUZZY_TESTS)
|
||||
file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/unittests")
|
||||
|
||||
execute_process(
|
||||
COMMAND ${CMAKE_COMMAND} -E tar xjf ${CMAKE_CURRENT_SOURCE_DIR}/unittests/fuzzy_tests-2015-07-16.tar.bz2
|
||||
COMMAND ${CMAKE_COMMAND} -E tar xjf ${CMAKE_CURRENT_SOURCE_DIR}/unittests/fuzzy_tests-2016-06-29.tar.bz2
|
||||
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/unittests
|
||||
)
|
||||
|
||||
@@ -421,7 +424,7 @@ if(BUILD_TESTING)
|
||||
|
||||
if(NOT UNIT_TEST_LIGHT)
|
||||
add_executable(compiled_tests unittests/compiled_tests.cpp)
|
||||
target_link_libraries(compiled_tests ${LIBS})
|
||||
target_link_libraries(compiled_tests ${LIBS} ${CHAISCRIPT_LIBS})
|
||||
ADD_CATCH_TESTS(compiled_tests)
|
||||
|
||||
|
||||
@@ -434,11 +437,11 @@ if(BUILD_TESTING)
|
||||
add_test(NAME Type_Info_Test COMMAND type_info_test)
|
||||
|
||||
add_executable(c_linkage_test unittests/c_linkage_test.cpp)
|
||||
target_link_libraries(c_linkage_test ${LIBS})
|
||||
target_link_libraries(c_linkage_test ${LIBS} ${CHAISCRIPT_LIBS})
|
||||
add_test(NAME C_Linkage_Test COMMAND c_linkage_test)
|
||||
|
||||
add_executable(integer_literal_test unittests/integer_literal_test.cpp)
|
||||
target_link_libraries(integer_literal_test ${LIBS})
|
||||
target_link_libraries(integer_literal_test ${LIBS} ${CHAISCRIPT_LIBS})
|
||||
add_test(NAME Integer_Literal_Test COMMAND integer_literal_test)
|
||||
|
||||
if(MULTITHREAD_SUPPORT_ENABLED)
|
||||
|
28
DesignGoals.md
Normal file
28
DesignGoals.md
Normal file
@@ -0,0 +1,28 @@
|
||||
# Introduction
|
||||
|
||||
This document outlines the principles that drive the development of ChaiScript. ChaiScript does not intent to be the perfect tool for *every* situation, but it does intend to be a good general purpose tool for *most* situations.
|
||||
|
||||
# Goals
|
||||
|
||||
1. Trivially easy to integrate with C++ projects
|
||||
2. 0 external depenencies
|
||||
3. "Perfect" integration with C++
|
||||
* Direct mapping between ChaiScript objects and C++ objects
|
||||
* Direct mapping between ChaiScript functions and C++ functions
|
||||
* Direct mapping between ChaiScript exceptions and C++ exceptions
|
||||
3. Never surprise the C++ developer
|
||||
* Object lifetimes managed by the stack
|
||||
* Familiar syntax to C++ developers
|
||||
4. Perform "well enough" to not get in the way
|
||||
|
||||
|
||||
# Alternatives
|
||||
|
||||
## Sol2
|
||||
|
||||
If you are looking for the fastest performing scripting language and don't mind Lua, you might want to consider [sol2](https://github.com/ThePhD/sol2).
|
||||
|
||||
## SWIG
|
||||
|
||||
If you are looking for the most flexible solution to be able to support multiple target languages, consider [SWIG](http://swig.org)
|
||||
|
@@ -27,6 +27,13 @@ chai.add(chaiscript::fun(&Class::method_name), "method_name");
|
||||
chai.add(chaiscript::fun(&Class::member_name), "member_name");
|
||||
```
|
||||
|
||||
### Bound Member Functions
|
||||
|
||||
```
|
||||
chai.add(chaiscript::fun(&Class::method_name, Class_instance_ptr), "method_name");
|
||||
chai.add(chaiscript::fun(&Class::member_name, Class_instance_ptr), "member_name");
|
||||
```
|
||||
|
||||
### With Overloads
|
||||
|
||||
#### Preferred
|
||||
@@ -84,6 +91,33 @@ chai.add(chaiscript::user_type<MyClass>(), "MyClass");
|
||||
|
||||
User defined type conversions are possible, defined in either script or in C++.
|
||||
|
||||
|
||||
### ChaiScript Defined Conversions
|
||||
|
||||
Function objects (including lambdas) can be used to add type conversions
|
||||
from inside of ChaiScript:
|
||||
|
||||
```
|
||||
add_type_conversion(type("string"), type("Type_Info"), fun(s) { return type(s); });
|
||||
```
|
||||
|
||||
### C++ Defined Conversions
|
||||
|
||||
Invoking a C++ type conversion possible with `static_cast`
|
||||
|
||||
```
|
||||
chai.add(chaiscript::type_conversion<T, bool>());
|
||||
```
|
||||
|
||||
Calling a user defined type conversion that takes a lambda
|
||||
|
||||
```
|
||||
chai.add(chaiscript::type_conversion<TestBaseType, Type2>([](const TestBaseType &t_bt) { /* return converted thing */ }));
|
||||
```
|
||||
|
||||
|
||||
### Helpers
|
||||
|
||||
A helper function exists for strongly typed and ChaiScript `Vector` function conversion definition:
|
||||
|
||||
```
|
||||
@@ -97,6 +131,7 @@ chai.add(chaiscript::map_conversion<std::map<std::string, int>>());
|
||||
```
|
||||
|
||||
|
||||
|
||||
This allows you to pass a ChaiScript function to a function requiring `std::vector<int>`
|
||||
|
||||
## Adding Objects
|
||||
@@ -111,6 +146,7 @@ chai.add_global_const(chaiscript::const_var(somevar), "somevar"); // global cons
|
||||
chai.add_global(chaiscript::var(somevar), "somevar"); // global non-const, throws if object exists
|
||||
chai.set_global(chaiscript::var(somevar), "somevar"); // global non-const, overwrites existing object
|
||||
```
|
||||
|
||||
# Using STL
|
||||
ChaiScript recognize many types from STL, but you have to add specific instantiation yourself.
|
||||
|
||||
@@ -260,6 +296,35 @@ if (g2.is_var_undef()) { g2 = 4; } // only initialize g2 once, if global decl hi
|
||||
GLOBAL g3; // all upper case version also accepted
|
||||
```
|
||||
|
||||
## Looping
|
||||
|
||||
```
|
||||
// c-style for loops
|
||||
for (var i = 0; i < 100; ++i) { print(i); }
|
||||
```
|
||||
|
||||
```
|
||||
// while
|
||||
while (some_condition()) { /* do something */ }
|
||||
```
|
||||
|
||||
```
|
||||
// ranged for
|
||||
for (x : [1,2,3]) { print(i); }
|
||||
```
|
||||
|
||||
## Conditionals
|
||||
|
||||
```
|
||||
if (expression) { }
|
||||
```
|
||||
|
||||
```
|
||||
// C++17-style init-if blocks
|
||||
// Value of 'statement' is scoped for entire `if` block
|
||||
if (statement; expression) { }
|
||||
```
|
||||
|
||||
## Built in Types
|
||||
|
||||
```
|
||||
@@ -418,9 +483,33 @@ the contained function.
|
||||
|
||||
If both a 2 parameter and a 3 parameter signature match, the 3 parameter function always wins.
|
||||
|
||||
## Context
|
||||
|
||||
* `__LINE__` Current file line number
|
||||
* `__FILE__` Full path of current file
|
||||
* `__CLASS__` Name of current class
|
||||
* `__FUNC__` Mame of current function
|
||||
|
||||
|
||||
# Built In Functions
|
||||
|
||||
## Disabling Built-Ins
|
||||
|
||||
When constructing a ChaiScript object, a vector of parameters can be passed in to disable or enable various built-in methods.
|
||||
|
||||
Current options:
|
||||
|
||||
```
|
||||
enum class Options
|
||||
{
|
||||
Load_Modules,
|
||||
No_Load_Modules,
|
||||
External_Scripts,
|
||||
No_External_Scripts
|
||||
};
|
||||
```
|
||||
|
||||
|
||||
## Evaluation
|
||||
|
||||
```
|
||||
@@ -432,4 +521,7 @@ use("filename") // evals file exactly once and returns value of last statement
|
||||
|
||||
Both `use` and `eval_file` search the 'usepaths' passed to the ChaiScript constructor
|
||||
|
||||
## JSON
|
||||
|
||||
* `from_json` converts a JSON string into its strongly typed (map, vector, int, double, string) representations
|
||||
* `to_json` converts a ChaiScript object (either a `Object` or one of map, vector, int, double, string) tree into its JSON string representation
|
||||
|
@@ -695,11 +695,10 @@
|
||||
/// Begins a function or method definition
|
||||
///
|
||||
/// ~~~~~~~~
|
||||
/// Function Definition ::= [annotation + CR/LF] "def" identifier "(" [[type] arg ("," [type] arg)*] ")" [":" guard] block
|
||||
/// Method Definition ::= [annotation + CR/LF] "def" class_name "::" method_name "(" [[type] arg ("," [type] arg)*] ")" [":" guard] block
|
||||
/// Function Definition ::= "def" identifier "(" [[type] arg ("," [type] arg)*] ")" [":" guard] block
|
||||
/// Method Definition ::= "def" class_name "::" method_name "(" [[type] arg ("," [type] arg)*] ")" [":" guard] block
|
||||
/// ~~~~~~~~
|
||||
///
|
||||
/// annotation: meta-annotation on function, currently used as documentation. Optional.
|
||||
/// 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.
|
||||
@@ -817,16 +816,26 @@
|
||||
/// @namespace chaiscript::detail
|
||||
/// @brief Classes and functions reserved for internal use. Items in this namespace are not supported.
|
||||
|
||||
#include "chaiscript_defines.hpp"
|
||||
|
||||
#include "dispatchkit/dispatchkit.hpp"
|
||||
#include "dispatchkit/function_call.hpp"
|
||||
#include "dispatchkit/dynamic_object.hpp"
|
||||
#include "dispatchkit/boxed_number.hpp"
|
||||
|
||||
#include "language/chaiscript_eval.hpp"
|
||||
#include "language/chaiscript_engine.hpp"
|
||||
#include "chaiscript_basic.hpp"
|
||||
#include "language/chaiscript_parser.hpp"
|
||||
#include "chaiscript_stdlib.hpp"
|
||||
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
class ChaiScript : public ChaiScript_Basic
|
||||
{
|
||||
public:
|
||||
ChaiScript(std::vector<std::string> t_modulepaths = {},
|
||||
std::vector<std::string> t_usepaths = {},
|
||||
const std::vector<Options> &t_opts = {})
|
||||
: ChaiScript_Basic(
|
||||
chaiscript::Std_Lib::library(),
|
||||
std::make_unique<parser::ChaiScript_Parser<eval::Noop_Tracer, optimizer::Optimizer_Default>>(),
|
||||
t_modulepaths, t_usepaths, t_opts)
|
||||
{
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* CHAISCRIPT_HPP_ */
|
||||
|
39
include/chaiscript/chaiscript_basic.hpp
Normal file
39
include/chaiscript/chaiscript_basic.hpp
Normal file
@@ -0,0 +1,39 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// Copyright 2009-2016, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#ifndef CHAISCRIPT_BASIC_HPP_
|
||||
#define CHAISCRIPT_BASIC_HPP_
|
||||
|
||||
#include "chaiscript_defines.hpp"
|
||||
|
||||
#include "dispatchkit/dispatchkit.hpp"
|
||||
#include "dispatchkit/function_call.hpp"
|
||||
#include "dispatchkit/dynamic_object.hpp"
|
||||
#include "dispatchkit/boxed_number.hpp"
|
||||
|
||||
#include "language/chaiscript_eval.hpp"
|
||||
#include "language/chaiscript_engine.hpp"
|
||||
|
||||
// This file includes all of the basic requirements for ChaiScript,
|
||||
// to use, you might do something like:
|
||||
//
|
||||
|
||||
/*
|
||||
|
||||
#include "chaiscript_stdlib.hpp"
|
||||
#include "language/chaiscript_parser.hpp"
|
||||
|
||||
ChaiScript_Basic chai(
|
||||
chaiscript::Std_Lib::library(),
|
||||
std::make_unique<parser::ChaiScript_Parser<eval::Noop_Tracer, optimizer::Optimizer_Default>>());
|
||||
|
||||
*/
|
||||
|
||||
// If you want a fully packaged ready to go ChaiScript, use chaiscript.hpp
|
||||
|
||||
|
||||
|
||||
#endif /* CHAISCRIPT_BASIC_HPP_ */
|
@@ -12,6 +12,9 @@
|
||||
#define CHAISCRIPT_COMPILER_VERSION CHAISCRIPT_STRINGIZE(_MSC_FULL_VER)
|
||||
#define CHAISCRIPT_MSVC _MSC_VER
|
||||
#define CHAISCRIPT_HAS_DECLSPEC
|
||||
|
||||
static_assert(_MSC_FULL_VER >= 190024210, "Visual C++ 2015 Update 3 or later required");
|
||||
|
||||
#else
|
||||
#define CHAISCRIPT_COMPILER_VERSION __VERSION__
|
||||
#endif
|
||||
@@ -60,6 +63,10 @@
|
||||
#define CHAISCRIPT_MODULE_EXPORT extern "C"
|
||||
#endif
|
||||
|
||||
#if defined(CHAISCRIPT_MSVC) || (defined(__GNUC__) && __GNUC__ >= 5) || defined(CHAISCRIPT_CLANG)
|
||||
#define CHAISCRIPT_UTF16_UTF32
|
||||
#endif
|
||||
|
||||
#ifdef _DEBUG
|
||||
#define CHAISCRIPT_DEBUG true
|
||||
#else
|
||||
@@ -89,18 +96,59 @@ namespace chaiscript {
|
||||
#endif
|
||||
}
|
||||
|
||||
template<typename Iter, typename Distance>
|
||||
Iter advance_copy(Iter iter, Distance distance) {
|
||||
std::advance(iter, static_cast<typename std::iterator_traits<Iter>::difference_type>(distance));
|
||||
return iter;
|
||||
struct Build_Info {
|
||||
static int version_major()
|
||||
{
|
||||
return chaiscript::version_major;
|
||||
}
|
||||
|
||||
static int version_minor()
|
||||
{
|
||||
return chaiscript::version_minor;
|
||||
}
|
||||
|
||||
static int version_patch()
|
||||
{
|
||||
return chaiscript::version_patch;
|
||||
}
|
||||
|
||||
static std::string version()
|
||||
{
|
||||
return std::to_string(version_major()) + '.' + std::to_string(version_minor()) + '.' + std::to_string(version_patch());
|
||||
}
|
||||
|
||||
static std::string compiler_id()
|
||||
{
|
||||
return compiler_name() + '-' + compiler_version();
|
||||
}
|
||||
|
||||
static std::string build_id()
|
||||
{
|
||||
return compiler_id() + (debug_build()?"-Debug":"-Release");
|
||||
}
|
||||
|
||||
static std::string compiler_version()
|
||||
{
|
||||
return chaiscript::compiler_version;
|
||||
}
|
||||
|
||||
static std::string compiler_name()
|
||||
{
|
||||
return chaiscript::compiler_name;
|
||||
}
|
||||
|
||||
static bool debug_build()
|
||||
{
|
||||
return chaiscript::debug_build;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<typename T>
|
||||
auto parse_num(const char *t_str) -> typename std::enable_if<std::is_integral<T>::value, T>::type
|
||||
{
|
||||
T t = 0;
|
||||
for (char c = *t_str; (c = *t_str); ++t_str) {
|
||||
for (char c = *t_str; (c = *t_str) != 0; ++t_str) {
|
||||
if (c < '0' || c > '9') {
|
||||
return t;
|
||||
}
|
||||
@@ -161,6 +209,18 @@ namespace chaiscript {
|
||||
return parse_num<T>(t_str.c_str());
|
||||
}
|
||||
|
||||
enum class Options
|
||||
{
|
||||
No_Load_Modules,
|
||||
Load_Modules,
|
||||
No_External_Scripts,
|
||||
External_Scripts
|
||||
};
|
||||
|
||||
static inline std::vector<Options> default_options()
|
||||
{
|
||||
return {Options::Load_Modules, Options::External_Scripts};
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@@ -14,11 +14,17 @@
|
||||
#include <vector>
|
||||
|
||||
#include "chaiscript_defines.hpp"
|
||||
#include "dispatchkit/dispatchkit.hpp"
|
||||
#include "language/chaiscript_common.hpp"
|
||||
|
||||
#include "dispatchkit/function_call.hpp"
|
||||
|
||||
//#include "dispatchkit/dispatchkit.hpp"
|
||||
#include "dispatchkit/operators.hpp"
|
||||
#include "dispatchkit/bootstrap.hpp"
|
||||
#include "dispatchkit/bootstrap_stl.hpp"
|
||||
#include "dispatchkit/boxed_value.hpp"
|
||||
//#include "dispatchkit/boxed_value.hpp"
|
||||
#include "language/chaiscript_prelude.hpp"
|
||||
#include "dispatchkit/register_function.hpp"
|
||||
#include "utility/json_wrap.hpp"
|
||||
|
||||
#ifndef CHAISCRIPT_NO_THREADS
|
||||
@@ -38,18 +44,16 @@ namespace chaiscript
|
||||
|
||||
static ModulePtr library()
|
||||
{
|
||||
using namespace bootstrap;
|
||||
|
||||
auto lib = std::make_shared<Module>();
|
||||
Bootstrap::bootstrap(*lib);
|
||||
bootstrap::Bootstrap::bootstrap(*lib);
|
||||
|
||||
standard_library::vector_type<std::vector<Boxed_Value> >("Vector", *lib);
|
||||
standard_library::string_type<std::string>("string", *lib);
|
||||
standard_library::map_type<std::map<std::string, Boxed_Value> >("Map", *lib);
|
||||
standard_library::pair_type<std::pair<Boxed_Value, Boxed_Value > >("Pair", *lib);
|
||||
bootstrap::standard_library::vector_type<std::vector<Boxed_Value> >("Vector", *lib);
|
||||
bootstrap::standard_library::string_type<std::string>("string", *lib);
|
||||
bootstrap::standard_library::map_type<std::map<std::string, Boxed_Value> >("Map", *lib);
|
||||
bootstrap::standard_library::pair_type<std::pair<Boxed_Value, Boxed_Value > >("Pair", *lib);
|
||||
|
||||
#ifndef CHAISCRIPT_NO_THREADS
|
||||
standard_library::future_type<std::future<chaiscript::Boxed_Value>>("future", *lib);
|
||||
bootstrap::standard_library::future_type<std::future<chaiscript::Boxed_Value>>("future", *lib);
|
||||
lib->add(chaiscript::fun([](const std::function<chaiscript::Boxed_Value ()> &t_func){ return std::async(std::launch::async, t_func);}), "async");
|
||||
#endif
|
||||
|
||||
|
@@ -108,6 +108,9 @@ namespace chaiscript
|
||||
|
||||
#else
|
||||
|
||||
#pragma message ("Threading without thread_local support is not well supported.")
|
||||
|
||||
|
||||
/// 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.
|
||||
///
|
||||
|
@@ -21,10 +21,7 @@ namespace chaiscript {
|
||||
class bad_any_cast : public std::bad_cast
|
||||
{
|
||||
public:
|
||||
bad_any_cast() noexcept
|
||||
: m_what("bad any cast")
|
||||
{
|
||||
}
|
||||
bad_any_cast() = default;
|
||||
|
||||
bad_any_cast(const bad_any_cast &) = default;
|
||||
|
||||
@@ -37,7 +34,7 @@ namespace chaiscript {
|
||||
}
|
||||
|
||||
private:
|
||||
std::string m_what;
|
||||
std::string m_what = "bad any cast";
|
||||
};
|
||||
}
|
||||
|
||||
@@ -151,8 +148,7 @@ namespace chaiscript {
|
||||
|
||||
const std::type_info & type() const
|
||||
{
|
||||
if (m_data)
|
||||
{
|
||||
if (m_data) {
|
||||
return m_data->type();
|
||||
} else {
|
||||
return typeid(void);
|
||||
|
@@ -41,7 +41,7 @@ namespace chaiscript
|
||||
}
|
||||
|
||||
explicit bad_boxed_cast(std::string t_what) noexcept
|
||||
: to(nullptr), m_what(std::move(t_what))
|
||||
: m_what(std::move(t_what))
|
||||
{
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ namespace chaiscript
|
||||
}
|
||||
|
||||
Type_Info from; ///< Type_Info contained in the Boxed_Value
|
||||
const std::type_info *to; ///< std::type_info of the desired (but failed) result type
|
||||
const std::type_info *to = nullptr; ///< std::type_info of the desired (but failed) result type
|
||||
|
||||
private:
|
||||
std::string m_what;
|
||||
|
@@ -27,45 +27,52 @@ namespace chaiscript
|
||||
}
|
||||
|
||||
template<typename O, typename Ret, typename P1, typename ... Param>
|
||||
std::function<Ret (Param...)> bind_first(Ret (*f)(P1, Param...), O&& o)
|
||||
auto bind_first(Ret (*f)(P1, Param...), O&& o)
|
||||
{
|
||||
return std::function<Ret (Param...)>(
|
||||
[f, o](Param...param) -> Ret {
|
||||
return f(std::forward<O>(o), std::forward<Param>(param)...);
|
||||
}
|
||||
);
|
||||
return [f, o](Param...param) -> Ret {
|
||||
return f(std::forward<O>(o), std::forward<Param>(param)...);
|
||||
};
|
||||
}
|
||||
|
||||
template<typename O, typename Ret, typename Class, typename ... Param>
|
||||
std::function<Ret (Param...)> bind_first(Ret (Class::*f)(Param...), O&& o)
|
||||
auto bind_first(Ret (Class::*f)(Param...), O&& o)
|
||||
{
|
||||
return std::function<Ret (Param...)>(
|
||||
[f, o](Param...param) -> Ret {
|
||||
return (get_pointer(o)->*f)(std::forward<Param>(param)...);
|
||||
}
|
||||
);
|
||||
return [f, o](Param...param) -> Ret {
|
||||
return (get_pointer(o)->*f)(std::forward<Param>(param)...);
|
||||
};
|
||||
}
|
||||
|
||||
template<typename O, typename Ret, typename Class, typename ... Param>
|
||||
std::function<Ret (Param...)> bind_first(Ret (Class::*f)(Param...) const, O&& o)
|
||||
auto bind_first(Ret (Class::*f)(Param...) const, O&& o)
|
||||
{
|
||||
return std::function<Ret (Param...)>(
|
||||
[f, o](Param...param) -> Ret {
|
||||
return (get_pointer(o)->*f)(std::forward<Param>(param)...);
|
||||
}
|
||||
);
|
||||
return [f, o](Param...param) -> Ret {
|
||||
return (get_pointer(o)->*f)(std::forward<Param>(param)...);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
template<typename O, typename Ret, typename P1, typename ... Param>
|
||||
std::function<Ret (Param...)> bind_first(const std::function<Ret (P1, Param...)> &f, O&& o)
|
||||
auto bind_first(const std::function<Ret (P1, Param...)> &f, O&& o)
|
||||
{
|
||||
return std::function<Ret (Param...)>(
|
||||
[f, o](Param...param) -> Ret {
|
||||
return f(o, std::forward<Param>(param)...);
|
||||
});
|
||||
return [f, o](Param...param) -> Ret {
|
||||
return f(o, std::forward<Param>(param)...);
|
||||
};
|
||||
}
|
||||
|
||||
template<typename F, typename O, typename Ret, typename Class, typename P1, typename ... Param>
|
||||
auto bind_first(const F &fo, O&& o, Ret (Class::*f)(P1, Param...) const)
|
||||
{
|
||||
return [fo, o, f](Param ...param) -> Ret {
|
||||
return (fo.*f)(o, std::forward<Param>(param)...);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
template<typename F, typename O>
|
||||
auto bind_first(const F &f, O&& o)
|
||||
{
|
||||
return bind_first(f, std::forward<O>(o), &F::operator());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@@ -7,50 +7,14 @@
|
||||
#ifndef CHAISCRIPT_BOOTSTRAP_HPP_
|
||||
#define CHAISCRIPT_BOOTSTRAP_HPP_
|
||||
|
||||
#include <cstdint>
|
||||
#include <exception>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
#include <iterator>
|
||||
|
||||
#include "bad_boxed_cast.hpp"
|
||||
#include "boxed_cast.hpp"
|
||||
#include "boxed_number.hpp"
|
||||
#include "boxed_value.hpp"
|
||||
#include "dispatchkit.hpp"
|
||||
#include "type_conversions.hpp"
|
||||
#include "dynamic_object.hpp"
|
||||
#include "operators.hpp"
|
||||
#include "proxy_constructors.hpp"
|
||||
#include "proxy_functions.hpp"
|
||||
#include "proxy_functions_detail.hpp"
|
||||
#include "register_function.hpp"
|
||||
#include "type_info.hpp"
|
||||
#include "../utility/utility.hpp"
|
||||
#include "../language/chaiscript_common.hpp"
|
||||
#include "register_function.hpp"
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
/// \brief Classes and functions useful for bootstrapping of ChaiScript and adding of new types
|
||||
namespace bootstrap
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
/// \brief Constructs a new POD value object from a Boxed_Number
|
||||
/// \param[in] v Boxed_Number to copy into the new object
|
||||
/// \returns The newly created object.
|
||||
template<typename P1>
|
||||
std::shared_ptr<P1> construct_pod(const Boxed_Number &v)
|
||||
{
|
||||
return std::make_shared<P1>(v.get_as<P1>());
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T, typename = typename std::enable_if<std::is_array<T>::value>::type >
|
||||
void array(const std::string &type, Module& m)
|
||||
{
|
||||
@@ -134,19 +98,10 @@ namespace chaiscript
|
||||
template<typename T>
|
||||
void construct_pod(const std::string &type, Module& m)
|
||||
{
|
||||
m.add(fun(&detail::construct_pod<T>), type);
|
||||
m.add(fun([](const Boxed_Number &bn){ return bn.get_as<T>(); }), type);
|
||||
}
|
||||
|
||||
|
||||
/// to_string function for internal use. Uses ostream operator<<
|
||||
template<typename Input>
|
||||
std::string to_string(Input i)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << i;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
/// Internal function for converting from a string to a value
|
||||
/// uses ostream operator >> to perform the conversion
|
||||
template<typename Input>
|
||||
@@ -194,15 +149,14 @@ namespace chaiscript
|
||||
/// for handling of Proxy_Function object (that is,
|
||||
/// function variables.
|
||||
template<typename Type>
|
||||
std::shared_ptr<Type> shared_ptr_clone(const std::shared_ptr<Type> &p)
|
||||
auto shared_ptr_clone(const std::shared_ptr<Type> &p)
|
||||
{
|
||||
return p;
|
||||
}
|
||||
|
||||
/// Specific version of shared_ptr_clone just for Proxy_Functions
|
||||
template<typename Type>
|
||||
std::shared_ptr<typename std::remove_const<Type>::type>
|
||||
shared_ptr_unconst_clone(const std::shared_ptr<typename std::add_const<Type>::type> &p)
|
||||
std::shared_ptr<typename std::remove_const<Type>::type> shared_ptr_unconst_clone(const std::shared_ptr<typename std::add_const<Type>::type> &p)
|
||||
{
|
||||
return std::const_pointer_cast<typename std::remove_const<Type>::type>(p);
|
||||
}
|
||||
@@ -288,8 +242,6 @@ namespace chaiscript
|
||||
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
|
||||
@@ -329,26 +281,6 @@ namespace chaiscript
|
||||
}
|
||||
}
|
||||
|
||||
static void throw_exception(const Boxed_Value &bv) {
|
||||
throw bv;
|
||||
}
|
||||
|
||||
static std::string what(const std::exception &e)
|
||||
{
|
||||
return e.what();
|
||||
}
|
||||
|
||||
/// Boolean specialization of internal to_string function
|
||||
static std::string bool_to_string(bool b)
|
||||
{
|
||||
if (b)
|
||||
{
|
||||
return "true";
|
||||
} else {
|
||||
return "false";
|
||||
}
|
||||
}
|
||||
|
||||
template<typename FunctionType>
|
||||
static std::vector<Boxed_Value> do_return_boxed_value_vector(FunctionType f,
|
||||
const dispatch::Proxy_Function_Base *b)
|
||||
@@ -384,7 +316,7 @@ namespace chaiscript
|
||||
}
|
||||
|
||||
template<typename Function>
|
||||
static std::function<std::vector<Boxed_Value> (const dispatch::Proxy_Function_Base*)> return_boxed_value_vector(const Function &f)
|
||||
static auto return_boxed_value_vector(const Function &f)
|
||||
{
|
||||
return [f](const dispatch::Proxy_Function_Base *b) {
|
||||
return do_return_boxed_value_vector(f, b);
|
||||
@@ -407,13 +339,13 @@ namespace chaiscript
|
||||
m.add(user_type<std::exception>(), "exception");
|
||||
|
||||
m.add(fun(&dispatch::Proxy_Function_Base::get_arity), "get_arity");
|
||||
m.add(fun(&dispatch::Proxy_Function_Base::annotation), "get_annotation");
|
||||
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<std::out_of_range>(), "out_of_range");
|
||||
m.add(user_type<std::logic_error>(), "logic_error");
|
||||
@@ -425,7 +357,6 @@ namespace chaiscript
|
||||
m.add(chaiscript::base_class<std::exception, std::runtime_error>());
|
||||
|
||||
m.add(constructor<std::runtime_error (const std::string &)>(), "runtime_error");
|
||||
m.add(fun(std::function<std::string (const std::runtime_error &)>(&what)), "what");
|
||||
|
||||
m.add(user_type<dispatch::Dynamic_Object>(), "Dynamic_Object");
|
||||
m.add(constructor<dispatch::Dynamic_Object (const std::string &)>(), "Dynamic_Object");
|
||||
@@ -520,15 +451,15 @@ namespace chaiscript
|
||||
operators::equal<bool>(m);
|
||||
operators::not_equal<bool>(m);
|
||||
|
||||
m.add(fun([](const std::string &s) -> std::string { return s; }), "to_string");
|
||||
m.add(fun(&Bootstrap::bool_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(&throw_exception), "throw");
|
||||
m.add(fun(&what), "what");
|
||||
m.add(fun([](const Boxed_Value &bv) { throw bv; }), "throw");
|
||||
|
||||
m.add(fun(&to_string<char>), "to_string");
|
||||
m.add(fun([](const char c) { return std::string(1, c); }), "to_string");
|
||||
m.add(fun(&Boxed_Number::to_string), "to_string");
|
||||
|
||||
|
||||
bootstrap_pod_type<double>("double", m);
|
||||
bootstrap_pod_type<long double>("long_double", m);
|
||||
bootstrap_pod_type<float>("float", m);
|
||||
@@ -552,10 +483,21 @@ namespace chaiscript
|
||||
bootstrap_pod_type<std::uint32_t>("uint32_t", m);
|
||||
bootstrap_pod_type<std::uint64_t>("uint64_t", m);
|
||||
|
||||
|
||||
operators::logical_compliment<bool>(m);
|
||||
|
||||
opers_arithmetic_pod(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");
|
||||
@@ -580,9 +522,11 @@ namespace chaiscript
|
||||
m.add(chaiscript::fun(&get_parse_tree), "get_parse_tree");
|
||||
|
||||
m.add(chaiscript::base_class<std::runtime_error, chaiscript::exception::eval_error>());
|
||||
m.add(chaiscript::base_class<std::exception, chaiscript::exception::eval_error>());
|
||||
|
||||
m.add(chaiscript::user_type<chaiscript::exception::arithmetic_error>(), "arithmetic_error");
|
||||
m.add(chaiscript::base_class<std::runtime_error, chaiscript::exception::arithmetic_error>());
|
||||
m.add(chaiscript::base_class<std::exception, chaiscript::exception::arithmetic_error>());
|
||||
|
||||
|
||||
// chaiscript::bootstrap::standard_library::vector_type<std::vector<std::shared_ptr<chaiscript::AST_Node> > >("AST_NodeVector", m);
|
||||
@@ -593,13 +537,13 @@ namespace chaiscript
|
||||
{ },
|
||||
{ {fun(&chaiscript::exception::eval_error::reason), "reason"},
|
||||
{fun(&chaiscript::exception::eval_error::pretty_print), "pretty_print"},
|
||||
{fun(std::function<std::vector<Boxed_Value> (const chaiscript::exception::eval_error &t_eval_error)>([](const chaiscript::exception::eval_error &t_eval_error) -> std::vector<Boxed_Value> {
|
||||
{fun([](const chaiscript::exception::eval_error &t_eval_error) {
|
||||
std::vector<Boxed_Value> retval;
|
||||
std::transform(t_eval_error.call_stack.begin(), t_eval_error.call_stack.end(),
|
||||
std::back_inserter(retval),
|
||||
&chaiscript::var<const std::shared_ptr<const chaiscript::AST_Node> &>);
|
||||
return retval;
|
||||
})), "call_stack"} }
|
||||
}), "call_stack"} }
|
||||
);
|
||||
|
||||
|
||||
@@ -621,24 +565,17 @@ namespace chaiscript
|
||||
{fun(&AST_Node::start), "start"},
|
||||
{fun(&AST_Node::end), "end"},
|
||||
{fun(&AST_Node::to_string), "to_string"},
|
||||
{fun(std::function<std::vector<Boxed_Value> (const chaiscript::AST_Node &t_node)>([](const chaiscript::AST_Node &t_node) -> std::vector<Boxed_Value> {
|
||||
{fun([](const chaiscript::AST_Node &t_node) -> std::vector<Boxed_Value> {
|
||||
std::vector<Boxed_Value> retval;
|
||||
std::transform(t_node.children.begin(), t_node.children.end(),
|
||||
const auto children = t_node.get_children();
|
||||
std::transform(children.begin(), children.end(),
|
||||
std::back_inserter(retval),
|
||||
&chaiscript::var<const std::shared_ptr<chaiscript::AST_Node> &>);
|
||||
return retval;
|
||||
})), "children"},
|
||||
{fun(&AST_Node::replace_child), "replace_child"}
|
||||
}), "children"}
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
chaiscript::utility::add_class<parser::ChaiScript_Parser>(m,
|
||||
"ChaiScript_Parser",
|
||||
{ constructor<parser::ChaiScript_Parser ()>() },
|
||||
{ {fun(&parser::ChaiScript_Parser::parse), "parse"},
|
||||
{fun(&parser::ChaiScript_Parser::ast), "ast"} }
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@@ -41,7 +41,6 @@ namespace chaiscript
|
||||
struct Bidir_Range
|
||||
{
|
||||
typedef Container container_type;
|
||||
typedef typename std::iterator_traits<typename Container::iterator>::reference reference_type;
|
||||
|
||||
Bidir_Range(Container &c)
|
||||
: m_begin(c.begin()), m_end(c.end())
|
||||
@@ -71,16 +70,16 @@ namespace chaiscript
|
||||
--m_end;
|
||||
}
|
||||
|
||||
reference_type front() const
|
||||
decltype(auto) front() const
|
||||
{
|
||||
if (empty())
|
||||
{
|
||||
throw std::range_error("Range empty");
|
||||
}
|
||||
return *m_begin;
|
||||
return (*m_begin);
|
||||
}
|
||||
|
||||
reference_type back() const
|
||||
decltype(auto) back() const
|
||||
{
|
||||
if (empty())
|
||||
{
|
||||
@@ -88,7 +87,7 @@ namespace chaiscript
|
||||
}
|
||||
typename Container::iterator pos = m_end;
|
||||
--pos;
|
||||
return *(pos);
|
||||
return (*(pos));
|
||||
}
|
||||
|
||||
typename Container::iterator m_begin;
|
||||
@@ -129,24 +128,24 @@ namespace chaiscript
|
||||
--m_end;
|
||||
}
|
||||
|
||||
const_reference_type front() const
|
||||
decltype(auto) front() const
|
||||
{
|
||||
if (empty())
|
||||
{
|
||||
throw std::range_error("Range empty");
|
||||
}
|
||||
return *m_begin;
|
||||
return (*m_begin);
|
||||
}
|
||||
|
||||
const_reference_type back() const
|
||||
decltype(auto) back() const
|
||||
{
|
||||
if (empty())
|
||||
{
|
||||
throw std::range_error("Range empty");
|
||||
}
|
||||
typename Container::const_iterator pos = m_end;
|
||||
auto pos = m_end;
|
||||
--pos;
|
||||
return *(pos);
|
||||
return (*(pos));
|
||||
}
|
||||
|
||||
typename Container::const_iterator m_begin;
|
||||
@@ -482,12 +481,8 @@ namespace chaiscript
|
||||
{
|
||||
m.add(user_type<PairType>(), type);
|
||||
|
||||
|
||||
typename PairType::first_type PairType::* f = &PairType::first;
|
||||
typename PairType::second_type PairType::* s = &PairType::second;
|
||||
|
||||
m.add(fun(f), "first");
|
||||
m.add(fun(s), "second");
|
||||
m.add(fun(&PairType::first), "first");
|
||||
m.add(fun(&PairType::second), "second");
|
||||
|
||||
basic_constructors<PairType>(type, m);
|
||||
m.add(constructor<PairType (const typename PairType::first_type &, const typename PairType::second_type &)>(), type);
|
||||
@@ -605,7 +600,6 @@ namespace chaiscript
|
||||
}
|
||||
|
||||
|
||||
/// hopefully working List type
|
||||
/// http://www.sgi.com/tech/stl/List.html
|
||||
template<typename ListType>
|
||||
void list_type(const std::string &type, Module& m)
|
||||
|
@@ -69,11 +69,11 @@ namespace chaiscript
|
||||
/// assert(i == 5);
|
||||
/// \endcode
|
||||
template<typename Type>
|
||||
typename detail::Cast_Helper<Type>::Result_Type boxed_cast(const Boxed_Value &bv, const Type_Conversions_State *t_conversions = nullptr)
|
||||
decltype(auto) boxed_cast(const Boxed_Value &bv, const Type_Conversions_State *t_conversions = nullptr)
|
||||
{
|
||||
if (!t_conversions || bv.get_type_info().bare_equal(user_type<Type>()) || (t_conversions && !(*t_conversions)->convertable_type<Type>())) {
|
||||
try {
|
||||
return detail::Cast_Helper<Type>::cast(bv, t_conversions);
|
||||
return(detail::Cast_Helper<Type>::cast(bv, t_conversions));
|
||||
} catch (const chaiscript::detail::exception::bad_any_cast &) {
|
||||
}
|
||||
}
|
||||
@@ -84,11 +84,11 @@ namespace chaiscript
|
||||
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<Type>::cast((*t_conversions)->boxed_type_conversion<Type>(t_conversions->saves(), bv), t_conversions);
|
||||
return(detail::Cast_Helper<Type>::cast((*t_conversions)->boxed_type_conversion<Type>(t_conversions->saves(), bv), t_conversions));
|
||||
} catch (...) {
|
||||
try {
|
||||
// try going the other way
|
||||
return detail::Cast_Helper<Type>::cast((*t_conversions)->boxed_type_down_conversion<Type>(t_conversions->saves(), bv), t_conversions);
|
||||
return(detail::Cast_Helper<Type>::cast((*t_conversions)->boxed_type_down_conversion<Type>(t_conversions->saves(), bv), t_conversions));
|
||||
} catch (const chaiscript::detail::exception::bad_any_cast &) {
|
||||
throw exception::bad_boxed_cast(bv.get_type_info(), typeid(Type));
|
||||
}
|
||||
|
@@ -29,21 +29,50 @@ namespace chaiscript
|
||||
throw std::runtime_error("Attempted to dereference null Boxed_Value");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static const T *verify_type_no_throw(const Boxed_Value &ob, const std::type_info &ti, const T *ptr) {
|
||||
if (ob.get_type_info() == ti) {
|
||||
return ptr;
|
||||
} else {
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static T *verify_type_no_throw(const Boxed_Value &ob, const std::type_info &ti, T *ptr) {
|
||||
if (!ob.is_const() && ob.get_type_info() == ti) {
|
||||
return ptr;
|
||||
} else {
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<typename T>
|
||||
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)) {
|
||||
return throw_if_null(ptr);
|
||||
} else {
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static T *verify_type(const Boxed_Value &ob, const std::type_info &ti, T *ptr) {
|
||||
if (!ob.is_const() && ob.get_type_info().bare_equal_type_info(ti)) {
|
||||
return throw_if_null(ptr);
|
||||
} else {
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
}
|
||||
}
|
||||
|
||||
/// Generic Cast_Helper_Inner, for casting to any type
|
||||
template<typename Result>
|
||||
struct Cast_Helper_Inner
|
||||
{
|
||||
typedef typename std::add_const<Result>::type Result_Type;
|
||||
|
||||
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions_State *)
|
||||
static Result cast(const Boxed_Value &ob, const Type_Conversions_State *)
|
||||
{
|
||||
if (ob.get_type_info().bare_equal_type_info(typeid(Result)))
|
||||
{
|
||||
auto p = throw_if_null(ob.get_const_ptr());
|
||||
return *static_cast<const Result *>(p);
|
||||
} else {
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
}
|
||||
return *static_cast<const Result *>(verify_type(ob, typeid(Result), ob.get_const_ptr()));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -57,15 +86,9 @@ namespace chaiscript
|
||||
template<typename Result>
|
||||
struct Cast_Helper_Inner<const Result *>
|
||||
{
|
||||
typedef const Result * Result_Type;
|
||||
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions_State *)
|
||||
static const Result * cast(const Boxed_Value &ob, const Type_Conversions_State *)
|
||||
{
|
||||
if (ob.get_type_info().bare_equal_type_info(typeid(Result)))
|
||||
{
|
||||
return static_cast<const Result *>(ob.get_const_ptr());
|
||||
} else {
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
}
|
||||
return static_cast<const Result *>(verify_type_no_throw(ob, typeid(Result), ob.get_const_ptr()));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -73,15 +96,9 @@ namespace chaiscript
|
||||
template<typename Result>
|
||||
struct Cast_Helper_Inner<Result *>
|
||||
{
|
||||
typedef Result * Result_Type;
|
||||
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions_State *)
|
||||
static Result * cast(const Boxed_Value &ob, const Type_Conversions_State *)
|
||||
{
|
||||
if (!ob.get_type_info().is_const() && ob.get_type_info() == typeid(Result))
|
||||
{
|
||||
return static_cast<Result *>(ob.get_ptr());
|
||||
} else {
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
}
|
||||
return static_cast<Result *>(verify_type_no_throw(ob, typeid(Result), ob.get_ptr()));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -100,17 +117,9 @@ namespace chaiscript
|
||||
template<typename Result>
|
||||
struct Cast_Helper_Inner<const Result &>
|
||||
{
|
||||
typedef const Result& Result_Type;
|
||||
|
||||
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions_State *)
|
||||
static const Result & cast(const Boxed_Value &ob, const Type_Conversions_State *)
|
||||
{
|
||||
if (ob.get_type_info().bare_equal_type_info(typeid(Result)))
|
||||
{
|
||||
auto p = throw_if_null(ob.get_const_ptr());
|
||||
return *static_cast<const Result *>(p);
|
||||
} else {
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
}
|
||||
return *static_cast<const Result *>(verify_type(ob, typeid(Result), ob.get_const_ptr()));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -120,16 +129,9 @@ namespace chaiscript
|
||||
template<typename Result>
|
||||
struct Cast_Helper_Inner<Result &>
|
||||
{
|
||||
typedef Result& Result_Type;
|
||||
|
||||
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions_State *)
|
||||
static Result& cast(const Boxed_Value &ob, const Type_Conversions_State *)
|
||||
{
|
||||
if (!ob.get_type_info().is_const() && ob.get_type_info().bare_equal_type_info(typeid(Result)))
|
||||
{
|
||||
return *(static_cast<Result *>(throw_if_null(ob.get_ptr())));
|
||||
} else {
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
}
|
||||
return *static_cast<Result *>(verify_type(ob, typeid(Result), ob.get_ptr()));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -137,9 +139,7 @@ namespace chaiscript
|
||||
template<typename Result>
|
||||
struct Cast_Helper_Inner<std::shared_ptr<Result> >
|
||||
{
|
||||
typedef std::shared_ptr<Result> Result_Type;
|
||||
|
||||
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions_State *)
|
||||
static auto cast(const Boxed_Value &ob, const Type_Conversions_State *)
|
||||
{
|
||||
return ob.get().cast<std::shared_ptr<Result> >();
|
||||
}
|
||||
@@ -149,9 +149,7 @@ namespace chaiscript
|
||||
template<typename Result>
|
||||
struct Cast_Helper_Inner<std::shared_ptr<const Result> >
|
||||
{
|
||||
typedef std::shared_ptr<const Result> Result_Type;
|
||||
|
||||
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions_State *)
|
||||
static auto cast(const Boxed_Value &ob, const Type_Conversions_State *)
|
||||
{
|
||||
if (!ob.get_type_info().is_const())
|
||||
{
|
||||
@@ -177,10 +175,7 @@ namespace chaiscript
|
||||
struct Cast_Helper_Inner<std::shared_ptr<Result> &>
|
||||
{
|
||||
static_assert(!std::is_const<Result>::value, "Non-const reference to std::shared_ptr<const T> is not supported");
|
||||
|
||||
typedef Boxed_Value::Sentinel<Result> Result_Type;
|
||||
|
||||
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions_State *)
|
||||
static auto cast(const Boxed_Value &ob, const Type_Conversions_State *)
|
||||
{
|
||||
std::shared_ptr<Result> &res = ob.get().cast<std::shared_ptr<Result> >();
|
||||
return ob.pointer_sentinel(res);
|
||||
@@ -204,9 +199,7 @@ namespace chaiscript
|
||||
template<>
|
||||
struct Cast_Helper_Inner<Boxed_Value>
|
||||
{
|
||||
typedef Boxed_Value Result_Type;
|
||||
|
||||
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions_State *)
|
||||
static Boxed_Value cast(const Boxed_Value &ob, const Type_Conversions_State *)
|
||||
{
|
||||
return ob;
|
||||
}
|
||||
@@ -216,9 +209,7 @@ namespace chaiscript
|
||||
template<>
|
||||
struct Cast_Helper_Inner<Boxed_Value &>
|
||||
{
|
||||
typedef std::reference_wrapper<Boxed_Value> Result_Type;
|
||||
|
||||
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions_State *)
|
||||
static std::reference_wrapper<Boxed_Value> cast(const Boxed_Value &ob, const Type_Conversions_State *)
|
||||
{
|
||||
return std::ref(const_cast<Boxed_Value &>(ob));
|
||||
}
|
||||
@@ -272,11 +263,9 @@ namespace chaiscript
|
||||
template<typename T>
|
||||
struct Cast_Helper
|
||||
{
|
||||
typedef typename Cast_Helper_Inner<T>::Result_Type Result_Type;
|
||||
|
||||
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions_State *t_conversions)
|
||||
static decltype(auto) cast(const Boxed_Value &ob, const Type_Conversions_State *t_conversions)
|
||||
{
|
||||
return Cast_Helper_Inner<T>::cast(ob, t_conversions);
|
||||
return(Cast_Helper_Inner<T>::cast(ob, t_conversions));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@@ -162,17 +162,17 @@ namespace chaiscript
|
||||
{
|
||||
switch (t_oper)
|
||||
{
|
||||
case Operators::equals:
|
||||
case Operators::Opers::equals:
|
||||
return const_var(t == u);
|
||||
case Operators::less_than:
|
||||
case Operators::Opers::less_than:
|
||||
return const_var(t < u);
|
||||
case Operators::greater_than:
|
||||
case Operators::Opers::greater_than:
|
||||
return const_var(t > u);
|
||||
case Operators::less_than_equal:
|
||||
case Operators::Opers::less_than_equal:
|
||||
return const_var(t <= u);
|
||||
case Operators::greater_than_equal:
|
||||
case Operators::Opers::greater_than_equal:
|
||||
return const_var(t >= u);
|
||||
case Operators::not_equal:
|
||||
case Operators::Opers::not_equal:
|
||||
return const_var(t != u);
|
||||
default:
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
@@ -184,10 +184,10 @@ namespace chaiscript
|
||||
{
|
||||
switch (t_oper)
|
||||
{
|
||||
case Operators::pre_increment:
|
||||
case Operators::Opers::pre_increment:
|
||||
++t;
|
||||
break;
|
||||
case Operators::pre_decrement:
|
||||
case Operators::Opers::pre_decrement:
|
||||
--t;
|
||||
break;
|
||||
default:
|
||||
@@ -202,20 +202,20 @@ namespace chaiscript
|
||||
{
|
||||
switch (t_oper)
|
||||
{
|
||||
case Operators::assign:
|
||||
case Operators::Opers::assign:
|
||||
t = u;
|
||||
break;
|
||||
case Operators::assign_product:
|
||||
case Operators::Opers::assign_product:
|
||||
t *= u;
|
||||
break;
|
||||
case Operators::assign_sum:
|
||||
case Operators::Opers::assign_sum:
|
||||
t += u;
|
||||
break;
|
||||
case Operators::assign_quotient:
|
||||
case Operators::Opers::assign_quotient:
|
||||
check_divide_by_zero(u);
|
||||
t /= u;
|
||||
break;
|
||||
case Operators::assign_difference:
|
||||
case Operators::Opers::assign_difference:
|
||||
t -= u;
|
||||
break;
|
||||
default:
|
||||
@@ -230,23 +230,23 @@ namespace chaiscript
|
||||
{
|
||||
switch (t_oper)
|
||||
{
|
||||
case Operators::assign_bitwise_and:
|
||||
case Operators::Opers::assign_bitwise_and:
|
||||
t &= u;
|
||||
break;
|
||||
case Operators::assign_bitwise_or:
|
||||
case Operators::Opers::assign_bitwise_or:
|
||||
t |= u;
|
||||
break;
|
||||
case Operators::assign_shift_left:
|
||||
case Operators::Opers::assign_shift_left:
|
||||
t <<= u;
|
||||
break;
|
||||
case Operators::assign_shift_right:
|
||||
case Operators::Opers::assign_shift_right:
|
||||
t >>= u;
|
||||
break;
|
||||
case Operators::assign_remainder:
|
||||
case Operators::Opers::assign_remainder:
|
||||
check_divide_by_zero(u);
|
||||
t %= u;
|
||||
break;
|
||||
case Operators::assign_bitwise_xor:
|
||||
case Operators::Opers::assign_bitwise_xor:
|
||||
t ^= u;
|
||||
break;
|
||||
default:
|
||||
@@ -260,7 +260,7 @@ namespace chaiscript
|
||||
{
|
||||
switch (t_oper)
|
||||
{
|
||||
case Operators::bitwise_complement:
|
||||
case Operators::Opers::bitwise_complement:
|
||||
return const_var(~t);
|
||||
default:
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
@@ -272,18 +272,18 @@ namespace chaiscript
|
||||
{
|
||||
switch (t_oper)
|
||||
{
|
||||
case Operators::shift_left:
|
||||
case Operators::Opers::shift_left:
|
||||
return const_var(t << u);
|
||||
case Operators::shift_right:
|
||||
case Operators::Opers::shift_right:
|
||||
return const_var(t >> u);
|
||||
case Operators::remainder:
|
||||
case Operators::Opers::remainder:
|
||||
check_divide_by_zero(u);
|
||||
return const_var(t % u);
|
||||
case Operators::bitwise_and:
|
||||
case Operators::Opers::bitwise_and:
|
||||
return const_var(t & u);
|
||||
case Operators::bitwise_or:
|
||||
case Operators::Opers::bitwise_or:
|
||||
return const_var(t | u);
|
||||
case Operators::bitwise_xor:
|
||||
case Operators::Opers::bitwise_xor:
|
||||
return const_var(t ^ u);
|
||||
default:
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
@@ -295,9 +295,9 @@ namespace chaiscript
|
||||
{
|
||||
switch (t_oper)
|
||||
{
|
||||
case Operators::unary_minus:
|
||||
case Operators::Opers::unary_minus:
|
||||
return const_var(-t);
|
||||
case Operators::unary_plus:
|
||||
case Operators::Opers::unary_plus:
|
||||
return const_var(+t);
|
||||
default:
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
@@ -309,14 +309,14 @@ namespace chaiscript
|
||||
{
|
||||
switch (t_oper)
|
||||
{
|
||||
case Operators::sum:
|
||||
case Operators::Opers::sum:
|
||||
return const_var(t + u);
|
||||
case Operators::quotient:
|
||||
case Operators::Opers::quotient:
|
||||
check_divide_by_zero(u);
|
||||
return const_var(t / u);
|
||||
case Operators::product:
|
||||
case Operators::Opers::product:
|
||||
return const_var(t * u);
|
||||
case Operators::difference:
|
||||
case Operators::Opers::difference:
|
||||
return const_var(t - u);
|
||||
default:
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
@@ -328,16 +328,16 @@ namespace chaiscript
|
||||
-> typename std::enable_if<!std::is_floating_point<LHS>::value && !std::is_floating_point<RHS>::value, Boxed_Value>::type
|
||||
{
|
||||
typedef typename std::common_type<LHS, RHS>::type common_type;
|
||||
if (t_oper > Operators::boolean_flag && t_oper < Operators::non_const_flag)
|
||||
if (t_oper > Operators::Opers::boolean_flag && t_oper < Operators::Opers::non_const_flag)
|
||||
{
|
||||
return boolean_go(t_oper, get_as_aux<common_type, LHS>(t_lhs), get_as_aux<common_type, RHS>(t_rhs));
|
||||
} else if (t_oper > Operators::non_const_flag && t_oper < Operators::non_const_int_flag && !t_lhs.is_const() && !t_lhs.is_return_value()) {
|
||||
} else if (t_oper > Operators::Opers::non_const_flag && t_oper < Operators::Opers::non_const_int_flag && !t_lhs.is_const() && !t_lhs.is_return_value()) {
|
||||
return binary_go(t_oper, *static_cast<LHS *>(t_lhs.get_ptr()), get_as_aux<common_type, RHS>(t_rhs), t_lhs);
|
||||
} else if (t_oper > Operators::non_const_int_flag && t_oper < Operators::const_int_flag && !t_lhs.is_const() && !t_lhs.is_return_value()) {
|
||||
} else if (t_oper > Operators::Opers::non_const_int_flag && t_oper < Operators::Opers::const_int_flag && !t_lhs.is_const() && !t_lhs.is_return_value()) {
|
||||
return binary_int_go(t_oper, *static_cast<LHS *>(t_lhs.get_ptr()), get_as_aux<common_type, RHS>(t_rhs), t_lhs);
|
||||
} else if (t_oper > Operators::const_int_flag && t_oper < Operators::const_flag) {
|
||||
} else if (t_oper > Operators::Opers::const_int_flag && t_oper < Operators::Opers::const_flag) {
|
||||
return const_binary_int_go(t_oper, get_as_aux<common_type, LHS>(t_lhs), get_as_aux<common_type, RHS>(t_rhs));
|
||||
} else if (t_oper > Operators::const_flag) {
|
||||
} else if (t_oper > Operators::Opers::const_flag) {
|
||||
return const_binary_go(t_oper, get_as_aux<common_type, LHS>(t_lhs), get_as_aux<common_type, RHS>(t_rhs));
|
||||
} else {
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
@@ -349,12 +349,12 @@ namespace chaiscript
|
||||
-> typename std::enable_if<std::is_floating_point<LHS>::value || std::is_floating_point<RHS>::value, Boxed_Value>::type
|
||||
{
|
||||
typedef typename std::common_type<LHS, RHS>::type common_type;
|
||||
if (t_oper > Operators::boolean_flag && t_oper < Operators::non_const_flag)
|
||||
if (t_oper > Operators::Opers::boolean_flag && t_oper < Operators::Opers::non_const_flag)
|
||||
{
|
||||
return boolean_go(t_oper, get_as_aux<common_type, LHS>(t_lhs), get_as_aux<common_type, RHS>(t_rhs));
|
||||
} else if (t_oper > Operators::non_const_flag && t_oper < Operators::non_const_int_flag && !t_lhs.is_const() && !t_lhs.is_return_value()) {
|
||||
} else if (t_oper > Operators::Opers::non_const_flag && t_oper < Operators::Opers::non_const_int_flag && !t_lhs.is_const() && !t_lhs.is_return_value()) {
|
||||
return binary_go(t_oper, *static_cast<LHS *>(t_lhs.get_ptr()), get_as_aux<common_type, RHS>(t_rhs), t_lhs);
|
||||
} else if (t_oper > Operators::const_flag) {
|
||||
} else if (t_oper > Operators::Opers::const_flag) {
|
||||
return const_binary_go(t_oper, get_as_aux<common_type, LHS>(t_lhs), get_as_aux<common_type, RHS>(t_rhs));
|
||||
} else {
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
@@ -366,11 +366,11 @@ namespace chaiscript
|
||||
static auto go(Operators::Opers t_oper, const Boxed_Value &t_lhs)
|
||||
-> typename std::enable_if<!std::is_floating_point<LHS>::value, Boxed_Value>::type
|
||||
{
|
||||
if (t_oper > Operators::non_const_flag && t_oper < Operators::non_const_int_flag && !t_lhs.is_const() && !t_lhs.is_return_value()) {
|
||||
if (t_oper > Operators::Opers::non_const_flag && t_oper < Operators::Opers::non_const_int_flag && !t_lhs.is_const() && !t_lhs.is_return_value()) {
|
||||
return unary_go(t_oper, *static_cast<LHS *>(t_lhs.get_ptr()), t_lhs);
|
||||
} else if (t_oper > Operators::const_int_flag && t_oper < Operators::const_flag) {
|
||||
} else if (t_oper > Operators::Opers::const_int_flag && t_oper < Operators::Opers::const_flag) {
|
||||
return const_unary_int_go(t_oper, *static_cast<const LHS *>(t_lhs.get_const_ptr()));
|
||||
} else if (t_oper > Operators::const_flag) {
|
||||
} else if (t_oper > Operators::Opers::const_flag) {
|
||||
return const_unary_go(t_oper, *static_cast<const LHS *>(t_lhs.get_const_ptr()));
|
||||
} else {
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
@@ -381,9 +381,9 @@ namespace chaiscript
|
||||
static auto go(Operators::Opers t_oper, const Boxed_Value &t_lhs)
|
||||
-> typename std::enable_if<std::is_floating_point<LHS>::value, Boxed_Value>::type
|
||||
{
|
||||
if (t_oper > Operators::non_const_flag && t_oper < Operators::non_const_int_flag && !t_lhs.is_const() && !t_lhs.is_return_value()) {
|
||||
if (t_oper > Operators::Opers::non_const_flag && t_oper < Operators::Opers::non_const_int_flag && !t_lhs.is_const() && !t_lhs.is_return_value()) {
|
||||
return unary_go(t_oper, *static_cast<LHS *>(t_lhs.get_ptr()), t_lhs);
|
||||
} else if (t_oper > Operators::const_flag) {
|
||||
} else if (t_oper > Operators::Opers::const_flag) {
|
||||
return const_unary_go(t_oper, *static_cast<const LHS *>(t_lhs.get_const_ptr()));
|
||||
} else {
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
@@ -502,7 +502,7 @@ namespace chaiscript
|
||||
{
|
||||
}
|
||||
|
||||
Boxed_Number(Boxed_Value v)
|
||||
explicit Boxed_Number(Boxed_Value v)
|
||||
: bv(std::move(v))
|
||||
{
|
||||
validate_boxed_number(bv);
|
||||
@@ -645,71 +645,6 @@ namespace chaiscript
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
}
|
||||
|
||||
bool operator==(const Boxed_Number &t_rhs) const
|
||||
{
|
||||
return boxed_cast<bool>(oper(Operators::equals, this->bv, t_rhs.bv));
|
||||
}
|
||||
|
||||
bool operator<(const Boxed_Number &t_rhs) const
|
||||
{
|
||||
return boxed_cast<bool>(oper(Operators::less_than, this->bv, t_rhs.bv));
|
||||
}
|
||||
|
||||
bool operator>(const Boxed_Number &t_rhs) const
|
||||
{
|
||||
return boxed_cast<bool>(oper(Operators::greater_than, this->bv, t_rhs.bv));
|
||||
}
|
||||
|
||||
bool operator>=(const Boxed_Number &t_rhs) const
|
||||
{
|
||||
return boxed_cast<bool>(oper(Operators::greater_than_equal, this->bv, t_rhs.bv));
|
||||
}
|
||||
|
||||
bool operator<=(const Boxed_Number &t_rhs) const
|
||||
{
|
||||
return boxed_cast<bool>(oper(Operators::less_than_equal, this->bv, t_rhs.bv));
|
||||
}
|
||||
|
||||
bool operator!=(const Boxed_Number &t_rhs) const
|
||||
{
|
||||
return boxed_cast<bool>(oper(Operators::not_equal, this->bv, t_rhs.bv));
|
||||
}
|
||||
|
||||
Boxed_Number operator--()
|
||||
{
|
||||
return oper(Operators::pre_decrement, this->bv);
|
||||
}
|
||||
|
||||
Boxed_Number operator++()
|
||||
{
|
||||
return oper(Operators::pre_increment, this->bv);
|
||||
}
|
||||
|
||||
Boxed_Number operator+(const Boxed_Number &t_rhs) const
|
||||
{
|
||||
return oper(Operators::sum, this->bv, t_rhs.bv);
|
||||
}
|
||||
|
||||
Boxed_Number operator+() const
|
||||
{
|
||||
return oper(Operators::unary_plus, this->bv);
|
||||
}
|
||||
|
||||
Boxed_Number operator-() const
|
||||
{
|
||||
return oper(Operators::unary_minus, this->bv);
|
||||
}
|
||||
|
||||
Boxed_Number operator-(const Boxed_Number &t_rhs) const
|
||||
{
|
||||
return oper(Operators::difference, this->bv, t_rhs.bv);
|
||||
}
|
||||
|
||||
Boxed_Number operator&=(const Boxed_Number &t_rhs)
|
||||
{
|
||||
return oper(Operators::assign_bitwise_and, this->bv, t_rhs.bv);
|
||||
}
|
||||
|
||||
static void validate_boxed_number(const Boxed_Value &v)
|
||||
{
|
||||
const Type_Info &inp_ = v.get_type_info();
|
||||
@@ -724,266 +659,165 @@ namespace chaiscript
|
||||
}
|
||||
}
|
||||
|
||||
// cppcheck-suppress operatorEq
|
||||
Boxed_Number operator=(const Boxed_Value &v)
|
||||
{
|
||||
validate_boxed_number(v);
|
||||
bv = v;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// cppcheck-suppress operatorEq
|
||||
Boxed_Number operator=(const Boxed_Number &t_rhs) const
|
||||
{
|
||||
return oper(Operators::assign, this->bv, t_rhs.bv);
|
||||
}
|
||||
|
||||
Boxed_Number operator|=(const Boxed_Number &t_rhs)
|
||||
{
|
||||
return oper(Operators::assign_bitwise_or, this->bv, t_rhs.bv);
|
||||
}
|
||||
|
||||
Boxed_Number operator^=(const Boxed_Number &t_rhs)
|
||||
{
|
||||
return oper(Operators::assign_bitwise_xor, this->bv, t_rhs.bv);
|
||||
}
|
||||
|
||||
Boxed_Number operator%=(const Boxed_Number &t_rhs)
|
||||
{
|
||||
return oper(Operators::assign_remainder, this->bv, t_rhs.bv);
|
||||
}
|
||||
|
||||
Boxed_Number operator<<=(const Boxed_Number &t_rhs)
|
||||
{
|
||||
return oper(Operators::assign_shift_left, this->bv, t_rhs.bv);
|
||||
}
|
||||
|
||||
Boxed_Number operator>>=(const Boxed_Number &t_rhs)
|
||||
{
|
||||
return oper(Operators::assign_shift_right, this->bv, t_rhs.bv);
|
||||
}
|
||||
|
||||
Boxed_Number operator&(const Boxed_Number &t_rhs) const
|
||||
{
|
||||
return oper(Operators::bitwise_and, this->bv, t_rhs.bv);
|
||||
}
|
||||
|
||||
Boxed_Number operator~() const
|
||||
{
|
||||
return oper(Operators::bitwise_complement, this->bv);
|
||||
}
|
||||
|
||||
Boxed_Number operator^(const Boxed_Number &t_rhs) const
|
||||
{
|
||||
return oper(Operators::bitwise_xor, this->bv, t_rhs.bv);
|
||||
}
|
||||
|
||||
Boxed_Number operator|(const Boxed_Number &t_rhs) const
|
||||
{
|
||||
return oper(Operators::bitwise_or, this->bv, t_rhs.bv);
|
||||
}
|
||||
|
||||
Boxed_Number operator*=(const Boxed_Number &t_rhs)
|
||||
{
|
||||
return oper(Operators::assign_product, this->bv, t_rhs.bv);
|
||||
}
|
||||
Boxed_Number operator/=(const Boxed_Number &t_rhs)
|
||||
{
|
||||
return oper(Operators::assign_quotient, this->bv, t_rhs.bv);
|
||||
}
|
||||
Boxed_Number operator+=(const Boxed_Number &t_rhs)
|
||||
{
|
||||
return oper(Operators::assign_sum, this->bv, t_rhs.bv);
|
||||
}
|
||||
Boxed_Number operator-=(const Boxed_Number &t_rhs)
|
||||
{
|
||||
return oper(Operators::assign_difference, this->bv, t_rhs.bv);
|
||||
}
|
||||
|
||||
Boxed_Number operator/(const Boxed_Number &t_rhs) const
|
||||
{
|
||||
return oper(Operators::quotient, this->bv, t_rhs.bv);
|
||||
}
|
||||
|
||||
Boxed_Number operator<<(const Boxed_Number &t_rhs) const
|
||||
{
|
||||
return oper(Operators::shift_left, this->bv, t_rhs.bv);
|
||||
}
|
||||
|
||||
Boxed_Number operator*(const Boxed_Number &t_rhs) const
|
||||
{
|
||||
return oper(Operators::product, this->bv, t_rhs.bv);
|
||||
}
|
||||
|
||||
Boxed_Number operator%(const Boxed_Number &t_rhs) const
|
||||
{
|
||||
return oper(Operators::remainder, this->bv, t_rhs.bv);
|
||||
}
|
||||
|
||||
Boxed_Number operator>>(const Boxed_Number &t_rhs) const
|
||||
{
|
||||
return oper(Operators::shift_right, this->bv, t_rhs.bv);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static bool equals(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs)
|
||||
{
|
||||
return boxed_cast<bool>(oper(Operators::equals, t_lhs.bv, t_rhs.bv));
|
||||
return boxed_cast<bool>(oper(Operators::Opers::equals, t_lhs.bv, t_rhs.bv));
|
||||
}
|
||||
|
||||
static bool less_than(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs)
|
||||
{
|
||||
return boxed_cast<bool>(oper(Operators::less_than, t_lhs.bv, t_rhs.bv));
|
||||
return boxed_cast<bool>(oper(Operators::Opers::less_than, t_lhs.bv, t_rhs.bv));
|
||||
}
|
||||
|
||||
static bool greater_than(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs)
|
||||
{
|
||||
return boxed_cast<bool>(oper(Operators::greater_than, t_lhs.bv, t_rhs.bv));
|
||||
return boxed_cast<bool>(oper(Operators::Opers::greater_than, t_lhs.bv, t_rhs.bv));
|
||||
}
|
||||
|
||||
static bool greater_than_equal(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs)
|
||||
{
|
||||
return boxed_cast<bool>(oper(Operators::greater_than_equal, t_lhs.bv, t_rhs.bv));
|
||||
return boxed_cast<bool>(oper(Operators::Opers::greater_than_equal, t_lhs.bv, t_rhs.bv));
|
||||
}
|
||||
|
||||
static bool less_than_equal(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs)
|
||||
{
|
||||
return boxed_cast<bool>(oper(Operators::less_than_equal, t_lhs.bv, t_rhs.bv));
|
||||
return boxed_cast<bool>(oper(Operators::Opers::less_than_equal, t_lhs.bv, t_rhs.bv));
|
||||
}
|
||||
|
||||
static bool not_equal(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs)
|
||||
{
|
||||
return boxed_cast<bool>(oper(Operators::not_equal, t_lhs.bv, t_rhs.bv));
|
||||
return boxed_cast<bool>(oper(Operators::Opers::not_equal, t_lhs.bv, t_rhs.bv));
|
||||
}
|
||||
|
||||
static Boxed_Number pre_decrement(Boxed_Number t_lhs)
|
||||
{
|
||||
return oper(Operators::pre_decrement, t_lhs.bv);
|
||||
return Boxed_Number(oper(Operators::Opers::pre_decrement, t_lhs.bv));
|
||||
}
|
||||
|
||||
static Boxed_Number pre_increment(Boxed_Number t_lhs)
|
||||
{
|
||||
return oper(Operators::pre_increment, t_lhs.bv);
|
||||
return Boxed_Number(oper(Operators::Opers::pre_increment, t_lhs.bv));
|
||||
}
|
||||
|
||||
static const Boxed_Number sum(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs)
|
||||
{
|
||||
return oper(Operators::sum, t_lhs.bv, t_rhs.bv);
|
||||
return Boxed_Number(oper(Operators::Opers::sum, t_lhs.bv, t_rhs.bv));
|
||||
}
|
||||
|
||||
static const Boxed_Number unary_plus(const Boxed_Number &t_lhs)
|
||||
{
|
||||
return oper(Operators::unary_plus, t_lhs.bv);
|
||||
return Boxed_Number(oper(Operators::Opers::unary_plus, t_lhs.bv));
|
||||
}
|
||||
|
||||
static const Boxed_Number unary_minus(const Boxed_Number &t_lhs)
|
||||
{
|
||||
return oper(Operators::unary_minus, t_lhs.bv);
|
||||
return Boxed_Number(oper(Operators::Opers::unary_minus, t_lhs.bv));
|
||||
}
|
||||
|
||||
static const Boxed_Number difference(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs)
|
||||
{
|
||||
return oper(Operators::difference, t_lhs.bv, t_rhs.bv);
|
||||
return Boxed_Number(oper(Operators::Opers::difference, t_lhs.bv, t_rhs.bv));
|
||||
}
|
||||
|
||||
static Boxed_Number assign_bitwise_and(Boxed_Number t_lhs, const Boxed_Number &t_rhs)
|
||||
{
|
||||
return oper(Operators::assign_bitwise_and, t_lhs.bv, t_rhs.bv);
|
||||
return Boxed_Number(oper(Operators::Opers::assign_bitwise_and, t_lhs.bv, t_rhs.bv));
|
||||
}
|
||||
|
||||
static Boxed_Number assign(Boxed_Number t_lhs, const Boxed_Number &t_rhs)
|
||||
{
|
||||
return oper(Operators::assign, t_lhs.bv, t_rhs.bv);
|
||||
return Boxed_Number(oper(Operators::Opers::assign, t_lhs.bv, t_rhs.bv));
|
||||
}
|
||||
|
||||
static Boxed_Number assign_bitwise_or(Boxed_Number t_lhs, const Boxed_Number &t_rhs)
|
||||
{
|
||||
return oper(Operators::assign_bitwise_or, t_lhs.bv, t_rhs.bv);
|
||||
return Boxed_Number(oper(Operators::Opers::assign_bitwise_or, t_lhs.bv, t_rhs.bv));
|
||||
}
|
||||
|
||||
static Boxed_Number assign_bitwise_xor(Boxed_Number t_lhs, const Boxed_Number &t_rhs)
|
||||
{
|
||||
return oper(Operators::assign_bitwise_xor, t_lhs.bv, t_rhs.bv);
|
||||
return Boxed_Number(oper(Operators::Opers::assign_bitwise_xor, t_lhs.bv, t_rhs.bv));
|
||||
}
|
||||
|
||||
static Boxed_Number assign_remainder(Boxed_Number t_lhs, const Boxed_Number &t_rhs)
|
||||
{
|
||||
return oper(Operators::assign_remainder, t_lhs.bv, t_rhs.bv);
|
||||
return Boxed_Number(oper(Operators::Opers::assign_remainder, t_lhs.bv, t_rhs.bv));
|
||||
}
|
||||
|
||||
static Boxed_Number assign_shift_left(Boxed_Number t_lhs, const Boxed_Number &t_rhs)
|
||||
{
|
||||
return oper(Operators::assign_shift_left, t_lhs.bv, t_rhs.bv);
|
||||
return Boxed_Number(oper(Operators::Opers::assign_shift_left, t_lhs.bv, t_rhs.bv));
|
||||
}
|
||||
|
||||
static Boxed_Number assign_shift_right(Boxed_Number t_lhs, const Boxed_Number &t_rhs)
|
||||
{
|
||||
return oper(Operators::assign_shift_right, t_lhs.bv, t_rhs.bv);
|
||||
return Boxed_Number(oper(Operators::Opers::assign_shift_right, t_lhs.bv, t_rhs.bv));
|
||||
}
|
||||
|
||||
static const Boxed_Number bitwise_and(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs)
|
||||
{
|
||||
return oper(Operators::bitwise_and, t_lhs.bv, t_rhs.bv);
|
||||
return Boxed_Number(oper(Operators::Opers::bitwise_and, t_lhs.bv, t_rhs.bv));
|
||||
}
|
||||
|
||||
static const Boxed_Number bitwise_complement(const Boxed_Number &t_lhs)
|
||||
{
|
||||
return oper(Operators::bitwise_complement, t_lhs.bv, Boxed_Value(0));
|
||||
return Boxed_Number(oper(Operators::Opers::bitwise_complement, t_lhs.bv, Boxed_Value(0)));
|
||||
}
|
||||
|
||||
static const Boxed_Number bitwise_xor(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs)
|
||||
{
|
||||
return oper(Operators::bitwise_xor, t_lhs.bv, t_rhs.bv);
|
||||
return Boxed_Number(oper(Operators::Opers::bitwise_xor, t_lhs.bv, t_rhs.bv));
|
||||
}
|
||||
|
||||
static const Boxed_Number bitwise_or(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs)
|
||||
{
|
||||
return oper(Operators::bitwise_or, t_lhs.bv, t_rhs.bv);
|
||||
return Boxed_Number(oper(Operators::Opers::bitwise_or, t_lhs.bv, t_rhs.bv));
|
||||
}
|
||||
|
||||
static Boxed_Number assign_product(Boxed_Number t_lhs, const Boxed_Number &t_rhs)
|
||||
{
|
||||
return oper(Operators::assign_product, t_lhs.bv, t_rhs.bv);
|
||||
return Boxed_Number(oper(Operators::Opers::assign_product, t_lhs.bv, t_rhs.bv));
|
||||
}
|
||||
|
||||
static Boxed_Number assign_quotient(Boxed_Number t_lhs, const Boxed_Number &t_rhs)
|
||||
{
|
||||
return oper(Operators::assign_quotient, t_lhs.bv, t_rhs.bv);
|
||||
return Boxed_Number(oper(Operators::Opers::assign_quotient, t_lhs.bv, t_rhs.bv));
|
||||
}
|
||||
|
||||
static Boxed_Number assign_sum(Boxed_Number t_lhs, const Boxed_Number &t_rhs)
|
||||
{
|
||||
return oper(Operators::assign_sum, t_lhs.bv, t_rhs.bv);
|
||||
return Boxed_Number(oper(Operators::Opers::assign_sum, t_lhs.bv, t_rhs.bv));
|
||||
}
|
||||
static Boxed_Number assign_difference(Boxed_Number t_lhs, const Boxed_Number &t_rhs)
|
||||
{
|
||||
return oper(Operators::assign_difference, t_lhs.bv, t_rhs.bv);
|
||||
return Boxed_Number(oper(Operators::Opers::assign_difference, t_lhs.bv, t_rhs.bv));
|
||||
}
|
||||
|
||||
static const Boxed_Number quotient(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs)
|
||||
{
|
||||
return oper(Operators::quotient, t_lhs.bv, t_rhs.bv);
|
||||
return Boxed_Number(oper(Operators::Opers::quotient, t_lhs.bv, t_rhs.bv));
|
||||
}
|
||||
|
||||
static const Boxed_Number shift_left(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs)
|
||||
{
|
||||
return oper(Operators::shift_left, t_lhs.bv, t_rhs.bv);
|
||||
return Boxed_Number(oper(Operators::Opers::shift_left, t_lhs.bv, t_rhs.bv));
|
||||
}
|
||||
|
||||
static const Boxed_Number product(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs)
|
||||
{
|
||||
return oper(Operators::product, t_lhs.bv, t_rhs.bv);
|
||||
return Boxed_Number(oper(Operators::Opers::product, t_lhs.bv, t_rhs.bv));
|
||||
}
|
||||
|
||||
static const Boxed_Number remainder(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs)
|
||||
{
|
||||
return oper(Operators::remainder, t_lhs.bv, t_rhs.bv);
|
||||
return Boxed_Number(oper(Operators::Opers::remainder, t_lhs.bv, t_rhs.bv));
|
||||
}
|
||||
|
||||
static const Boxed_Number shift_right(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs)
|
||||
{
|
||||
return oper(Operators::shift_right, t_lhs.bv, t_rhs.bv);
|
||||
return Boxed_Number(oper(Operators::Opers::shift_right, t_lhs.bv, t_rhs.bv));
|
||||
}
|
||||
|
||||
|
||||
@@ -1009,9 +843,7 @@ namespace chaiscript
|
||||
template<>
|
||||
struct Cast_Helper<Boxed_Number>
|
||||
{
|
||||
typedef Boxed_Number Result_Type;
|
||||
|
||||
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions_State *)
|
||||
static Boxed_Number cast(const Boxed_Value &ob, const Type_Conversions_State *)
|
||||
{
|
||||
return Boxed_Number(ob);
|
||||
}
|
||||
|
@@ -77,9 +77,9 @@ namespace chaiscript
|
||||
|
||||
struct Object_Data
|
||||
{
|
||||
static std::unique_ptr<Data> get(Boxed_Value::Void_Type, bool t_return_value)
|
||||
static auto get(Boxed_Value::Void_Type, bool t_return_value)
|
||||
{
|
||||
return std::make_unique<Data>(
|
||||
return std::make_shared<Data>(
|
||||
detail::Get_Type_Info<void>::get(),
|
||||
chaiscript::detail::Any(),
|
||||
false,
|
||||
@@ -89,15 +89,15 @@ namespace chaiscript
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static std::unique_ptr<Data> get(const std::shared_ptr<T> *obj, bool t_return_value)
|
||||
static auto get(const std::shared_ptr<T> *obj, bool t_return_value)
|
||||
{
|
||||
return get(*obj, t_return_value);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static std::unique_ptr<Data> get(const std::shared_ptr<T> &obj, bool t_return_value)
|
||||
static auto get(const std::shared_ptr<T> &obj, bool t_return_value)
|
||||
{
|
||||
return std::make_unique<Data>(
|
||||
return std::make_shared<Data>(
|
||||
detail::Get_Type_Info<T>::get(),
|
||||
chaiscript::detail::Any(obj),
|
||||
false,
|
||||
@@ -107,10 +107,10 @@ namespace chaiscript
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static std::unique_ptr<Data> get(std::shared_ptr<T> &&obj, bool t_return_value)
|
||||
static auto get(std::shared_ptr<T> &&obj, bool t_return_value)
|
||||
{
|
||||
auto ptr = obj.get();
|
||||
return std::make_unique<Data>(
|
||||
return std::make_shared<Data>(
|
||||
detail::Get_Type_Info<T>::get(),
|
||||
chaiscript::detail::Any(std::move(obj)),
|
||||
false,
|
||||
@@ -120,23 +120,23 @@ namespace chaiscript
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static std::unique_ptr<Data> get(T *t, bool t_return_value)
|
||||
static auto get(T *t, bool t_return_value)
|
||||
{
|
||||
return get(std::ref(*t), t_return_value);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static std::unique_ptr<Data> get(const T *t, bool t_return_value)
|
||||
static auto get(const T *t, bool t_return_value)
|
||||
{
|
||||
return get(std::cref(*t), t_return_value);
|
||||
}
|
||||
|
||||
|
||||
template<typename T>
|
||||
static std::unique_ptr<Data> get(std::reference_wrapper<T> obj, bool t_return_value)
|
||||
static auto get(std::reference_wrapper<T> obj, bool t_return_value)
|
||||
{
|
||||
auto p = &obj.get();
|
||||
return std::make_unique<Data>(
|
||||
return std::make_shared<Data>(
|
||||
detail::Get_Type_Info<T>::get(),
|
||||
chaiscript::detail::Any(std::move(obj)),
|
||||
true,
|
||||
@@ -146,11 +146,11 @@ namespace chaiscript
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static std::unique_ptr<Data> get(T t, bool t_return_value)
|
||||
static auto get(T t, bool t_return_value)
|
||||
{
|
||||
auto p = std::make_shared<T>(std::move(t));
|
||||
auto ptr = p.get();
|
||||
return std::make_unique<Data>(
|
||||
return std::make_shared<Data>(
|
||||
detail::Get_Type_Info<T>::get(),
|
||||
chaiscript::detail::Any(std::move(p)),
|
||||
false,
|
||||
@@ -159,9 +159,9 @@ namespace chaiscript
|
||||
);
|
||||
}
|
||||
|
||||
static std::unique_ptr<Data> get()
|
||||
static std::shared_ptr<Data> get()
|
||||
{
|
||||
return std::make_unique<Data>(
|
||||
return std::make_shared<Data>(
|
||||
Type_Info(),
|
||||
chaiscript::detail::Any(),
|
||||
false,
|
||||
@@ -182,10 +182,7 @@ namespace chaiscript
|
||||
}
|
||||
|
||||
/// Unknown-type constructor
|
||||
Boxed_Value()
|
||||
: m_data(Object_Data::get())
|
||||
{
|
||||
}
|
||||
Boxed_Value() = default;
|
||||
|
||||
Boxed_Value(Boxed_Value&&) = default;
|
||||
Boxed_Value& operator=(Boxed_Value&&) = default;
|
||||
@@ -226,48 +223,39 @@ namespace chaiscript
|
||||
return m_data->m_type_info.bare_equal(ti);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
struct Sentinel {
|
||||
Sentinel(std::shared_ptr<T> &ptr, Data &data)
|
||||
: m_ptr(ptr), m_data(data)
|
||||
{
|
||||
}
|
||||
|
||||
~Sentinel()
|
||||
{
|
||||
// save new pointer data
|
||||
m_data.get().m_data_ptr = m_ptr.get().get();
|
||||
m_data.get().m_const_data_ptr = m_ptr.get().get();
|
||||
}
|
||||
|
||||
Sentinel& operator=(Sentinel&&s) {
|
||||
m_ptr = std::move(s.m_ptr);
|
||||
m_data = std::move(s.m_data);
|
||||
}
|
||||
|
||||
Sentinel(Sentinel &&s)
|
||||
: m_ptr(std::move(s.m_ptr)),
|
||||
m_data(std::move(s.m_data))
|
||||
{
|
||||
}
|
||||
|
||||
operator std::shared_ptr<T>&() const
|
||||
{
|
||||
return m_ptr.get();
|
||||
}
|
||||
|
||||
Sentinel &operator=(const Sentinel &) = delete;
|
||||
Sentinel(Sentinel&) = delete;
|
||||
|
||||
std::reference_wrapper<std::shared_ptr<T>> m_ptr;
|
||||
std::reference_wrapper<Data> m_data;
|
||||
};
|
||||
|
||||
|
||||
template<typename T>
|
||||
Sentinel<T> pointer_sentinel(std::shared_ptr<T> &ptr) const
|
||||
auto pointer_sentinel(std::shared_ptr<T> &ptr) const
|
||||
{
|
||||
return Sentinel<T>(ptr, *(m_data.get()));
|
||||
struct Sentinel {
|
||||
Sentinel(std::shared_ptr<T> &t_ptr, Data &data)
|
||||
: m_ptr(t_ptr), m_data(data)
|
||||
{
|
||||
}
|
||||
|
||||
~Sentinel()
|
||||
{
|
||||
// save new pointer data
|
||||
m_data.get().m_data_ptr = m_ptr.get().get();
|
||||
m_data.get().m_const_data_ptr = m_ptr.get().get();
|
||||
}
|
||||
|
||||
Sentinel& operator=(Sentinel&&s) = default;
|
||||
Sentinel(Sentinel &&s) = default;
|
||||
|
||||
operator std::shared_ptr<T>&() const
|
||||
{
|
||||
return m_ptr.get();
|
||||
}
|
||||
|
||||
Sentinel &operator=(const Sentinel &) = delete;
|
||||
Sentinel(Sentinel&) = delete;
|
||||
|
||||
std::reference_wrapper<std::shared_ptr<T>> m_ptr;
|
||||
std::reference_wrapper<Data> m_data;
|
||||
};
|
||||
|
||||
return Sentinel(ptr, *(m_data.get()));
|
||||
}
|
||||
|
||||
bool is_null() const noexcept
|
||||
@@ -358,7 +346,7 @@ namespace chaiscript
|
||||
: m_data(t_data) {
|
||||
}
|
||||
|
||||
std::shared_ptr<Data> m_data;
|
||||
std::shared_ptr<Data> m_data = Object_Data::get();
|
||||
};
|
||||
|
||||
/// @brief Creates a Boxed_Value. If the object passed in is a value type, it is copied. If it is a pointer, std::shared_ptr, or std::reference_type
|
||||
|
@@ -8,7 +8,6 @@
|
||||
#define CHAISCRIPT_DISPATCHKIT_HPP_
|
||||
|
||||
#include <algorithm>
|
||||
#include <deque>
|
||||
#include <iostream>
|
||||
#include <list>
|
||||
#include <map>
|
||||
@@ -31,12 +30,16 @@
|
||||
#include "proxy_constructors.hpp"
|
||||
#include "proxy_functions.hpp"
|
||||
#include "type_info.hpp"
|
||||
#include "short_alloc.hpp"
|
||||
|
||||
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;
|
||||
@@ -45,6 +48,7 @@ struct Placeholder_Object;
|
||||
} // 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.
|
||||
|
||||
@@ -310,11 +314,6 @@ namespace chaiscript
|
||||
[&vals, &t_conversions](const Proxy_Function &f){ return f->call_match(vals, t_conversions); });
|
||||
}
|
||||
|
||||
std::string annotation() const override
|
||||
{
|
||||
return "Multiple method dispatch function wrapper.";
|
||||
}
|
||||
|
||||
protected:
|
||||
Boxed_Value do_call(const std::vector<Boxed_Value> ¶ms, const Type_Conversions_State &t_conversions) const override
|
||||
{
|
||||
@@ -377,22 +376,56 @@ namespace chaiscript
|
||||
{
|
||||
struct Stack_Holder
|
||||
{
|
||||
typedef std::vector<std::pair<std::string, Boxed_Value>> Scope;
|
||||
typedef std::vector<Scope> StackData;
|
||||
//template <class T, std::size_t BufSize = sizeof(T)*20000>
|
||||
// using SmallVector = std::vector<T, short_alloc<T, BufSize>>;
|
||||
|
||||
template <class T>
|
||||
using SmallVector = std::vector<T>;
|
||||
|
||||
|
||||
typedef SmallVector<std::pair<std::string, Boxed_Value>> Scope;
|
||||
typedef SmallVector<Scope> StackData;
|
||||
typedef SmallVector<StackData> Stacks;
|
||||
typedef SmallVector<Boxed_Value> Call_Param_List;
|
||||
typedef SmallVector<Call_Param_List> Call_Params;
|
||||
|
||||
Stack_Holder()
|
||||
: call_depth(0)
|
||||
{
|
||||
stacks.reserve(2);
|
||||
stacks.emplace_back(1);
|
||||
call_params.emplace_back();
|
||||
call_params.back().reserve(2);
|
||||
push_stack();
|
||||
push_call_params();
|
||||
}
|
||||
|
||||
std::vector<StackData> stacks;
|
||||
void push_stack_data()
|
||||
{
|
||||
stacks.back().emplace_back();
|
||||
// stacks.back().emplace_back(Scope(scope_allocator));
|
||||
}
|
||||
|
||||
std::vector<std::vector<Boxed_Value>> call_params;
|
||||
int call_depth;
|
||||
void push_stack()
|
||||
{
|
||||
stacks.emplace_back(1);
|
||||
// stacks.emplace_back(StackData(1, Scope(scope_allocator), stack_data_allocator));
|
||||
}
|
||||
|
||||
void push_call_params()
|
||||
{
|
||||
call_params.emplace_back();
|
||||
// call_params.emplace_back(Call_Param_List(call_param_list_allocator));
|
||||
}
|
||||
|
||||
//Scope::allocator_type::arena_type scope_allocator;
|
||||
//StackData::allocator_type::arena_type stack_data_allocator;
|
||||
//Stacks::allocator_type::arena_type stacks_allocator;
|
||||
//Call_Param_List::allocator_type::arena_type call_param_list_allocator;
|
||||
//Call_Params::allocator_type::arena_type call_params_allocator;
|
||||
|
||||
// Stacks stacks = Stacks(stacks_allocator);
|
||||
// Call_Params call_params = Call_Params(call_params_allocator);
|
||||
|
||||
Stacks stacks;
|
||||
Call_Params call_params;
|
||||
|
||||
int call_depth = 0;
|
||||
};
|
||||
|
||||
/// Main class for the dispatchkit. Handles management
|
||||
@@ -403,7 +436,7 @@ namespace chaiscript
|
||||
public:
|
||||
typedef std::map<std::string, chaiscript::Type_Info> Type_Name_Map;
|
||||
typedef std::vector<std::pair<std::string, Boxed_Value>> Scope;
|
||||
typedef std::vector<Scope> StackData;
|
||||
typedef Stack_Holder::StackData StackData;
|
||||
|
||||
struct State
|
||||
{
|
||||
@@ -412,28 +445,20 @@ namespace chaiscript
|
||||
std::vector<std::pair<std::string, Boxed_Value>> m_boxed_functions;
|
||||
std::map<std::string, Boxed_Value> m_global_objects;
|
||||
Type_Name_Map m_types;
|
||||
std::set<std::string> m_reserved_words;
|
||||
|
||||
State &operator=(const State &) = default;
|
||||
State() = default;
|
||||
State(const State &) = default;
|
||||
};
|
||||
|
||||
Dispatch_Engine()
|
||||
: m_stack_holder(this)
|
||||
{
|
||||
}
|
||||
|
||||
~Dispatch_Engine()
|
||||
Dispatch_Engine(chaiscript::parser::ChaiScript_Parser_Base &parser)
|
||||
: m_stack_holder(this),
|
||||
m_parser(parser)
|
||||
{
|
||||
}
|
||||
|
||||
/// \brief casts an object while applying any Dynamic_Conversion available
|
||||
template<typename Type>
|
||||
typename detail::Cast_Helper<Type>::Result_Type boxed_cast(const Boxed_Value &bv) const
|
||||
decltype(auto) boxed_cast(const Boxed_Value &bv) const
|
||||
{
|
||||
Type_Conversions_State state(m_conversions, m_conversions.conversion_saves());
|
||||
return chaiscript::boxed_cast<Type>(bv, &state);
|
||||
return(chaiscript::boxed_cast<Type>(bv, &state));
|
||||
}
|
||||
|
||||
/// Add a new conversion for upcasting to a base class
|
||||
@@ -445,7 +470,6 @@ namespace chaiscript
|
||||
/// Add a new named Proxy_Function to the system
|
||||
void add(const Proxy_Function &f, const std::string &name)
|
||||
{
|
||||
validate_object_name(name);
|
||||
add_function(f, name);
|
||||
}
|
||||
|
||||
@@ -453,7 +477,6 @@ namespace chaiscript
|
||||
/// is not available in the current scope it is created
|
||||
void add(Boxed_Value obj, const std::string &name)
|
||||
{
|
||||
validate_object_name(name);
|
||||
auto &stack = get_stack_data();
|
||||
|
||||
for (auto stack_elem = stack.rbegin(); stack_elem != stack.rend(); ++stack_elem)
|
||||
@@ -473,6 +496,26 @@ namespace chaiscript
|
||||
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(const std::string &t_name, Boxed_Value obj, Stack_Holder &t_holder)
|
||||
{
|
||||
auto &stack_elem = get_stack_data(t_holder).back();
|
||||
|
||||
if (std::any_of(stack_elem.begin(), stack_elem.end(),
|
||||
[&](const std::pair<std::string, Boxed_Value> &o) {
|
||||
return o.first == t_name;
|
||||
}))
|
||||
{
|
||||
throw chaiscript::exception::name_conflict_error(t_name);
|
||||
}
|
||||
|
||||
stack_elem.emplace_back(t_name, std::move(obj));
|
||||
return stack_elem.back().second;
|
||||
}
|
||||
|
||||
|
||||
/// 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
|
||||
@@ -488,7 +531,7 @@ namespace chaiscript
|
||||
throw chaiscript::exception::name_conflict_error(t_name);
|
||||
}
|
||||
|
||||
get_stack_data(t_holder).back().emplace_back(t_name, std::move(obj));
|
||||
stack_elem.emplace_back(t_name, std::move(obj));
|
||||
}
|
||||
|
||||
|
||||
@@ -503,7 +546,6 @@ namespace chaiscript
|
||||
/// Adds a new global shared object, between all the threads
|
||||
void add_global_const(const Boxed_Value &obj, const std::string &name)
|
||||
{
|
||||
validate_object_name(name);
|
||||
if (!obj.is_const())
|
||||
{
|
||||
throw chaiscript::exception::global_non_const();
|
||||
@@ -522,8 +564,6 @@ namespace chaiscript
|
||||
/// Adds a new global (non-const) shared object, between all the threads
|
||||
Boxed_Value add_global_no_throw(const Boxed_Value &obj, const std::string &name)
|
||||
{
|
||||
validate_object_name(name);
|
||||
|
||||
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
|
||||
|
||||
const auto itr = m_state.m_global_objects.find(name);
|
||||
@@ -540,8 +580,6 @@ namespace chaiscript
|
||||
/// Adds a new global (non-const) shared object, between all the threads
|
||||
void add_global(const Boxed_Value &obj, const std::string &name)
|
||||
{
|
||||
validate_object_name(name);
|
||||
|
||||
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
|
||||
|
||||
if (m_state.m_global_objects.find(name) != m_state.m_global_objects.end())
|
||||
@@ -555,8 +593,6 @@ namespace chaiscript
|
||||
/// Updates an existing global shared object or adds a new global shared object if not found
|
||||
void set_global(const Boxed_Value &obj, const std::string &name)
|
||||
{
|
||||
validate_object_name(name);
|
||||
|
||||
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
|
||||
|
||||
const auto itr = m_state.m_global_objects.find(name);
|
||||
@@ -583,8 +619,8 @@ namespace chaiscript
|
||||
/// Adds a new scope to the stack
|
||||
static void new_scope(Stack_Holder &t_holder)
|
||||
{
|
||||
get_stack_data(t_holder).emplace_back();
|
||||
t_holder.call_params.emplace_back();
|
||||
t_holder.push_stack_data();
|
||||
t_holder.push_call_params();
|
||||
}
|
||||
|
||||
/// Pops the current scope from the stack
|
||||
@@ -603,7 +639,7 @@ namespace chaiscript
|
||||
static void new_stack(Stack_Holder &t_holder)
|
||||
{
|
||||
// add a new Stack with 1 element
|
||||
t_holder.stacks.emplace_back(1);
|
||||
t_holder.push_stack();
|
||||
}
|
||||
|
||||
static void pop_stack(Stack_Holder &t_holder)
|
||||
@@ -815,7 +851,7 @@ namespace chaiscript
|
||||
{
|
||||
auto &stack = get_stack_data();
|
||||
auto &scope = stack.front();
|
||||
scope = std::vector<std::pair<std::string, Boxed_Value>>(t_locals.begin(), t_locals.end());
|
||||
scope.assign(t_locals.begin(), t_locals.end());
|
||||
}
|
||||
|
||||
|
||||
@@ -886,12 +922,6 @@ namespace chaiscript
|
||||
return rets;
|
||||
}
|
||||
|
||||
void add_reserved_word(const std::string &name)
|
||||
{
|
||||
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
|
||||
|
||||
m_state.m_reserved_words.insert(name);
|
||||
}
|
||||
|
||||
const Type_Conversions &conversions() const
|
||||
{
|
||||
@@ -947,14 +977,21 @@ namespace chaiscript
|
||||
|
||||
This_Foist fi(*this, l_params.front());
|
||||
|
||||
auto func = boxed_cast<std::shared_ptr<const dispatch::Proxy_Function_Base>>(bv);
|
||||
try {
|
||||
return (*func)({l_params.begin() + l_num_params, l_params.end()}, l_conversions);
|
||||
auto func = boxed_cast<const dispatch::Proxy_Function_Base *>(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<Const_Proxy_Function>{boxed_cast<Const_Proxy_Function>(bv)});
|
||||
} catch (const chaiscript::exception::bad_boxed_cast &) {
|
||||
} catch (const chaiscript::exception::arity_error &) {
|
||||
} catch (const chaiscript::exception::guard_error &) {
|
||||
// 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<Const_Proxy_Function>(l_funs.begin(), l_funs.end()));
|
||||
}
|
||||
throw chaiscript::exception::dispatch_error({l_params.begin() + l_num_params, l_params.end()}, std::vector<Const_Proxy_Function>{func});
|
||||
} else {
|
||||
return bv;
|
||||
}
|
||||
@@ -1058,6 +1095,7 @@ namespace chaiscript
|
||||
void dump_function(const std::pair<const std::string, Proxy_Function > &f) const
|
||||
{
|
||||
std::vector<Type_Info> params = f.second->get_param_types();
|
||||
|
||||
std::vector<std::pair<std::string, Type_Info>> typed_params;
|
||||
|
||||
auto func(std::dynamic_pointer_cast<const dispatch::Dynamic_Function_Interface>(f.second));
|
||||
@@ -1065,11 +1103,6 @@ namespace chaiscript
|
||||
typed_params = func->get_dynamic_param_types().types();
|
||||
}
|
||||
|
||||
std::string annotation = f.second->annotation();
|
||||
|
||||
if (annotation.size() > 0) {
|
||||
std::cout << annotation;
|
||||
}
|
||||
dump_type(params.front());
|
||||
std::cout << " " << f.first << "(";
|
||||
|
||||
@@ -1261,6 +1294,11 @@ namespace chaiscript
|
||||
return m_stack_holder->stacks.back();
|
||||
}
|
||||
|
||||
parser::ChaiScript_Parser_Base &get_parser()
|
||||
{
|
||||
return m_parser.get();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
const std::vector<std::pair<std::string, Boxed_Value>> &get_boxed_functions_int() const
|
||||
@@ -1395,10 +1433,6 @@ namespace chaiscript
|
||||
|
||||
if (rt.bare_equal(boxed_type))
|
||||
{
|
||||
if (lt.bare_equal(boxed_pod_type))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1450,20 +1484,6 @@ namespace chaiscript
|
||||
}
|
||||
|
||||
|
||||
/// Throw a reserved_word exception if the name is not allowed
|
||||
void validate_object_name(const std::string &name) const
|
||||
{
|
||||
if (name.find("::") != std::string::npos) {
|
||||
throw chaiscript::exception::illegal_name_error(name);
|
||||
}
|
||||
|
||||
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
|
||||
|
||||
if (m_state.m_reserved_words.find(name) != m_state.m_reserved_words.end())
|
||||
{
|
||||
throw chaiscript::exception::reserved_word_error(name);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Container, typename Key, typename Value>
|
||||
static void add_keyed_value(Container &t_c, const Key &t_key, Value &&t_value)
|
||||
@@ -1501,7 +1521,7 @@ namespace chaiscript
|
||||
static typename Container::const_iterator find_keyed_value(const Container &t_c, const Key &t_key, const size_t t_hint)
|
||||
{
|
||||
if (t_c.size() > t_hint && t_c[t_hint].first == t_key) {
|
||||
return advance_copy(t_c.begin(), t_hint);
|
||||
return std::next(t_c.begin(), static_cast<typename std::iterator_traits<typename Container::const_iterator>::difference_type>(t_hint));
|
||||
} else {
|
||||
return find_keyed_value(t_c, t_key);
|
||||
}
|
||||
@@ -1558,8 +1578,9 @@ namespace chaiscript
|
||||
|
||||
Type_Conversions m_conversions;
|
||||
chaiscript::detail::threading::Thread_Storage<Stack_Holder> m_stack_holder;
|
||||
std::reference_wrapper<parser::ChaiScript_Parser_Base> m_parser;
|
||||
|
||||
mutable std::atomic_uint_fast32_t m_method_missing_loc;
|
||||
mutable std::atomic_uint_fast32_t m_method_missing_loc = {0};
|
||||
|
||||
State m_state;
|
||||
};
|
||||
@@ -1594,8 +1615,12 @@ namespace chaiscript
|
||||
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());
|
||||
}
|
||||
|
||||
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());
|
||||
return m_engine.get().add_object(t_name, std::move(obj), m_stack_holder.get());
|
||||
}
|
||||
|
||||
Boxed_Value get_object(const std::string &t_name, std::atomic_uint_fast32_t &t_loc) const {
|
||||
@@ -1612,3 +1637,4 @@ namespace chaiscript
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
@@ -109,12 +109,6 @@ namespace chaiscript
|
||||
return {m_func};
|
||||
}
|
||||
|
||||
std::string annotation() const override
|
||||
{
|
||||
return m_func->annotation();
|
||||
}
|
||||
|
||||
|
||||
protected:
|
||||
virtual Boxed_Value do_call(const std::vector<Boxed_Value> ¶ms, const Type_Conversions_State &t_conversions) const override
|
||||
{
|
||||
@@ -218,7 +212,7 @@ namespace chaiscript
|
||||
}
|
||||
|
||||
|
||||
virtual Param_Types get_dynamic_param_types() const {
|
||||
Param_Types get_dynamic_param_types() const override {
|
||||
auto dynamic(std::dynamic_pointer_cast<dispatch::Dynamic_Function_Interface>(m_func));
|
||||
|
||||
if (dynamic) {
|
||||
@@ -243,11 +237,6 @@ namespace chaiscript
|
||||
return m_func->call_match(new_vals, t_conversions);
|
||||
}
|
||||
|
||||
std::string annotation() const override
|
||||
{
|
||||
return m_func->annotation();
|
||||
}
|
||||
|
||||
protected:
|
||||
Boxed_Value do_call(const std::vector<Boxed_Value> ¶ms, const Type_Conversions_State &t_conversions) const override
|
||||
{
|
||||
|
@@ -81,9 +81,7 @@ namespace chaiscript
|
||||
template<typename Signature>
|
||||
struct Cast_Helper<const std::function<Signature> &>
|
||||
{
|
||||
typedef std::function<Signature> Result_Type;
|
||||
|
||||
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions_State *t_conversions)
|
||||
static std::function<Signature> cast(const Boxed_Value &ob, const Type_Conversions_State *t_conversions)
|
||||
{
|
||||
if (ob.get_type_info().bare_equal(user_type<Const_Proxy_Function>()))
|
||||
{
|
||||
@@ -98,9 +96,7 @@ namespace chaiscript
|
||||
template<typename Signature>
|
||||
struct Cast_Helper<std::function<Signature> >
|
||||
{
|
||||
typedef std::function<Signature> Result_Type;
|
||||
|
||||
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions_State *t_conversions)
|
||||
static std::function<Signature> cast(const Boxed_Value &ob, const Type_Conversions_State *t_conversions)
|
||||
{
|
||||
if (ob.get_type_info().bare_equal(user_type<Const_Proxy_Function>()))
|
||||
{
|
||||
@@ -115,9 +111,7 @@ namespace chaiscript
|
||||
template<typename Signature>
|
||||
struct Cast_Helper<const std::function<Signature> >
|
||||
{
|
||||
typedef std::function<Signature> Result_Type;
|
||||
|
||||
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions_State *t_conversions)
|
||||
static std::function<Signature> cast(const Boxed_Value &ob, const Type_Conversions_State *t_conversions)
|
||||
{
|
||||
if (ob.get_type_info().bare_equal(user_type<Const_Proxy_Function>()))
|
||||
{
|
||||
|
@@ -100,6 +100,24 @@ namespace chaiscript
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Ret>
|
||||
struct Handle_Return<Ret *&>
|
||||
{
|
||||
static Boxed_Value handle(Ret *p)
|
||||
{
|
||||
return Boxed_Value(p, true);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Ret>
|
||||
struct Handle_Return<const Ret *&>
|
||||
{
|
||||
static Boxed_Value handle(const Ret *p)
|
||||
{
|
||||
return Boxed_Value(p, true);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Ret>
|
||||
struct Handle_Return<Ret *>
|
||||
{
|
||||
@@ -146,6 +164,14 @@ namespace chaiscript
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Ret>
|
||||
struct Handle_Return<const Ret>
|
||||
{
|
||||
static Boxed_Value handle(const Ret &r)
|
||||
{
|
||||
return Boxed_Value(std::cref(r));
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Ret>
|
||||
struct Handle_Return<Ret &>
|
||||
@@ -154,11 +180,6 @@ namespace chaiscript
|
||||
{
|
||||
return Boxed_Value(std::ref(r));
|
||||
}
|
||||
|
||||
static Boxed_Value handle(const Ret &r)
|
||||
{
|
||||
return Boxed_Value(std::cref(r));
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
|
@@ -16,414 +16,202 @@ namespace chaiscript
|
||||
{
|
||||
namespace operators
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
/// \todo make this return a decltype once we drop gcc 4.6
|
||||
template<typename L, typename R>
|
||||
auto assign(L l, R r) -> L&
|
||||
{
|
||||
return (l = r);
|
||||
}
|
||||
|
||||
template<typename L, typename R>
|
||||
auto assign_bitwise_and(L l, R r) -> decltype((l &= r))
|
||||
{
|
||||
return (l &= r);
|
||||
}
|
||||
|
||||
template<typename L, typename R>
|
||||
auto assign_xor(L l, R r) -> decltype((l^=r))
|
||||
{
|
||||
return (l ^= r);
|
||||
}
|
||||
|
||||
template<typename L, typename R>
|
||||
auto assign_bitwise_or(L l, R r) -> decltype((l |= r))
|
||||
{
|
||||
return (l |= r);
|
||||
}
|
||||
|
||||
template<typename L, typename R>
|
||||
auto assign_difference(L l, R r) -> decltype(( l -= r))
|
||||
{
|
||||
return (l -= r);
|
||||
}
|
||||
|
||||
template<typename L, typename R>
|
||||
auto assign_left_shift(L l, R r) -> decltype(( l <<= r))
|
||||
{
|
||||
return (l <<= r);
|
||||
}
|
||||
|
||||
template<typename L, typename R>
|
||||
auto assign_product(L l, R r) -> decltype(( l *= r ))
|
||||
{
|
||||
return (l *= r);
|
||||
}
|
||||
|
||||
template<typename L, typename R>
|
||||
auto assign_quotient(L l, R r) -> decltype(( l /= r ))
|
||||
{
|
||||
return (l /= r);
|
||||
}
|
||||
|
||||
template<typename L, typename R>
|
||||
auto assign_remainder(L l, R r) -> decltype(( l %= r ))
|
||||
{
|
||||
return (l %= r);
|
||||
}
|
||||
|
||||
template<typename L, typename R>
|
||||
auto assign_right_shift(L l, R r) -> decltype(( l >>= r))
|
||||
{
|
||||
return (l >>= r);
|
||||
}
|
||||
|
||||
/// \todo make this return a decltype once we drop gcc 4.6
|
||||
template<typename L, typename R>
|
||||
auto assign_sum(L l, R r) -> L&
|
||||
{
|
||||
return (l += r);
|
||||
}
|
||||
|
||||
template<typename L>
|
||||
auto prefix_decrement(L l) -> decltype(( --l ))
|
||||
{
|
||||
return (--l);
|
||||
}
|
||||
|
||||
template<typename L>
|
||||
auto prefix_increment(L l) -> decltype(( ++l ))
|
||||
{
|
||||
return (++l);
|
||||
}
|
||||
|
||||
template<typename L, typename R>
|
||||
auto equal(L l, R r) -> decltype(( l == r ))
|
||||
{
|
||||
return (l == r);
|
||||
}
|
||||
|
||||
template<typename L, typename R>
|
||||
auto greater_than(L l, R r) -> decltype(( l > r ))
|
||||
{
|
||||
return (l > r);
|
||||
}
|
||||
|
||||
template<typename L, typename R>
|
||||
auto greater_than_equal(L l, R r) -> decltype(( l >= r ))
|
||||
{
|
||||
return (l >= r);
|
||||
}
|
||||
|
||||
template<typename L, typename R>
|
||||
auto less_than(L l, R r) -> decltype(( l < r ))
|
||||
{
|
||||
return (l < r);
|
||||
}
|
||||
|
||||
template<typename L, typename R>
|
||||
auto less_than_equal(L l, R r) -> decltype(( l <= r ))
|
||||
{
|
||||
return (l <= r);
|
||||
}
|
||||
|
||||
template<typename L>
|
||||
auto logical_compliment(L l) -> decltype(( !l ))
|
||||
{
|
||||
return (!l);
|
||||
}
|
||||
|
||||
template<typename L, typename R>
|
||||
auto not_equal(L l, R r) -> decltype(( l != r ))
|
||||
{
|
||||
return (l != r);
|
||||
}
|
||||
|
||||
template<typename L, typename R>
|
||||
auto addition(L l, R r) -> decltype(( l + r ))
|
||||
{
|
||||
return (l + r);
|
||||
}
|
||||
|
||||
template<typename L>
|
||||
auto unary_plus(L l) -> decltype(( +l ))
|
||||
{
|
||||
return (+l);
|
||||
}
|
||||
|
||||
template<typename L, typename R>
|
||||
auto subtraction(L l, R r) -> decltype(( l - r ))
|
||||
{
|
||||
return (l - r);
|
||||
}
|
||||
|
||||
template<typename L>
|
||||
auto unary_minus(L l) -> decltype(( -l ))
|
||||
{
|
||||
#ifdef CHAISCRIPT_MSVC
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4146)
|
||||
return (-l);
|
||||
#pragma warning(pop)
|
||||
#else
|
||||
return (-l);
|
||||
#endif
|
||||
}
|
||||
|
||||
template<typename L, typename R>
|
||||
auto bitwise_and(L l, R r) -> decltype(( l & r ))
|
||||
{
|
||||
return (l & r);
|
||||
}
|
||||
|
||||
template<typename L>
|
||||
auto bitwise_compliment(L l) -> decltype(( ~l ))
|
||||
{
|
||||
return (~l);
|
||||
}
|
||||
|
||||
template<typename L, typename R>
|
||||
auto bitwise_xor(L l, R r) -> decltype(( l ^ r ))
|
||||
{
|
||||
return (l ^ r);
|
||||
}
|
||||
|
||||
template<typename L, typename R>
|
||||
auto bitwise_or(L l, R r) -> decltype(( l | r ))
|
||||
{
|
||||
return (l | r);
|
||||
}
|
||||
|
||||
template<typename L, typename R>
|
||||
auto division(L l, R r) -> decltype(( l / r ))
|
||||
{
|
||||
return (l / r);
|
||||
}
|
||||
|
||||
template<typename L, typename R>
|
||||
auto left_shift(L l, R r) -> decltype(( l << r ))
|
||||
{
|
||||
return l << r;
|
||||
}
|
||||
|
||||
template<typename L, typename R>
|
||||
auto multiplication(L l, R r) -> decltype(( l * r ))
|
||||
{
|
||||
return l * r;
|
||||
}
|
||||
|
||||
template<typename L, typename R>
|
||||
auto remainder(L l, R r) -> decltype(( l % r ))
|
||||
{
|
||||
return (l % r);
|
||||
}
|
||||
|
||||
template<typename L, typename R>
|
||||
auto right_shift(L l, R r) -> decltype(( l >> r ))
|
||||
{
|
||||
return (l >> r);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<typename T>
|
||||
void assign(Module& m)
|
||||
{
|
||||
m.add(chaiscript::fun(&detail::assign<T &, const T&>), "=");
|
||||
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs = rhs;}), "=");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void assign_bitwise_and(Module& m)
|
||||
{
|
||||
m.add(chaiscript::fun(&detail::assign_bitwise_and<T &, const T&>), "&=");
|
||||
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs &= rhs;}), "&=");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void assign_xor(Module& m)
|
||||
{
|
||||
m.add(chaiscript::fun(&detail::assign_xor<T &, const T&>), "^=");
|
||||
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs ^= rhs;}), "^=");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void assign_bitwise_or(Module& m)
|
||||
{
|
||||
m.add(chaiscript::fun(&detail::assign_bitwise_or<T &, const T&>), "|=");
|
||||
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs |= rhs;}), "|=");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void assign_difference(Module& m)
|
||||
{
|
||||
m.add(chaiscript::fun(&detail::assign_difference<T &, const T&>), "-=");
|
||||
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs -= rhs;}), "-=");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void assign_left_shift(Module& m)
|
||||
{
|
||||
m.add(chaiscript::fun(&detail::assign_left_shift<T &, const T&>), "<<=");
|
||||
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs <<= rhs;}), "<<=");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void assign_product(Module& m)
|
||||
{
|
||||
m.add(chaiscript::fun(&detail::assign_product<T &, const T&>), "*=");
|
||||
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs <<= rhs;}), "*=");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void assign_quotient(Module& m)
|
||||
{
|
||||
m.add(chaiscript::fun(&detail::assign_quotient<T &, const T&>), "/=");
|
||||
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs /= rhs;}), "/=");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void assign_remainder(Module& m)
|
||||
{
|
||||
m.add(chaiscript::fun(&detail::assign_remainder<T &, const T&>), "%=");
|
||||
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs %= rhs;}), "%=");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void assign_right_shift(Module& m)
|
||||
{
|
||||
m.add(chaiscript::fun(&detail::assign_right_shift<T &, const T&>), ">>=");
|
||||
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs >>= rhs;}), ">>=");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void assign_sum(Module& m)
|
||||
{
|
||||
m.add(chaiscript::fun(&detail::assign_sum<T &, const T&>), "+=");
|
||||
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs += rhs;}), "+=");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void prefix_decrement(Module& m)
|
||||
{
|
||||
m.add(chaiscript::fun(&detail::prefix_decrement<T &>), "--");
|
||||
m.add(chaiscript::fun([](T &lhs)->T&{return --lhs;}), "--");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void prefix_increment(Module& m)
|
||||
{
|
||||
m.add(chaiscript::fun(&detail::prefix_increment<T &>), "++");
|
||||
m.add(chaiscript::fun([](T &lhs)->T&{return ++lhs;}), "++");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void equal(Module& m)
|
||||
{
|
||||
m.add(chaiscript::fun(&detail::equal<const T&, const T&>), "==");
|
||||
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs==rhs;}), "==");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void greater_than(Module& m)
|
||||
{
|
||||
m.add(chaiscript::fun(&detail::greater_than<const T&, const T&>), ">");
|
||||
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs>rhs;}), ">");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void greater_than_equal(Module& m)
|
||||
{
|
||||
m.add(chaiscript::fun(&detail::greater_than_equal<const T&, const T&>), ">=");
|
||||
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs>=rhs;}), ">=");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void less_than(Module& m)
|
||||
{
|
||||
m.add(chaiscript::fun(&detail::less_than<const T&, const T&>), "<");
|
||||
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs<rhs;}), "<");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void less_than_equal(Module& m)
|
||||
{
|
||||
m.add(chaiscript::fun(&detail::less_than_equal<const T&, const T&>), "<=");
|
||||
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs<=rhs;}), "<=");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void logical_compliment(Module& m)
|
||||
{
|
||||
m.add(chaiscript::fun(&detail::logical_compliment<const T &>), "!");
|
||||
m.add(chaiscript::fun([](const T &lhs){return !lhs;}), "!");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void not_equal(Module& m)
|
||||
{
|
||||
m.add(chaiscript::fun(&detail::not_equal<const T &, const T &>), "!=");
|
||||
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs!=rhs;}), "!=");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void addition(Module& m)
|
||||
{
|
||||
m.add(chaiscript::fun(&detail::addition<const T &, const T &>), "+");
|
||||
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs+rhs;}), "+");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void unary_plus(Module& m)
|
||||
{
|
||||
m.add(chaiscript::fun(&detail::unary_plus<const T &>), "+");
|
||||
m.add(chaiscript::fun([](const T &lhs){return +lhs;}), "+");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void subtraction(Module& m)
|
||||
{
|
||||
m.add(chaiscript::fun(&detail::subtraction<const T &, const T &>), "-");
|
||||
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs-rhs;}), "-");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void unary_minus(Module& m)
|
||||
{
|
||||
m.add(chaiscript::fun(&detail::unary_minus<const T &>), "-");
|
||||
m.add(chaiscript::fun([](const T &lhs){return -lhs;}), "-");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void bitwise_and(Module& m)
|
||||
{
|
||||
m.add(chaiscript::fun(&detail::bitwise_and<const T &, const T &>), "&");
|
||||
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs&rhs;}), "&");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void bitwise_compliment(Module& m)
|
||||
{
|
||||
m.add(chaiscript::fun(&detail::bitwise_compliment<const T &>), "~");
|
||||
m.add(chaiscript::fun([](const T &lhs){return ~lhs;}), "~");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void bitwise_xor(Module& m)
|
||||
{
|
||||
m.add(chaiscript::fun(&detail::bitwise_xor<const T &, const T &>), "^");
|
||||
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs^rhs;}), "^");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void bitwise_or(Module& m)
|
||||
{
|
||||
m.add(chaiscript::fun(&detail::bitwise_or<const T &, const T &>), "|");
|
||||
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs|rhs;}), "|");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void division(Module& m)
|
||||
{
|
||||
m.add(chaiscript::fun(&detail::division<const T &, const T &>), "/");
|
||||
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs/rhs;}), "/");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void left_shift(Module& m)
|
||||
{
|
||||
m.add(chaiscript::fun(&detail::left_shift<const T &, const T &>), "<<");
|
||||
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs<<rhs;}), "<<");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void multiplication(Module& m)
|
||||
{
|
||||
m.add(chaiscript::fun(&detail::multiplication<const T &, const T &>), "*");
|
||||
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs*rhs;}), "*");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void remainder(Module& m)
|
||||
{
|
||||
m.add(chaiscript::fun(&detail::remainder<const T &, const T &>), "%");
|
||||
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs%rhs;}), "%");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void right_shift(Module& m)
|
||||
{
|
||||
m.add(chaiscript::fun(&detail::right_shift<const T &, const T &>), ">>");
|
||||
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs>>rhs;}), ">>");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -200,20 +200,15 @@ namespace chaiscript
|
||||
//! to the passed in values
|
||||
bool filter(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const
|
||||
{
|
||||
assert(m_arity == -1 || (m_arity > 0 && static_cast<int>(vals.size()) == m_arity));
|
||||
|
||||
if (m_arity < 0)
|
||||
{
|
||||
return true;
|
||||
} else if (static_cast<size_t>(m_arity) == vals.size()) {
|
||||
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);
|
||||
}
|
||||
} 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 false;
|
||||
return compare_type_to_param(m_types[1], vals[0], t_conversions);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -223,8 +218,6 @@ namespace chaiscript
|
||||
return m_arity;
|
||||
}
|
||||
|
||||
virtual std::string annotation() const = 0;
|
||||
|
||||
static bool compare_type_to_param(const Type_Info &ti, const Boxed_Value &bv, const Type_Conversions_State &t_conversions)
|
||||
{
|
||||
if (ti.is_undef()
|
||||
@@ -332,11 +325,10 @@ namespace chaiscript
|
||||
int t_arity=-1,
|
||||
AST_NodePtr t_parsenode = AST_NodePtr(),
|
||||
Param_Types t_param_types = Param_Types(),
|
||||
std::string t_description = "",
|
||||
Proxy_Function t_guard = Proxy_Function())
|
||||
: Proxy_Function_Base(build_param_type_list(t_param_types), t_arity),
|
||||
m_param_types(std::move(t_param_types)),
|
||||
m_guard(std::move(t_guard)), m_parsenode(std::move(t_parsenode)), m_description(std::move(t_description))
|
||||
m_guard(std::move(t_guard)), m_parsenode(std::move(t_parsenode))
|
||||
{
|
||||
}
|
||||
|
||||
@@ -369,12 +361,7 @@ namespace chaiscript
|
||||
return m_parsenode;
|
||||
}
|
||||
|
||||
virtual std::string annotation() const override
|
||||
{
|
||||
return m_description;
|
||||
}
|
||||
|
||||
virtual Param_Types get_dynamic_param_types() const {
|
||||
Param_Types get_dynamic_param_types() const override {
|
||||
return m_param_types;
|
||||
}
|
||||
|
||||
@@ -418,7 +405,6 @@ namespace chaiscript
|
||||
Param_Types m_param_types;
|
||||
Proxy_Function m_guard;
|
||||
AST_NodePtr m_parsenode;
|
||||
std::string m_description;
|
||||
};
|
||||
|
||||
|
||||
@@ -432,13 +418,11 @@ namespace chaiscript
|
||||
int t_arity=-1,
|
||||
AST_NodePtr t_parsenode = AST_NodePtr(),
|
||||
Param_Types t_param_types = Param_Types(),
|
||||
std::string t_description = "",
|
||||
Proxy_Function t_guard = Proxy_Function())
|
||||
: Dynamic_Proxy_Function(
|
||||
t_arity,
|
||||
std::move(t_parsenode),
|
||||
std::move(t_param_types),
|
||||
std::move(t_description),
|
||||
std::move(t_guard)
|
||||
),
|
||||
m_f(std::move(t_f))
|
||||
@@ -537,10 +521,6 @@ namespace chaiscript
|
||||
return args;
|
||||
}
|
||||
|
||||
virtual std::string annotation() const override
|
||||
{
|
||||
return "Bound: " + m_f->annotation();
|
||||
}
|
||||
|
||||
protected:
|
||||
static std::vector<Type_Info> build_param_type_info(const Const_Proxy_Function &t_f,
|
||||
@@ -585,11 +565,6 @@ namespace chaiscript
|
||||
{
|
||||
}
|
||||
|
||||
std::string annotation() const override
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const override
|
||||
{
|
||||
return static_cast<int>(vals.size()) == get_arity()
|
||||
@@ -626,8 +601,7 @@ namespace chaiscript
|
||||
protected:
|
||||
Boxed_Value do_call(const std::vector<Boxed_Value> ¶ms, const Type_Conversions_State &t_conversions) const override
|
||||
{
|
||||
typedef typename detail::Function_Signature<Func>::Return_Type Return_Type;
|
||||
return detail::Do_Call<Return_Type>::template go<Func>(m_f, params, t_conversions);
|
||||
return detail::call_func(detail::Function_Signature<Func>(), m_f, params, t_conversions);
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -679,7 +653,7 @@ namespace chaiscript
|
||||
protected:
|
||||
Boxed_Value do_call(const std::vector<Boxed_Value> ¶ms, const Type_Conversions_State &t_conversions) const override
|
||||
{
|
||||
return detail::Do_Call<typename std::function<Func>::result_type>::template go<Func>(m_f.get(), params, t_conversions);
|
||||
return detail::call_func(detail::Function_Signature<Func>(), m_f.get(), params, t_conversions);
|
||||
}
|
||||
|
||||
|
||||
@@ -724,11 +698,6 @@ namespace chaiscript
|
||||
return vals[0].get_type_info().bare_equal(user_type<Class>());
|
||||
}
|
||||
|
||||
std::string annotation() const override
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
protected:
|
||||
Boxed_Value do_call(const std::vector<Boxed_Value> ¶ms, const Type_Conversions_State &t_conversions) const override
|
||||
{
|
||||
@@ -759,13 +728,13 @@ namespace chaiscript
|
||||
template<typename Type>
|
||||
auto do_call_impl(Class *o) const -> std::enable_if_t<!std::is_pointer<Type>::value, Boxed_Value>
|
||||
{
|
||||
return detail::Handle_Return<const typename std::add_lvalue_reference<Type>::type>::handle(o->*m_attr);
|
||||
return detail::Handle_Return<typename std::add_lvalue_reference<Type>::type>::handle(o->*m_attr);
|
||||
}
|
||||
|
||||
template<typename Type>
|
||||
auto do_call_impl(const Class *o) const -> std::enable_if_t<!std::is_pointer<Type>::value, Boxed_Value>
|
||||
{
|
||||
return detail::Handle_Return<const typename std::add_lvalue_reference<Type>::type>::handle(o->*m_attr);
|
||||
return detail::Handle_Return<typename std::add_lvalue_reference<typename std::add_const<Type>::type>::type>::handle(o->*m_attr);
|
||||
}
|
||||
|
||||
|
||||
@@ -881,7 +850,8 @@ namespace chaiscript
|
||||
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()) {
|
||||
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;
|
||||
@@ -889,8 +859,6 @@ namespace chaiscript
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
|
||||
try {
|
||||
return (*(matching_func->second))(newplist, t_conversions);
|
||||
} catch (const exception::bad_boxed_cast &) {
|
||||
@@ -918,14 +886,8 @@ namespace chaiscript
|
||||
std::vector<std::pair<size_t, const Proxy_Function_Base *>> ordered_funcs;
|
||||
ordered_funcs.reserve(funcs.size());
|
||||
|
||||
#ifdef CHAISCRIPT_HAS_MAGIC_STATICS
|
||||
static auto boxed_type = user_type<Boxed_Value>();
|
||||
static auto dynamic_type = user_type<Dynamic_Object>();
|
||||
#else
|
||||
auto boxed_type = user_type<Boxed_Value>();
|
||||
auto dynamic_type = user_type<Dynamic_Object>();
|
||||
#endif
|
||||
|
||||
const constexpr auto boxed_type = user_type<Boxed_Value>();
|
||||
const constexpr auto dynamic_type = user_type<Dynamic_Object>();
|
||||
|
||||
for (const auto &func : funcs)
|
||||
{
|
||||
@@ -956,7 +918,7 @@ namespace chaiscript
|
||||
for (const auto &func : ordered_funcs )
|
||||
{
|
||||
try {
|
||||
if (func.first == i && func.second->filter(plist, t_conversions))
|
||||
if (func.first == i && (i == 0 || func.second->filter(plist, t_conversions)))
|
||||
{
|
||||
return (*(func.second))(plist, t_conversions);
|
||||
}
|
||||
|
@@ -99,17 +99,31 @@ namespace chaiscript
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
/// 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<typename Callable, typename Ret, typename ... Params>
|
||||
Ret call_func(const chaiscript::dispatch::detail::Function_Signature<Ret (Params...)> &sig, const Callable &f,
|
||||
Boxed_Value call_func(const chaiscript::dispatch::detail::Function_Signature<Ret (Params...)> &sig, const Callable &f,
|
||||
const std::vector<Boxed_Value> ¶ms, const Type_Conversions_State &t_conversions)
|
||||
{
|
||||
return call_func(sig, std::index_sequence_for<Params...>{}, f, params, t_conversions);
|
||||
return Handle_Return<Ret>::handle(call_func(sig, std::index_sequence_for<Params...>{}, f, params, t_conversions));
|
||||
}
|
||||
|
||||
template<typename Callable, typename ... Params>
|
||||
Boxed_Value call_func(const chaiscript::dispatch::detail::Function_Signature<void (Params...)> &sig, const Callable &f,
|
||||
const std::vector<Boxed_Value> ¶ms, const Type_Conversions_State &t_conversions)
|
||||
{
|
||||
call_func(sig, std::index_sequence_for<Params...>{}, f, params, t_conversions);
|
||||
#ifdef CHAISCRIPT_MSVC
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4702)
|
||||
#endif
|
||||
// MSVC is reporting that this is unreachable code - and it's wrong.
|
||||
return Handle_Return<void>::handle();
|
||||
#ifdef CHAISCRIPT_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
@@ -118,34 +132,4 @@ namespace chaiscript
|
||||
}
|
||||
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
namespace dispatch
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
template<typename Ret>
|
||||
struct Do_Call
|
||||
{
|
||||
template<typename Signature, typename Callable>
|
||||
static Boxed_Value go(const Callable &fun, const std::vector<Boxed_Value> ¶ms, const Type_Conversions_State &t_conversions)
|
||||
{
|
||||
return Handle_Return<Ret>::handle(call_func(Function_Signature<Signature>(), fun, params, t_conversions));
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct Do_Call<void>
|
||||
{
|
||||
template<typename Signature, typename Callable>
|
||||
static Boxed_Value go(const Callable &fun, const std::vector<Boxed_Value> ¶ms, const Type_Conversions_State &t_conversions)
|
||||
{
|
||||
call_func(Function_Signature<Signature>(), fun, params, t_conversions);
|
||||
return Handle_Return<void>::handle();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
157
include/chaiscript/dispatchkit/short_alloc.hpp
Normal file
157
include/chaiscript/dispatchkit/short_alloc.hpp
Normal file
@@ -0,0 +1,157 @@
|
||||
#ifndef SHORT_ALLOC_H
|
||||
#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
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
#include <cstddef>
|
||||
#include <cassert>
|
||||
|
||||
template <std::size_t N, std::size_t alignment = alignof(std::max_align_t)>
|
||||
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;
|
||||
|
||||
template <std::size_t ReqAlign> 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<std::size_t>(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);}
|
||||
|
||||
bool
|
||||
pointer_in_buffer(char* p) noexcept
|
||||
{return buf_ <= p && p <= buf_ + N;}
|
||||
};
|
||||
|
||||
template <std::size_t N, std::size_t alignment>
|
||||
template <std::size_t ReqAlign>
|
||||
char*
|
||||
arena<N, alignment>::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<decltype(aligned_n)>(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<char*>(::operator new(n));
|
||||
}
|
||||
|
||||
template <std::size_t N, std::size_t alignment>
|
||||
void
|
||||
arena<N, alignment>::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 T, std::size_t N, std::size_t Align = alignof(std::max_align_t)>
|
||||
class short_alloc
|
||||
{
|
||||
public:
|
||||
using value_type = T;
|
||||
static auto constexpr alignment = Align;
|
||||
static auto constexpr size = N;
|
||||
using arena_type = arena<size, alignment>;
|
||||
|
||||
private:
|
||||
arena_type& a_;
|
||||
|
||||
public:
|
||||
short_alloc(const short_alloc&) = default;
|
||||
short_alloc& operator=(const short_alloc&) = delete;
|
||||
|
||||
short_alloc(arena_type& a) noexcept : a_(a)
|
||||
{
|
||||
static_assert(size % alignment == 0,
|
||||
"size N needs to be a multiple of alignment Align");
|
||||
}
|
||||
template <class U>
|
||||
short_alloc(const short_alloc<U, N, alignment>& a) noexcept
|
||||
: a_(a.a_) {}
|
||||
|
||||
template <class _Up> struct rebind {using other = short_alloc<_Up, N, alignment>;};
|
||||
|
||||
T* allocate(std::size_t n)
|
||||
{
|
||||
return reinterpret_cast<T*>(a_.template allocate<alignof(T)>(n*sizeof(T)));
|
||||
}
|
||||
void deallocate(T* p, std::size_t n) noexcept
|
||||
{
|
||||
a_.deallocate(reinterpret_cast<char*>(p), n*sizeof(T));
|
||||
}
|
||||
|
||||
template <class T1, std::size_t N1, std::size_t A1,
|
||||
class U, std::size_t M, std::size_t A2>
|
||||
friend
|
||||
bool
|
||||
operator==(const short_alloc<T1, N1, A1>& x, const short_alloc<U, M, A2>& y) noexcept;
|
||||
|
||||
template <class U, std::size_t M, std::size_t A> friend class short_alloc;
|
||||
};
|
||||
|
||||
template <class T, std::size_t N, std::size_t A1, class U, std::size_t M, std::size_t A2>
|
||||
inline
|
||||
bool
|
||||
operator==(const short_alloc<T, N, A1>& x, const short_alloc<U, M, A2>& y) noexcept
|
||||
{
|
||||
return N == M && A1 == A2 && &x.a_ == &y.a_;
|
||||
}
|
||||
|
||||
template <class T, std::size_t N, std::size_t A1, class U, std::size_t M, std::size_t A2>
|
||||
inline
|
||||
bool
|
||||
operator!=(const short_alloc<T, N, A1>& x, const short_alloc<U, M, A2>& y) noexcept
|
||||
{
|
||||
return !(x == y);
|
||||
}
|
||||
|
||||
#endif // SHORT_ALLOC_HPP
|
||||
|
@@ -29,8 +29,8 @@ namespace chaiscript
|
||||
class Type_Info
|
||||
{
|
||||
public:
|
||||
constexpr Type_Info(bool t_is_const, bool t_is_reference, bool t_is_pointer, bool t_is_void,
|
||||
bool t_is_arithmetic, const std::type_info *t_ti, const std::type_info *t_bare_ti)
|
||||
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)
|
||||
: m_type_info(t_ti), m_bare_type_info(t_bare_ti),
|
||||
m_flags((static_cast<unsigned int>(t_is_const) << is_const_flag)
|
||||
+ (static_cast<unsigned int>(t_is_reference) << is_reference_flag)
|
||||
@@ -47,6 +47,16 @@ namespace chaiscript
|
||||
return m_type_info < 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
|
||||
@@ -121,9 +131,7 @@ namespace chaiscript
|
||||
template<typename T>
|
||||
struct Get_Type_Info
|
||||
{
|
||||
typedef T type;
|
||||
|
||||
constexpr static Type_Info get()
|
||||
static constexpr Type_Info get()
|
||||
{
|
||||
return Type_Info(std::is_const<typename std::remove_pointer<typename std::remove_reference<T>::type>::type>::value,
|
||||
std::is_reference<T>::value, std::is_pointer<T>::value,
|
||||
@@ -138,9 +146,9 @@ namespace chaiscript
|
||||
template<typename T>
|
||||
struct Get_Type_Info<std::shared_ptr<T> >
|
||||
{
|
||||
typedef T type;
|
||||
// typedef T type;
|
||||
|
||||
constexpr static Type_Info get()
|
||||
static constexpr Type_Info get()
|
||||
{
|
||||
return Type_Info(std::is_const<T>::value, std::is_reference<T>::value, std::is_pointer<T>::value,
|
||||
std::is_void<T>::value,
|
||||
@@ -158,9 +166,7 @@ namespace chaiscript
|
||||
template<typename T>
|
||||
struct Get_Type_Info<const std::shared_ptr<T> &>
|
||||
{
|
||||
typedef T type;
|
||||
|
||||
constexpr static Type_Info get()
|
||||
static constexpr Type_Info get()
|
||||
{
|
||||
return Type_Info(std::is_const<T>::value, std::is_reference<T>::value, std::is_pointer<T>::value,
|
||||
std::is_void<T>::value,
|
||||
@@ -173,9 +179,7 @@ namespace chaiscript
|
||||
template<typename T>
|
||||
struct Get_Type_Info<std::reference_wrapper<T> >
|
||||
{
|
||||
typedef T type;
|
||||
|
||||
constexpr static Type_Info get()
|
||||
static constexpr Type_Info get()
|
||||
{
|
||||
return Type_Info(std::is_const<T>::value, std::is_reference<T>::value, std::is_pointer<T>::value,
|
||||
std::is_void<T>::value,
|
||||
@@ -188,9 +192,7 @@ namespace chaiscript
|
||||
template<typename T>
|
||||
struct Get_Type_Info<const std::reference_wrapper<T> &>
|
||||
{
|
||||
typedef T type;
|
||||
|
||||
constexpr static Type_Info get()
|
||||
static constexpr Type_Info get()
|
||||
{
|
||||
return Type_Info(std::is_const<T>::value, std::is_reference<T>::value, std::is_pointer<T>::value,
|
||||
std::is_void<T>::value,
|
||||
@@ -212,7 +214,7 @@ namespace chaiscript
|
||||
/// chaiscript::Type_Info ti = chaiscript::user_type(i);
|
||||
/// \endcode
|
||||
template<typename T>
|
||||
constexpr Type_Info user_type(const T &/*t*/)
|
||||
constexpr Type_Info user_type(const T &/*t*/)
|
||||
{
|
||||
return detail::Get_Type_Info<T>::get();
|
||||
}
|
||||
@@ -227,7 +229,7 @@ namespace chaiscript
|
||||
/// chaiscript::Type_Info ti = chaiscript::user_type<int>();
|
||||
/// \endcode
|
||||
template<typename T>
|
||||
constexpr Type_Info user_type()
|
||||
constexpr Type_Info user_type()
|
||||
{
|
||||
return detail::Get_Type_Info<T>::get();
|
||||
}
|
||||
|
@@ -13,7 +13,7 @@ namespace chaiscript
|
||||
{
|
||||
|
||||
struct Operators {
|
||||
enum Opers
|
||||
enum class Opers
|
||||
{
|
||||
boolean_flag,
|
||||
equals, less_than, greater_than, less_than_equal, greater_than_equal, not_equal,
|
||||
@@ -31,7 +31,7 @@ namespace chaiscript
|
||||
};
|
||||
|
||||
static const char *to_string(Opers t_oper) {
|
||||
const char *opers[] = {
|
||||
static const char *opers[] = {
|
||||
"",
|
||||
"==", "<", ">", "<=", ">=", "!=",
|
||||
"",
|
||||
@@ -46,80 +46,80 @@ namespace chaiscript
|
||||
"+", "/", "*", "-", "+", "-",
|
||||
""
|
||||
};
|
||||
return opers[t_oper];
|
||||
return opers[static_cast<int>(t_oper)];
|
||||
}
|
||||
|
||||
static Opers to_operator(const std::string &t_str, bool t_is_unary = false)
|
||||
{
|
||||
if (t_str == "==")
|
||||
{
|
||||
return equals;
|
||||
return Opers::equals;
|
||||
} else if (t_str == "<") {
|
||||
return less_than;
|
||||
return Opers::less_than;
|
||||
} else if (t_str == ">") {
|
||||
return greater_than;
|
||||
return Opers::greater_than;
|
||||
} else if (t_str == "<=") {
|
||||
return less_than_equal;
|
||||
return Opers::less_than_equal;
|
||||
} else if (t_str == ">=") {
|
||||
return greater_than_equal;
|
||||
return Opers::greater_than_equal;
|
||||
} else if (t_str == "!=") {
|
||||
return not_equal;
|
||||
return Opers::not_equal;
|
||||
} else if (t_str == "=") {
|
||||
return assign;
|
||||
return Opers::assign;
|
||||
} else if (t_str == "++") {
|
||||
return pre_increment;
|
||||
return Opers::pre_increment;
|
||||
} else if (t_str == "--") {
|
||||
return pre_decrement;
|
||||
return Opers::pre_decrement;
|
||||
} else if (t_str == "*=") {
|
||||
return assign_product;
|
||||
return Opers::assign_product;
|
||||
} else if (t_str == "+=") {
|
||||
return assign_sum;
|
||||
return Opers::assign_sum;
|
||||
} else if (t_str == "-=") {
|
||||
return assign_difference;
|
||||
return Opers::assign_difference;
|
||||
} else if (t_str == "&=") {
|
||||
return assign_bitwise_and;
|
||||
return Opers::assign_bitwise_and;
|
||||
} else if (t_str == "|=") {
|
||||
return assign_bitwise_or;
|
||||
return Opers::assign_bitwise_or;
|
||||
} else if (t_str == "<<=") {
|
||||
return assign_shift_left;
|
||||
return Opers::assign_shift_left;
|
||||
} else if (t_str == ">>=") {
|
||||
return assign_shift_right;
|
||||
return Opers::assign_shift_right;
|
||||
} else if (t_str == "%=") {
|
||||
return assign_remainder;
|
||||
return Opers::assign_remainder;
|
||||
} else if (t_str == "^=") {
|
||||
return assign_bitwise_xor;
|
||||
return Opers::assign_bitwise_xor;
|
||||
} else if (t_str == "<<") {
|
||||
return shift_left;
|
||||
return Opers::shift_left;
|
||||
} else if (t_str == ">>") {
|
||||
return shift_right;
|
||||
return Opers::shift_right;
|
||||
} else if (t_str == "%") {
|
||||
return remainder;
|
||||
return Opers::remainder;
|
||||
} else if (t_str == "&") {
|
||||
return bitwise_and;
|
||||
return Opers::bitwise_and;
|
||||
} else if (t_str == "|") {
|
||||
return bitwise_or;
|
||||
return Opers::bitwise_or;
|
||||
} else if (t_str == "^") {
|
||||
return bitwise_xor;
|
||||
return Opers::bitwise_xor;
|
||||
} else if (t_str == "~") {
|
||||
return bitwise_complement;
|
||||
return Opers::bitwise_complement;
|
||||
} else if (t_str == "+") {
|
||||
if (t_is_unary) {
|
||||
return unary_plus;
|
||||
return Opers::unary_plus;
|
||||
} else {
|
||||
return sum;
|
||||
return Opers::sum;
|
||||
}
|
||||
} else if (t_str == "-") {
|
||||
if (t_is_unary) {
|
||||
return unary_minus;
|
||||
return Opers::unary_minus;
|
||||
} else {
|
||||
return difference;
|
||||
return Opers::difference;
|
||||
}
|
||||
} else if (t_str == "/") {
|
||||
return quotient;
|
||||
return Opers::quotient;
|
||||
} else if (t_str == "*") {
|
||||
return product;
|
||||
return Opers::product;
|
||||
} else {
|
||||
return invalid;
|
||||
return Opers::invalid;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -26,34 +26,60 @@ struct AST_Node;
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
struct Name_Validator {
|
||||
static bool is_reserved_word(const std::string &name)
|
||||
{
|
||||
static const std::set<std::string> m_reserved_words
|
||||
= {"def", "fun", "while", "for", "if", "else", "&&", "||", ",", "auto",
|
||||
"return", "break", "true", "false", "class", "attr", "var", "global", "GLOBAL", "_",
|
||||
"__LINE__", "__FILE__", "__FUNC__", "__CLASS__"};
|
||||
return m_reserved_words.count(name) > 0;
|
||||
}
|
||||
|
||||
static bool valid_object_name(const std::string &name)
|
||||
{
|
||||
return name.find("::") == std::string::npos && !is_reserved_word(name);
|
||||
}
|
||||
|
||||
static void validate_object_name(const std::string &name)
|
||||
{
|
||||
if (is_reserved_word(name)) {
|
||||
throw exception::reserved_word_error(name);
|
||||
}
|
||||
|
||||
if (name.find("::") != std::string::npos) {
|
||||
throw exception::illegal_name_error(name);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/// Signature of module entry point that all binary loadable modules must implement.
|
||||
typedef ModulePtr (*Create_Module_Func)();
|
||||
|
||||
|
||||
/// Types of AST nodes available to the parser and eval
|
||||
class AST_Node_Type {
|
||||
public:
|
||||
enum Type { Error, Int, Float, Id, Char, Str, Eol, Fun_Call, Arg_List, Variable, Equation, Var_Decl,
|
||||
Comparison, Addition, Subtraction, Multiplication, Division, Modulus, Array_Call, Dot_Access, Quoted_String, Single_Quoted_String,
|
||||
Lambda, Block, Def, While, If, For, Inline_Array, Inline_Map, Return, File, Prefix, Break, Continue, Map_Pair, Value_Range,
|
||||
Inline_Range, Annotation, Try, Catch, Finally, Method, Attr_Decl, Shift, Equality, Bitwise_And, Bitwise_Xor, Bitwise_Or,
|
||||
Logical_And, Logical_Or, Reference, Switch, Case, Default, Ternary_Cond, Noop, Class, Binary, Arg, Global_Decl
|
||||
};
|
||||
enum class AST_Node_Type { Id, Fun_Call, Unused_Return_Fun_Call, Arg_List, Equation, Var_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, Ternary_Cond, Noop, Class, Binary, Arg, Global_Decl, Constant, Compiled
|
||||
};
|
||||
|
||||
enum class Operator_Precidence { Ternary_Cond, Logical_Or,
|
||||
Logical_And, Bitwise_Or, Bitwise_Xor, Bitwise_And,
|
||||
Equality, Comparison, Shift, Addition, Multiplication, Prefix };
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
/// Helper lookup to get the name of each node type
|
||||
const char *ast_node_type_to_string(int ast_node_type) {
|
||||
const char *ast_node_types[] = { "Internal Parser Error", "Int", "Float", "Id", "Char", "Str", "Eol", "Fun_Call", "Arg_List", "Variable", "Equation", "Var_Decl",
|
||||
"Comparison", "Addition", "Subtraction", "Multiplication", "Division", "Modulus", "Array_Call", "Dot_Access", "Quoted_String", "Single_Quoted_String",
|
||||
"Lambda", "Block", "Def", "While", "If", "For", "Inline_Array", "Inline_Map", "Return", "File", "Prefix", "Break", "Continue", "Map_Pair", "Value_Range",
|
||||
"Inline_Range", "Annotation", "Try", "Catch", "Finally", "Method", "Attr_Decl", "Shift", "Equality", "Bitwise_And", "Bitwise_Xor", "Bitwise_Or",
|
||||
"Logical_And", "Logical_Or", "Reference", "Switch", "Case", "Default", "Ternary Condition", "Noop", "Class", "Binary", "Arg"};
|
||||
const char *ast_node_type_to_string(AST_Node_Type ast_node_type) {
|
||||
static const char * const ast_node_types[] = { "Id", "Fun_Call", "Unused_Return_Fun_Call", "Arg_List", "Equation", "Var_Decl",
|
||||
"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", "Ternary Condition", "Noop", "Class", "Binary", "Arg", "Global_Decl", "Constant", "Compiled"};
|
||||
|
||||
return ast_node_types[ast_node_type];
|
||||
return ast_node_types[static_cast<int>(ast_node_type)];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,6 +127,36 @@ namespace chaiscript
|
||||
/// \brief Classes which may be thrown during error cases when ChaiScript is executing.
|
||||
namespace exception
|
||||
{
|
||||
/// \brief Thrown if an error occurs while attempting to load a binary module
|
||||
struct load_module_error : std::runtime_error
|
||||
{
|
||||
load_module_error(const std::string &t_reason) noexcept
|
||||
: std::runtime_error(t_reason)
|
||||
{
|
||||
}
|
||||
|
||||
load_module_error(const std::string &t_name, const std::vector<load_module_error> &t_errors)
|
||||
: std::runtime_error(format_error(t_name, t_errors))
|
||||
{
|
||||
}
|
||||
|
||||
load_module_error(const load_module_error &) = default;
|
||||
virtual ~load_module_error() noexcept = default;
|
||||
|
||||
static std::string format_error(const std::string &t_name, const std::vector<load_module_error> &t_errors)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << "Error loading module '" << t_name << "'\n"
|
||||
<< " The following locations were searched:\n";
|
||||
|
||||
for (const auto &err : t_errors) {
|
||||
ss << " " << err.what() << "\n";
|
||||
}
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/// Errors generated during parsing or evaluation
|
||||
struct eval_error : std::runtime_error {
|
||||
@@ -161,12 +217,12 @@ namespace chaiscript
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
virtual ~eval_error() noexcept {}
|
||||
virtual ~eval_error() noexcept = default;
|
||||
|
||||
private:
|
||||
|
||||
template<typename T>
|
||||
static int id(const T& t)
|
||||
static AST_Node_Type id(const T& t)
|
||||
{
|
||||
return t->identifier;
|
||||
}
|
||||
@@ -434,11 +490,9 @@ namespace chaiscript
|
||||
/// \brief Struct that doubles as both a parser ast_node and an AST node.
|
||||
struct AST_Node : std::enable_shared_from_this<AST_Node> {
|
||||
public:
|
||||
const int identifier; //< \todo shouldn't this be a strongly typed enum value?
|
||||
const AST_Node_Type identifier;
|
||||
const std::string text;
|
||||
Parse_Location location;
|
||||
std::vector<AST_NodePtr> children;
|
||||
AST_NodePtr annotation;
|
||||
|
||||
const std::string &filename() const {
|
||||
return *location.filename;
|
||||
@@ -452,19 +506,22 @@ namespace chaiscript
|
||||
return location.end;
|
||||
}
|
||||
|
||||
virtual std::string pretty_print() const
|
||||
std::string pretty_print() const
|
||||
{
|
||||
std::ostringstream oss;
|
||||
|
||||
oss << text;
|
||||
|
||||
for (auto & elem : this->children) {
|
||||
oss << elem->pretty_print();
|
||||
for (auto & elem : this->get_children()) {
|
||||
oss << elem->pretty_print() << ' ';
|
||||
}
|
||||
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
virtual std::vector<AST_NodePtr> 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 {
|
||||
@@ -473,25 +530,16 @@ namespace chaiscript
|
||||
oss << t_prepend << "(" << ast_node_type_to_string(this->identifier) << ") "
|
||||
<< this->text << " : " << this->location.start.line << ", " << this->location.start.column << '\n';
|
||||
|
||||
for (auto & elem : this->children) {
|
||||
for (auto & elem : this->get_children()) {
|
||||
oss << elem->to_string(t_prepend + " ");
|
||||
}
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
Boxed_Value eval(const chaiscript::detail::Dispatch_State &t_e) const
|
||||
{
|
||||
try {
|
||||
return eval_internal(t_e);
|
||||
} catch (exception::eval_error &ee) {
|
||||
ee.call_stack.push_back(shared_from_this());
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
static bool get_bool_condition(const Boxed_Value &t_bv) {
|
||||
static bool get_bool_condition(const Boxed_Value &t_bv, const chaiscript::detail::Dispatch_State &t_ss) {
|
||||
try {
|
||||
return boxed_cast<bool>(t_bv);
|
||||
return t_ss->boxed_cast<bool>(t_bv);
|
||||
}
|
||||
catch (const exception::bad_boxed_cast &) {
|
||||
throw exception::eval_error("Condition not boolean");
|
||||
@@ -499,33 +547,47 @@ namespace chaiscript
|
||||
}
|
||||
|
||||
|
||||
void replace_child(const AST_NodePtr &t_child, const AST_NodePtr &t_new_child)
|
||||
{
|
||||
std::replace(children.begin(), children.end(), t_child, t_new_child);
|
||||
}
|
||||
|
||||
virtual ~AST_Node() {}
|
||||
|
||||
protected:
|
||||
AST_Node(std::string t_ast_node_text, int t_id, Parse_Location t_loc,
|
||||
std::vector<AST_NodePtr> t_children = std::vector<AST_NodePtr>()) :
|
||||
identifier(t_id), text(std::move(t_ast_node_text)),
|
||||
location(std::move(t_loc)),
|
||||
children(std::move(t_children))
|
||||
{
|
||||
}
|
||||
|
||||
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &) const
|
||||
{
|
||||
throw std::runtime_error("Undispatched ast_node (internal error)");
|
||||
}
|
||||
|
||||
private:
|
||||
// Copy and assignment explicitly unimplemented
|
||||
virtual ~AST_Node() = default;
|
||||
AST_Node(AST_Node &&) = default;
|
||||
AST_Node &operator=(AST_Node &&) = default;
|
||||
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))
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
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(AST_NodePtr 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<typename T>
|
||||
T &get_tracer()
|
||||
{
|
||||
// to do type check this somehow?
|
||||
return *static_cast<T*>(get_tracer_ptr());
|
||||
}
|
||||
|
||||
protected:
|
||||
ChaiScript_Parser_Base(const ChaiScript_Parser_Base &) = default;
|
||||
};
|
||||
}
|
||||
|
||||
namespace eval
|
||||
{
|
||||
@@ -554,77 +616,83 @@ namespace chaiscript
|
||||
/// Creates a new scope then pops it on destruction
|
||||
struct Scope_Push_Pop
|
||||
{
|
||||
Scope_Push_Pop(Scope_Push_Pop &&) = default;
|
||||
Scope_Push_Pop& operator=(Scope_Push_Pop &&) = default;
|
||||
Scope_Push_Pop(const Scope_Push_Pop &) = delete;
|
||||
Scope_Push_Pop& operator=(const Scope_Push_Pop &) = delete;
|
||||
|
||||
Scope_Push_Pop(const chaiscript::detail::Dispatch_State &t_ds)
|
||||
: m_ds(t_ds)
|
||||
{
|
||||
m_ds.get()->new_scope(m_ds.get().stack_holder());
|
||||
m_ds->new_scope(m_ds.stack_holder());
|
||||
}
|
||||
|
||||
~Scope_Push_Pop()
|
||||
{
|
||||
m_ds.get()->pop_scope(m_ds.get().stack_holder());
|
||||
m_ds->pop_scope(m_ds.stack_holder());
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
std::reference_wrapper<const chaiscript::detail::Dispatch_State> m_ds;
|
||||
const chaiscript::detail::Dispatch_State &m_ds;
|
||||
};
|
||||
|
||||
/// Creates a new function call and pops it on destruction
|
||||
struct Function_Push_Pop
|
||||
{
|
||||
Function_Push_Pop(Function_Push_Pop &&) = default;
|
||||
Function_Push_Pop& operator=(Function_Push_Pop &&) = default;
|
||||
Function_Push_Pop(const Function_Push_Pop &) = delete;
|
||||
Function_Push_Pop& operator=(const Function_Push_Pop &) = delete;
|
||||
|
||||
Function_Push_Pop(const chaiscript::detail::Dispatch_State &t_ds)
|
||||
: m_ds(t_ds)
|
||||
{
|
||||
m_ds.get()->new_function_call(m_ds.get().stack_holder(), m_ds.get().conversion_saves());
|
||||
m_ds->new_function_call(m_ds.stack_holder(), m_ds.conversion_saves());
|
||||
}
|
||||
|
||||
~Function_Push_Pop()
|
||||
{
|
||||
m_ds.get()->pop_function_call(m_ds.get().stack_holder(), m_ds.get().conversion_saves());
|
||||
m_ds->pop_function_call(m_ds.stack_holder(), m_ds.conversion_saves());
|
||||
}
|
||||
|
||||
void save_params(const std::vector<Boxed_Value> &t_params)
|
||||
{
|
||||
m_ds.get()->save_function_params(t_params);
|
||||
m_ds->save_function_params(t_params);
|
||||
}
|
||||
|
||||
void save_params(std::initializer_list<Boxed_Value> t_params)
|
||||
{
|
||||
m_ds.get()->save_function_params(std::move(t_params));
|
||||
m_ds->save_function_params(std::move(t_params));
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
std::reference_wrapper<const chaiscript::detail::Dispatch_State> m_ds;
|
||||
const chaiscript::detail::Dispatch_State &m_ds;
|
||||
};
|
||||
|
||||
/// Creates a new scope then pops it on destruction
|
||||
struct Stack_Push_Pop
|
||||
{
|
||||
Stack_Push_Pop(Stack_Push_Pop &&) = default;
|
||||
Stack_Push_Pop& operator=(Stack_Push_Pop &&) = default;
|
||||
Stack_Push_Pop(const Stack_Push_Pop &) = delete;
|
||||
Stack_Push_Pop& operator=(const Stack_Push_Pop &) = delete;
|
||||
|
||||
Stack_Push_Pop(const chaiscript::detail::Dispatch_State &t_ds)
|
||||
: m_ds(t_ds)
|
||||
{
|
||||
m_ds.get()->new_stack(m_ds.get().stack_holder());
|
||||
m_ds->new_stack(m_ds.stack_holder());
|
||||
}
|
||||
|
||||
~Stack_Push_Pop()
|
||||
{
|
||||
m_ds.get()->pop_stack(m_ds.get().stack_holder());
|
||||
m_ds->pop_stack(m_ds.stack_holder());
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
std::reference_wrapper<const chaiscript::detail::Dispatch_State> m_ds;
|
||||
const chaiscript::detail::Dispatch_State &m_ds;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@@ -17,6 +17,7 @@
|
||||
#include <set>
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
#include <cstring>
|
||||
|
||||
#include "../chaiscript_defines.hpp"
|
||||
#include "../chaiscript_threading.hpp"
|
||||
@@ -33,227 +34,31 @@
|
||||
|
||||
#if defined(_POSIX_VERSION) && !defined(__CYGWIN__)
|
||||
#include <dlfcn.h>
|
||||
#else
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef CHAISCRIPT_WINDOWS
|
||||
#define VC_EXTRA_LEAN
|
||||
#if !defined(WIN32_LEAN_AND_MEAN)
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
#include <windows.h>
|
||||
#endif
|
||||
#include "chaiscript_windows.hpp"
|
||||
#elif _POSIX_VERSION
|
||||
#include "chaiscript_posix.hpp"
|
||||
#else
|
||||
#include "chaiscript_unknown.hpp"
|
||||
#endif
|
||||
|
||||
|
||||
#include "../dispatchkit/exception_specification.hpp"
|
||||
#include "chaiscript_parser.hpp"
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
namespace exception
|
||||
{
|
||||
/// \brief Thrown if an error occurs while attempting to load a binary module
|
||||
struct load_module_error : std::runtime_error
|
||||
{
|
||||
load_module_error(const std::string &t_reason) noexcept
|
||||
: std::runtime_error(t_reason)
|
||||
{
|
||||
}
|
||||
|
||||
load_module_error(const load_module_error &) = default;
|
||||
virtual ~load_module_error() noexcept {}
|
||||
};
|
||||
}
|
||||
|
||||
namespace detail
|
||||
{
|
||||
#if defined(_POSIX_VERSION) && !defined(__CYGWIN__)
|
||||
struct Loadable_Module
|
||||
{
|
||||
struct DLModule
|
||||
{
|
||||
DLModule(const std::string &t_filename)
|
||||
: m_data(dlopen(t_filename.c_str(), RTLD_NOW))
|
||||
{
|
||||
if (!m_data)
|
||||
{
|
||||
throw chaiscript::exception::load_module_error(dlerror());
|
||||
}
|
||||
}
|
||||
|
||||
DLModule(const DLModule &); // Explicitly unimplemented copy constructor
|
||||
DLModule &operator=(const DLModule &); // Explicitly unimplemented assignment operator
|
||||
|
||||
~DLModule()
|
||||
{
|
||||
dlclose(m_data);
|
||||
}
|
||||
|
||||
void *m_data;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct DLSym
|
||||
{
|
||||
DLSym(DLModule &t_mod, const std::string &t_symbol)
|
||||
: m_symbol(cast_symbol(dlsym(t_mod.m_data, t_symbol.c_str())))
|
||||
{
|
||||
if (!m_symbol)
|
||||
{
|
||||
throw chaiscript::exception::load_module_error(dlerror());
|
||||
}
|
||||
}
|
||||
|
||||
static T cast_symbol(void *p)
|
||||
{
|
||||
union cast_union
|
||||
{
|
||||
T func_ptr;
|
||||
void *in_ptr;
|
||||
};
|
||||
|
||||
cast_union c;
|
||||
c.in_ptr = p;
|
||||
return c.func_ptr;
|
||||
}
|
||||
|
||||
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<Create_Module_Func> m_func;
|
||||
ModulePtr m_moduleptr;
|
||||
};
|
||||
#else
|
||||
|
||||
#ifdef WIN32
|
||||
|
||||
|
||||
struct Loadable_Module
|
||||
{
|
||||
template<typename T>
|
||||
static std::wstring to_wstring(const T &t_str)
|
||||
{
|
||||
return std::wstring(t_str.begin(), t_str.end());
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static std::string to_string(const T &t_str)
|
||||
{
|
||||
return std::string(t_str.begin(), t_str.end());
|
||||
}
|
||||
|
||||
#if defined(_UNICODE) || defined(UNICODE)
|
||||
template<typename T>
|
||||
static std::wstring to_proper_string(const T &t_str)
|
||||
{
|
||||
return to_wstring(t_str);
|
||||
}
|
||||
#else
|
||||
template<typename T>
|
||||
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)
|
||||
{
|
||||
typedef LPTSTR StringType;
|
||||
|
||||
#if defined(_UNICODE) || defined(UNICODE)
|
||||
std::wstring retval = L"Unknown Error";
|
||||
#else
|
||||
std::string retval = "Unknown Error";
|
||||
#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<StringType>(&lpMsgBuf),
|
||||
0, nullptr ) != 0 && lpMsgBuf)
|
||||
{
|
||||
retval = lpMsgBuf;
|
||||
LocalFree(lpMsgBuf);
|
||||
}
|
||||
|
||||
return to_string(retval);
|
||||
}
|
||||
|
||||
struct DLModule
|
||||
{
|
||||
DLModule(const std::string &t_filename)
|
||||
: m_data(LoadLibrary(to_proper_string(t_filename).c_str()))
|
||||
{
|
||||
if (!m_data)
|
||||
{
|
||||
throw chaiscript::exception::load_module_error(get_error_message(GetLastError()));
|
||||
}
|
||||
}
|
||||
|
||||
~DLModule()
|
||||
{
|
||||
FreeLibrary(m_data);
|
||||
}
|
||||
|
||||
HMODULE m_data;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct DLSym
|
||||
{
|
||||
DLSym(DLModule &t_mod, const std::string &t_symbol)
|
||||
: m_symbol(reinterpret_cast<T>(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;
|
||||
};
|
||||
|
||||
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<Create_Module_Func> m_func;
|
||||
ModulePtr m_moduleptr;
|
||||
};
|
||||
|
||||
#else
|
||||
struct Loadable_Module
|
||||
{
|
||||
Loadable_Module(const std::string &, const std::string &)
|
||||
{
|
||||
throw chaiscript::exception::load_module_error("Loadable module support not available for your platform");
|
||||
}
|
||||
|
||||
ModulePtr m_moduleptr;
|
||||
};
|
||||
#endif
|
||||
#endif
|
||||
|
||||
typedef std::shared_ptr<Loadable_Module> Loadable_Module_Ptr;
|
||||
}
|
||||
|
||||
|
||||
/// \brief The main object that the ChaiScript user will use.
|
||||
class ChaiScript {
|
||||
class ChaiScript_Basic {
|
||||
|
||||
mutable chaiscript::detail::threading::shared_mutex m_mutex;
|
||||
mutable chaiscript::detail::threading::recursive_mutex m_use_mutex;
|
||||
@@ -265,19 +70,16 @@ namespace chaiscript
|
||||
std::vector<std::string> m_module_paths;
|
||||
std::vector<std::string> m_use_paths;
|
||||
|
||||
std::unique_ptr<parser::ChaiScript_Parser_Base> m_parser;
|
||||
|
||||
chaiscript::detail::Dispatch_Engine m_engine;
|
||||
|
||||
/// 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)
|
||||
{
|
||||
try {
|
||||
parser::ChaiScript_Parser parser;
|
||||
if (parser.parse(t_input, t_filename)) {
|
||||
//parser.show_match_stack();
|
||||
return parser.optimized_ast()->eval(m_engine);
|
||||
} else {
|
||||
return Boxed_Value();
|
||||
}
|
||||
const auto p = m_parser->parse(t_input, t_filename);
|
||||
return p->eval(m_engine);
|
||||
}
|
||||
catch (chaiscript::eval::detail::Return_Value &rv) {
|
||||
return rv.retval;
|
||||
@@ -286,8 +88,6 @@ namespace chaiscript
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/// Evaluates the given file and looks in the 'use' paths
|
||||
const Boxed_Value internal_eval_file(const std::string &t_filename) {
|
||||
for (const auto &path : m_use_paths)
|
||||
@@ -324,28 +124,7 @@ namespace chaiscript
|
||||
}
|
||||
|
||||
/// Builds all the requirements for ChaiScript, including its evaluator and a run of its prelude.
|
||||
void build_eval_system(const ModulePtr &t_lib) {
|
||||
m_engine.add_reserved_word("def");
|
||||
m_engine.add_reserved_word("fun");
|
||||
m_engine.add_reserved_word("while");
|
||||
m_engine.add_reserved_word("for");
|
||||
m_engine.add_reserved_word("if");
|
||||
m_engine.add_reserved_word("else");
|
||||
m_engine.add_reserved_word("&&");
|
||||
m_engine.add_reserved_word("||");
|
||||
m_engine.add_reserved_word(",");
|
||||
m_engine.add_reserved_word("auto");
|
||||
m_engine.add_reserved_word("return");
|
||||
m_engine.add_reserved_word("break");
|
||||
m_engine.add_reserved_word("true");
|
||||
m_engine.add_reserved_word("false");
|
||||
m_engine.add_reserved_word("class");
|
||||
m_engine.add_reserved_word("attr");
|
||||
m_engine.add_reserved_word("var");
|
||||
m_engine.add_reserved_word("global");
|
||||
m_engine.add_reserved_word("GLOBAL");
|
||||
m_engine.add_reserved_word("_");
|
||||
|
||||
void build_eval_system(const ModulePtr &t_lib, const std::vector<Options> &t_opts) {
|
||||
if (t_lib)
|
||||
{
|
||||
add(t_lib);
|
||||
@@ -390,23 +169,26 @@ namespace chaiscript
|
||||
|
||||
|
||||
|
||||
m_engine.add(fun([this](const std::string &t_module, const std::string &t_file){ return 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_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){ return 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");
|
||||
}
|
||||
|
||||
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_NodePtr &t_ast){ return eval(t_ast); }), "eval");
|
||||
m_engine.add(fun(&parse), "parse");
|
||||
|
||||
m_engine.add(fun(&ChaiScript::version_major), "version_major");
|
||||
m_engine.add(fun(&ChaiScript::version_minor), "version_minor");
|
||||
m_engine.add(fun(&ChaiScript::version_patch), "version_patch");
|
||||
m_engine.add(fun(&ChaiScript::version), "version");
|
||||
m_engine.add(fun(&ChaiScript::compiler_version), "compiler_version");
|
||||
m_engine.add(fun(&ChaiScript::compiler_name), "compiler_name");
|
||||
m_engine.add(fun(&ChaiScript::compiler_id), "compiler_id");
|
||||
m_engine.add(fun(&ChaiScript::debug_build), "debug_build");
|
||||
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");
|
||||
@@ -437,64 +219,42 @@ namespace chaiscript
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::string> ensure_minimum_path_vec(std::vector<std::string> 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
|
||||
/// \param[in] t_usepaths Vector of paths to search when attempting to "use" an included ChaiScript file
|
||||
ChaiScript(const ModulePtr &t_lib,
|
||||
std::vector<std::string> t_modulepaths = std::vector<std::string>(),
|
||||
std::vector<std::string> t_usepaths = std::vector<std::string>())
|
||||
: m_module_paths(std::move(t_modulepaths)), m_use_paths(std::move(t_usepaths))
|
||||
ChaiScript_Basic(const ModulePtr &t_lib,
|
||||
std::unique_ptr<parser::ChaiScript_Parser_Base> &&parser,
|
||||
std::vector<std::string> t_module_paths = {},
|
||||
std::vector<std::string> t_use_paths = {},
|
||||
const std::vector<chaiscript::Options> &t_opts = chaiscript::default_options())
|
||||
: 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 (m_module_paths.empty())
|
||||
{
|
||||
m_module_paths.push_back("");
|
||||
}
|
||||
|
||||
if (m_use_paths.empty())
|
||||
{
|
||||
m_use_paths.push_back("");
|
||||
}
|
||||
|
||||
build_eval_system(t_lib);
|
||||
}
|
||||
|
||||
/// \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
|
||||
ChaiScript( std::vector<std::string> t_modulepaths = std::vector<std::string>(),
|
||||
std::vector<std::string> t_usepaths = std::vector<std::string>())
|
||||
: m_module_paths(std::move(t_modulepaths)), m_use_paths(std::move(t_usepaths))
|
||||
{
|
||||
if (m_module_paths.empty())
|
||||
{
|
||||
m_module_paths.push_back("");
|
||||
}
|
||||
|
||||
if (m_use_paths.empty())
|
||||
{
|
||||
m_use_paths.push_back("");
|
||||
}
|
||||
|
||||
#if 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::*in_ptr)(const std::string&);
|
||||
Boxed_Value (ChaiScript_Basic::*in_ptr)(const std::string&);
|
||||
void *out_ptr;
|
||||
};
|
||||
|
||||
Dl_info rInfo;
|
||||
memset( &rInfo, 0, sizeof(rInfo) );
|
||||
cast_union u;
|
||||
u.in_ptr = &ChaiScript::use;
|
||||
u.in_ptr = &ChaiScript_Basic::use;
|
||||
if ( dladdr(static_cast<void*>(u.out_ptr), &rInfo) && rInfo.dli_fname ) {
|
||||
std::string dllpath(rInfo.dli_fname);
|
||||
const size_t lastslash = dllpath.rfind('/');
|
||||
@@ -514,12 +274,37 @@ namespace chaiscript
|
||||
m_module_paths.insert(m_module_paths.begin(), dllpath+"/");
|
||||
}
|
||||
#endif
|
||||
build_eval_system(t_lib, t_opts);
|
||||
}
|
||||
|
||||
|
||||
// attempt to load the stdlib
|
||||
load_module("chaiscript_stdlib-" + version());
|
||||
|
||||
build_eval_system(ModulePtr());
|
||||
/// \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
|
||||
ChaiScript_Basic(std::unique_ptr<parser::ChaiScript_Parser_Base> &&parser,
|
||||
std::vector<std::string> t_module_paths = {},
|
||||
std::vector<std::string> t_use_paths = {},
|
||||
const std::vector<chaiscript::Options> &t_opts = chaiscript::default_options())
|
||||
: 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"
|
||||
<< t_err.what();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -532,65 +317,16 @@ namespace chaiscript
|
||||
}
|
||||
}
|
||||
|
||||
static AST_NodePtr parse(const std::string &t_input)
|
||||
AST_NodePtr parse(const std::string &t_input, const bool t_debug_print = false)
|
||||
{
|
||||
parser::ChaiScript_Parser parser;
|
||||
if (parser.parse(t_input, "PARSE")) {
|
||||
//parser.show_match_stack();
|
||||
return parser.optimized_ast();
|
||||
} else {
|
||||
throw chaiscript::exception::eval_error("Unknown error while parsing");
|
||||
const auto ast = m_parser->parse(t_input, "PARSE");
|
||||
if (t_debug_print) {
|
||||
m_parser->debug_print(ast);
|
||||
}
|
||||
return ast;
|
||||
}
|
||||
|
||||
|
||||
static int version_major()
|
||||
{
|
||||
return chaiscript::version_major;
|
||||
}
|
||||
|
||||
static int version_minor()
|
||||
{
|
||||
return chaiscript::version_minor;
|
||||
}
|
||||
|
||||
static int version_patch()
|
||||
{
|
||||
return chaiscript::version_patch;
|
||||
}
|
||||
|
||||
static std::string version()
|
||||
{
|
||||
return std::to_string(version_major()) + '.' + std::to_string(version_minor()) + '.' + std::to_string(version_patch());
|
||||
}
|
||||
|
||||
static std::string compiler_id()
|
||||
{
|
||||
return compiler_name() + '-' + compiler_version();
|
||||
}
|
||||
|
||||
static std::string build_id()
|
||||
{
|
||||
return compiler_id() + (debug_build()?"-Debug":"-Release");
|
||||
}
|
||||
|
||||
static std::string compiler_version()
|
||||
{
|
||||
return chaiscript::compiler_version;
|
||||
}
|
||||
|
||||
static std::string compiler_name()
|
||||
{
|
||||
return chaiscript::compiler_name;
|
||||
}
|
||||
|
||||
static bool debug_build()
|
||||
{
|
||||
return chaiscript::debug_build;
|
||||
}
|
||||
|
||||
|
||||
|
||||
std::string get_type_name(const Type_Info &ti) const
|
||||
{
|
||||
return m_engine.get_type_name(ti);
|
||||
@@ -643,8 +379,9 @@ 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 &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;
|
||||
}
|
||||
@@ -654,14 +391,16 @@ 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 &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 &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;
|
||||
}
|
||||
@@ -759,8 +498,9 @@ namespace chaiscript
|
||||
///
|
||||
/// \sa \ref adding_items
|
||||
template<typename T>
|
||||
ChaiScript &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;
|
||||
}
|
||||
@@ -774,7 +514,7 @@ namespace chaiscript
|
||||
/// chaiscript::ChaiScript chai;
|
||||
/// chai.add(chaiscript::base_class<std::runtime_error, chaiscript::dispatch_error>());
|
||||
/// \endcode
|
||||
ChaiScript &add(const Type_Conversion &d)
|
||||
ChaiScript_Basic &add(const Type_Conversion &d)
|
||||
{
|
||||
m_engine.add(d);
|
||||
return *this;
|
||||
@@ -783,7 +523,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 &add(const ModulePtr &t_p)
|
||||
ChaiScript_Basic &add(const ModulePtr &t_p)
|
||||
{
|
||||
t_p->apply(*this, this->get_eval_engine());
|
||||
return *this;
|
||||
@@ -805,7 +545,7 @@ namespace chaiscript
|
||||
{
|
||||
std::vector<exception::load_module_error> errors;
|
||||
std::string version_stripped_name = t_module_name;
|
||||
size_t version_pos = version_stripped_name.find("-"+version());
|
||||
size_t version_pos = version_stripped_name.find("-" + Build_Info::version());
|
||||
if (version_pos != std::string::npos)
|
||||
{
|
||||
version_stripped_name.erase(version_pos);
|
||||
@@ -835,21 +575,7 @@ namespace chaiscript
|
||||
}
|
||||
}
|
||||
|
||||
std::string errstring;
|
||||
|
||||
for (std::vector<exception::load_module_error>::const_iterator itr = errors.begin();
|
||||
itr != errors.end();
|
||||
++itr)
|
||||
{
|
||||
if (!errstring.empty())
|
||||
{
|
||||
errstring += "; ";
|
||||
}
|
||||
|
||||
errstring += itr->what();
|
||||
}
|
||||
|
||||
throw chaiscript::exception::load_module_error("Unable to find module: " + t_module_name + " Errors: " + errstring);
|
||||
throw chaiscript::exception::load_module_error(t_module_name, errors);
|
||||
}
|
||||
|
||||
/// \brief Load a binary module from a dynamic library. Works on platforms that support
|
||||
@@ -886,14 +612,7 @@ namespace chaiscript
|
||||
/// \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())
|
||||
{
|
||||
try {
|
||||
return do_eval(t_script);
|
||||
} catch (Boxed_Value &bv) {
|
||||
if (t_handler) {
|
||||
t_handler->handle(bv, m_engine);
|
||||
}
|
||||
throw;
|
||||
}
|
||||
return eval(t_script, t_handler);
|
||||
}
|
||||
|
||||
/// \brief Evaluates a string and returns a typesafe result.
|
||||
@@ -912,21 +631,14 @@ namespace chaiscript
|
||||
template<typename T>
|
||||
T eval(const std::string &t_input, const Exception_Handler &t_handler = Exception_Handler(), const std::string &t_filename="__EVAL__")
|
||||
{
|
||||
try {
|
||||
return m_engine.boxed_cast<T>(do_eval(t_input, t_filename));
|
||||
} catch (Boxed_Value &bv) {
|
||||
if (t_handler) {
|
||||
t_handler->handle(bv, m_engine);
|
||||
}
|
||||
throw;
|
||||
}
|
||||
return m_engine.boxed_cast<T>(eval(t_input, t_handler, t_filename));
|
||||
}
|
||||
|
||||
/// \brief casts an object while applying any Dynamic_Conversion available
|
||||
template<typename Type>
|
||||
typename detail::Cast_Helper<Type>::Result_Type boxed_cast(const Boxed_Value &bv) const
|
||||
decltype(auto) boxed_cast(const Boxed_Value &bv) const
|
||||
{
|
||||
return m_engine.boxed_cast<Type>(bv);
|
||||
return(m_engine.boxed_cast<Type>(bv));
|
||||
}
|
||||
|
||||
|
||||
@@ -958,14 +670,7 @@ namespace chaiscript
|
||||
/// \return result of the script execution
|
||||
/// \throw chaiscript::exception::eval_error In the case that evaluation fails.
|
||||
Boxed_Value eval_file(const std::string &t_filename, const Exception_Handler &t_handler = Exception_Handler()) {
|
||||
try {
|
||||
return do_eval(load_file(t_filename), t_filename);
|
||||
} catch (Boxed_Value &bv) {
|
||||
if (t_handler) {
|
||||
t_handler->handle(bv, m_engine);
|
||||
}
|
||||
throw;
|
||||
}
|
||||
return eval(load_file(t_filename), t_handler, t_filename);
|
||||
}
|
||||
|
||||
/// \brief Loads the file specified by filename, evaluates it, and returns the type safe result.
|
||||
@@ -978,14 +683,7 @@ namespace chaiscript
|
||||
/// to the requested type.
|
||||
template<typename T>
|
||||
T eval_file(const std::string &t_filename, const Exception_Handler &t_handler = Exception_Handler()) {
|
||||
try {
|
||||
return m_engine.boxed_cast<T>(do_eval(load_file(t_filename), t_filename));
|
||||
} catch (Boxed_Value &bv) {
|
||||
if (t_handler) {
|
||||
t_handler->handle(bv, m_engine);
|
||||
}
|
||||
throw;
|
||||
}
|
||||
return m_engine.boxed_cast<T>(eval_file(t_filename, t_handler));
|
||||
}
|
||||
};
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
427
include/chaiscript/language/chaiscript_optimizer.hpp
Normal file
427
include/chaiscript/language/chaiscript_optimizer.hpp
Normal file
@@ -0,0 +1,427 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// Copyright 2009-2016, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#ifndef CHAISCRIPT_OPTIMIZER_HPP_
|
||||
#define CHAISCRIPT_OPTIMIZER_HPP_
|
||||
|
||||
#include "chaiscript_eval.hpp"
|
||||
|
||||
|
||||
namespace chaiscript {
|
||||
namespace optimizer {
|
||||
|
||||
template<typename ... T>
|
||||
struct Optimizer : T...
|
||||
{
|
||||
Optimizer() = default;
|
||||
Optimizer(T ... t)
|
||||
: T(std::move(t))...
|
||||
{
|
||||
}
|
||||
|
||||
template<typename Tracer>
|
||||
auto optimize(eval::AST_Node_Impl_Ptr<Tracer> p) {
|
||||
(void)std::initializer_list<int>{ (p = static_cast<T&>(*this).optimize(p), 0)... };
|
||||
return p;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
auto child_at(const eval::AST_Node_Impl_Ptr<T> &node, const size_t offset) {
|
||||
if (node->children[offset]->identifier == AST_Node_Type::Compiled) {
|
||||
return dynamic_cast<const eval::Compiled_AST_Node<T>&>(*node->children[offset]).m_original_node;
|
||||
} else {
|
||||
return node->children[offset];
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
if (node->identifier == AST_Node_Type::Compiled) {
|
||||
return dynamic_cast<const eval::Compiled_AST_Node<T>&>(*node).m_original_node->children[offset];
|
||||
} else {
|
||||
return node->children[offset];
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
auto child_count(const eval::AST_Node_Impl_Ptr<T> &node) {
|
||||
if (node->identifier == AST_Node_Type::Compiled) {
|
||||
return dynamic_cast<const eval::Compiled_AST_Node<T>&>(*node).m_original_node->children.size();
|
||||
} else {
|
||||
return node->children.size();
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T, typename Callable>
|
||||
auto make_compiled_node(const eval::AST_Node_Impl_Ptr<T> &original_node, std::vector<eval::AST_Node_Impl_Ptr<T>> children, Callable callable)
|
||||
{
|
||||
return chaiscript::make_shared<eval::AST_Node_Impl<T>, eval::Compiled_AST_Node<T>>(original_node, std::move(children), std::move(callable));
|
||||
}
|
||||
|
||||
|
||||
struct Return {
|
||||
template<typename T>
|
||||
auto optimize(const eval::AST_Node_Impl_Ptr<T> &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();
|
||||
if (block_last_child->identifier == AST_Node_Type::Return) {
|
||||
if (block_last_child->children.size() == 1) {
|
||||
last_child->children.back() = block_last_child->children[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
bool contains_var_decl_in_scope(const T &node)
|
||||
{
|
||||
if (node->identifier == AST_Node_Type::Var_Decl) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto num = child_count(node);
|
||||
|
||||
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
|
||||
&& contains_var_decl_in_scope(child)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
struct Block {
|
||||
template<typename T>
|
||||
auto optimize(const eval::AST_Node_Impl_Ptr<T> &node) {
|
||||
if (node->identifier == AST_Node_Type::Block)
|
||||
{
|
||||
if (!contains_var_decl_in_scope(node))
|
||||
{
|
||||
if (node->children.size() == 1) {
|
||||
return node->children[0];
|
||||
} else {
|
||||
return chaiscript::make_shared<eval::AST_Node_Impl<T>, eval::Scopeless_Block_AST_Node<T>>(node->text, node->location, node->children);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
};
|
||||
|
||||
struct Dead_Code {
|
||||
template<typename T>
|
||||
auto optimize(const eval::AST_Node_Impl_Ptr<T> &node) {
|
||||
if (node->identifier == AST_Node_Type::Block)
|
||||
{
|
||||
std::vector<size_t> keepers;
|
||||
const auto num_children = node->children.size();
|
||||
keepers.reserve(num_children);
|
||||
|
||||
for (size_t i = 0; i < num_children; ++i) {
|
||||
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 {
|
||||
std::vector<eval::AST_Node_Impl_Ptr<T>> new_children;
|
||||
for (const auto x : keepers)
|
||||
{
|
||||
new_children.push_back(node->children[x]);
|
||||
}
|
||||
return chaiscript::make_shared<eval::AST_Node_Impl<T>, eval::Block_AST_Node<T>>(node->text, node->location, new_children);
|
||||
}
|
||||
} else {
|
||||
return node;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct Unused_Return {
|
||||
template<typename T>
|
||||
auto optimize(const eval::AST_Node_Impl_Ptr<T> &node) {
|
||||
if ((node->identifier == AST_Node_Type::Block
|
||||
|| node->identifier == AST_Node_Type::Scopeless_Block)
|
||||
&& node->children.size() > 0)
|
||||
{
|
||||
for (size_t i = 0; i < node->children.size()-1; ++i) {
|
||||
auto child = node->children[i];
|
||||
if (child->identifier == AST_Node_Type::Fun_Call) {
|
||||
node->children[i] = chaiscript::make_shared<eval::AST_Node_Impl<T>, eval::Unused_Return_Fun_Call_AST_Node<T>>(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_shared<eval::AST_Node_Impl<T>, eval::Unused_Return_Fun_Call_AST_Node<T>>(sub_child->text, sub_child->location, std::move(sub_child->children));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return node;
|
||||
}
|
||||
};
|
||||
|
||||
struct If {
|
||||
template<typename T>
|
||||
auto optimize(const eval::AST_Node_Impl_Ptr<T> &node) {
|
||||
if ((node->identifier == AST_Node_Type::If || node->identifier == AST_Node_Type::Ternary_Cond)
|
||||
&& node->children.size() >= 2
|
||||
&& node->children[0]->identifier == AST_Node_Type::Constant)
|
||||
{
|
||||
const auto condition = std::dynamic_pointer_cast<eval::Constant_AST_Node<T>>(node->children[0])->m_value;
|
||||
if (condition.get_type_info().bare_equal_type_info(typeid(bool))) {
|
||||
if (boxed_cast<bool>(condition)) {
|
||||
return node->children[1];
|
||||
} else if (node->children.size() == 3) {
|
||||
return node->children[2];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
};
|
||||
|
||||
struct Partial_Fold {
|
||||
template<typename T>
|
||||
auto optimize(const eval::AST_Node_Impl_Ptr<T> &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)
|
||||
{
|
||||
try {
|
||||
const auto &oper = node->text;
|
||||
const auto parsed = Operators::to_operator(oper);
|
||||
if (parsed != Operators::Opers::invalid) {
|
||||
const auto rhs = std::dynamic_pointer_cast<eval::Constant_AST_Node<T>>(node->children[1])->m_value;
|
||||
if (rhs.get_type_info().is_arithmetic()) {
|
||||
return chaiscript::make_shared<eval::AST_Node_Impl<T>, eval::Fold_Right_Binary_Operator_AST_Node<T>>(node->text, node->location, node->children, rhs);
|
||||
}
|
||||
}
|
||||
} catch (const std::exception &) {
|
||||
//failure to fold, that's OK
|
||||
}
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
};
|
||||
|
||||
struct Constant_Fold {
|
||||
template<typename T>
|
||||
auto optimize(const eval::AST_Node_Impl_Ptr<T> &node) {
|
||||
|
||||
if (node->identifier == AST_Node_Type::Prefix
|
||||
&& node->children.size() == 1
|
||||
&& node->children[0]->identifier == AST_Node_Type::Constant)
|
||||
{
|
||||
try {
|
||||
const auto &oper = node->text;
|
||||
const auto parsed = Operators::to_operator(oper, true);
|
||||
const auto lhs = std::dynamic_pointer_cast<eval::Constant_AST_Node<T>>(node->children[0])->m_value;
|
||||
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_shared<eval::AST_Node_Impl<T>, eval::Constant_AST_Node<T>>(std::move(match), node->location, std::move(val));
|
||||
} else if (lhs.get_type_info().bare_equal_type_info(typeid(bool)) && oper == "!") {
|
||||
return chaiscript::make_shared<eval::AST_Node_Impl<T>, eval::Constant_AST_Node<T>>(std::move(match), node->location, Boxed_Value(!boxed_cast<bool>(lhs)));
|
||||
}
|
||||
} catch (const std::exception &) {
|
||||
//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)
|
||||
{
|
||||
try {
|
||||
const auto lhs = std::dynamic_pointer_cast<eval::Constant_AST_Node<T>>(node->children[0])->m_value;
|
||||
const auto rhs = std::dynamic_pointer_cast<eval::Constant_AST_Node<T>>(node->children[1])->m_value;
|
||||
if (lhs.get_type_info().bare_equal_type_info(typeid(bool)) && rhs.get_type_info().bare_equal_type_info(typeid(bool))) {
|
||||
const auto match = node->children[0]->text + " " + node->text + " " + node->children[1]->text;
|
||||
const auto val = [lhs_val = boxed_cast<bool>(lhs), rhs_val = boxed_cast<bool>(rhs), id = node->identifier] {
|
||||
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_shared<eval::AST_Node_Impl<T>, eval::Constant_AST_Node<T>>(std::move(match), node->location, std::move(val));
|
||||
}
|
||||
} catch (const std::exception &) {
|
||||
//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)
|
||||
{
|
||||
try {
|
||||
const auto &oper = node->text;
|
||||
const auto parsed = Operators::to_operator(oper);
|
||||
if (parsed != Operators::Opers::invalid) {
|
||||
const auto lhs = std::dynamic_pointer_cast<eval::Constant_AST_Node<T>>(node->children[0])->m_value;
|
||||
const auto rhs = std::dynamic_pointer_cast<eval::Constant_AST_Node<T>>(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 match = node->children[0]->text + " " + oper + " " + node->children[1]->text;
|
||||
return chaiscript::make_shared<eval::AST_Node_Impl<T>, eval::Constant_AST_Node<T>>(std::move(match), node->location, std::move(val));
|
||||
}
|
||||
}
|
||||
} catch (const std::exception &) {
|
||||
//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) {
|
||||
|
||||
const auto arg = std::dynamic_pointer_cast<eval::Constant_AST_Node<T>>(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 match = fun_name + "(" + node->children[1]->children[0]->text + ")";
|
||||
return chaiscript::make_shared<eval::AST_Node_Impl<T>, eval::Constant_AST_Node<T>>(std::move(match), node->location, Boxed_Value(val));
|
||||
};
|
||||
|
||||
if (fun_name == "double") {
|
||||
return make_constant(Boxed_Number(arg).get_as<double>());
|
||||
} else if (fun_name == "int") {
|
||||
return make_constant(Boxed_Number(arg).get_as<int>());
|
||||
} else if (fun_name == "float") {
|
||||
return make_constant(Boxed_Number(arg).get_as<float>());
|
||||
} else if (fun_name == "long") {
|
||||
return make_constant(Boxed_Number(arg).get_as<long>());
|
||||
} else if (fun_name == "size_t") {
|
||||
return make_constant(Boxed_Number(arg).get_as<size_t>());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
};
|
||||
|
||||
struct For_Loop {
|
||||
template<typename T>
|
||||
auto optimize(const eval::AST_Node_Impl_Ptr<T> &for_node) {
|
||||
|
||||
if (for_node->identifier != AST_Node_Type::For) {
|
||||
return for_node;
|
||||
}
|
||||
|
||||
const auto eq_node = child_at(for_node, 0);
|
||||
const auto binary_node = child_at(for_node, 1);
|
||||
const auto prefix_node = child_at(for_node, 2);
|
||||
|
||||
if (eq_node->identifier == AST_Node_Type::Equation
|
||||
&& child_count(eq_node) == 2
|
||||
&& child_at(eq_node, 0)->identifier == AST_Node_Type::Var_Decl
|
||||
&& 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(child_at(eq_node,0), 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(child_at(eq_node,0), 0)->text)
|
||||
{
|
||||
const Boxed_Value &begin = std::dynamic_pointer_cast<const eval::Constant_AST_Node<T>>(child_at(eq_node, 1))->m_value;
|
||||
const Boxed_Value &end = std::dynamic_pointer_cast<const eval::Constant_AST_Node<T>>(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<int>())
|
||||
&& end.get_type_info().bare_equal(user_type<int>())) {
|
||||
|
||||
const auto start_int = boxed_cast<int>(begin);
|
||||
const auto end_int = boxed_cast<int>(end);
|
||||
|
||||
const auto body = child_at(for_node, 3);
|
||||
|
||||
return make_compiled_node(for_node, {body},
|
||||
[id, start_int, end_int](const std::vector<eval::AST_Node_Impl_Ptr<T>> &children, const chaiscript::detail::Dispatch_State &t_ss) {
|
||||
assert(children.size() == 1);
|
||||
chaiscript::eval::detail::Scope_Push_Pop spp(t_ss);
|
||||
|
||||
int i = start_int;
|
||||
t_ss.add_object(id, var(&i));
|
||||
|
||||
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;
|
||||
}
|
||||
} else {
|
||||
return for_node;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
typedef Optimizer<optimizer::Partial_Fold, optimizer::Unused_Return, optimizer::Constant_Fold,
|
||||
optimizer::If, optimizer::Return, optimizer::Dead_Code, optimizer::Block, optimizer::For_Loop> Optimizer_Default;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
81
include/chaiscript/language/chaiscript_posix.hpp
Normal file
81
include/chaiscript/language/chaiscript_posix.hpp
Normal file
@@ -0,0 +1,81 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// Copyright 2009-2016, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#ifndef CHAISCRIPT_POSIX_HPP_
|
||||
#define CHAISCRIPT_POSIX_HPP_
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
struct Loadable_Module
|
||||
{
|
||||
struct DLModule
|
||||
{
|
||||
DLModule(const std::string &t_filename)
|
||||
: m_data(dlopen(t_filename.c_str(), RTLD_NOW))
|
||||
{
|
||||
if (!m_data)
|
||||
{
|
||||
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<typename T>
|
||||
struct DLSym
|
||||
{
|
||||
DLSym(DLModule &t_mod, const std::string &t_symbol)
|
||||
: m_symbol(cast_symbol(dlsym(t_mod.m_data, t_symbol.c_str())))
|
||||
{
|
||||
if (!m_symbol)
|
||||
{
|
||||
throw chaiscript::exception::load_module_error(dlerror());
|
||||
}
|
||||
}
|
||||
|
||||
static T cast_symbol(void *p)
|
||||
{
|
||||
union cast_union
|
||||
{
|
||||
T func_ptr;
|
||||
void *in_ptr;
|
||||
};
|
||||
|
||||
cast_union c;
|
||||
c.in_ptr = p;
|
||||
return c.func_ptr;
|
||||
}
|
||||
|
||||
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<Create_Module_Func> m_func;
|
||||
ModulePtr m_moduleptr;
|
||||
};
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
43
include/chaiscript/language/chaiscript_tracer.hpp
Normal file
43
include/chaiscript/language/chaiscript_tracer.hpp
Normal file
@@ -0,0 +1,43 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// Copyright 2009-2016, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#ifndef CHAISCRIPT_TRACER_HPP_
|
||||
#define CHAISCRIPT_TRACER_HPP_
|
||||
|
||||
namespace chaiscript {
|
||||
namespace eval {
|
||||
|
||||
struct Noop_Tracer
|
||||
{
|
||||
template<typename T>
|
||||
static void trace(const chaiscript::detail::Dispatch_State &, const AST_Node_Impl<T> *)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
template<typename ... T>
|
||||
struct Tracer : T...
|
||||
{
|
||||
Tracer() = default;
|
||||
Tracer(T ... t)
|
||||
: T(std::move(t))...
|
||||
{
|
||||
}
|
||||
|
||||
void do_trace(const chaiscript::detail::Dispatch_State &ds, const AST_Node_Impl<Tracer<T...>> *node) {
|
||||
(void)std::initializer_list<int>{ (T::trace(ds, node), 0)... };
|
||||
}
|
||||
|
||||
static void trace(const chaiscript::detail::Dispatch_State &ds, const AST_Node_Impl<Tracer<T...>> *node) {
|
||||
ds->get_parser().get_tracer<Tracer<T...>>().do_trace(ds, node);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
27
include/chaiscript/language/chaiscript_unknown.hpp
Normal file
27
include/chaiscript/language/chaiscript_unknown.hpp
Normal file
@@ -0,0 +1,27 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// Copyright 2009-2016, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#ifndef CHAISCRIPT_UNKNOWN_HPP_
|
||||
#define CHAISCRIPT_UNKNOWN_HPP_
|
||||
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
struct Loadable_Module
|
||||
{
|
||||
Loadable_Module(const std::string &, const std::string &)
|
||||
{
|
||||
throw chaiscript::exception::load_module_error("Loadable module support not available for your platform");
|
||||
}
|
||||
|
||||
ModulePtr m_moduleptr;
|
||||
};
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
133
include/chaiscript/language/chaiscript_windows.hpp
Normal file
133
include/chaiscript/language/chaiscript_windows.hpp
Normal file
@@ -0,0 +1,133 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// Copyright 2009-2016, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#ifndef CHAISCRIPT_WINDOWS_HPP_
|
||||
#define CHAISCRIPT_WINDOWS_HPP_
|
||||
|
||||
#include <string>
|
||||
|
||||
#ifdef CHAISCRIPT_WINDOWS
|
||||
#define VC_EXTRA_LEAN
|
||||
#if !defined(WIN32_LEAN_AND_MEAN)
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
struct Loadable_Module
|
||||
{
|
||||
template<typename T>
|
||||
static std::wstring to_wstring(const T &t_str)
|
||||
{
|
||||
return std::wstring(t_str.begin(), t_str.end());
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static std::string to_string(const T &t_str)
|
||||
{
|
||||
return std::string(t_str.begin(), t_str.end());
|
||||
}
|
||||
|
||||
#if defined(_UNICODE) || defined(UNICODE)
|
||||
template<typename T>
|
||||
static std::wstring to_proper_string(const T &t_str)
|
||||
{
|
||||
return to_wstring(t_str);
|
||||
}
|
||||
#else
|
||||
template<typename T>
|
||||
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)
|
||||
{
|
||||
typedef LPTSTR StringType;
|
||||
|
||||
#if defined(_UNICODE) || defined(UNICODE)
|
||||
std::wstring retval = L"Unknown Error";
|
||||
#else
|
||||
std::string retval = "Unknown Error";
|
||||
#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<StringType>(&lpMsgBuf),
|
||||
0, nullptr ) != 0 && lpMsgBuf)
|
||||
{
|
||||
retval = lpMsgBuf;
|
||||
LocalFree(lpMsgBuf);
|
||||
}
|
||||
|
||||
return to_string(retval);
|
||||
}
|
||||
|
||||
struct DLModule
|
||||
{
|
||||
DLModule(const std::string &t_filename)
|
||||
: m_data(LoadLibrary(to_proper_string(t_filename).c_str()))
|
||||
{
|
||||
if (!m_data)
|
||||
{
|
||||
throw chaiscript::exception::load_module_error(get_error_message(GetLastError()));
|
||||
}
|
||||
}
|
||||
|
||||
DLModule(DLModule &&) = default;
|
||||
DLModule &operator=(DLModule &&) = default;
|
||||
DLModule(const DLModule &) = delete;
|
||||
DLModule &operator=(const DLModule &) = delete;
|
||||
|
||||
~DLModule()
|
||||
{
|
||||
FreeLibrary(m_data);
|
||||
}
|
||||
|
||||
HMODULE m_data;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct DLSym
|
||||
{
|
||||
DLSym(DLModule &t_mod, const std::string &t_symbol)
|
||||
: m_symbol(reinterpret_cast<T>(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;
|
||||
};
|
||||
|
||||
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<Create_Module_Func> m_func;
|
||||
ModulePtr m_moduleptr;
|
||||
};
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@@ -47,6 +47,79 @@ class JSON
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
struct QuickFlatMap
|
||||
{
|
||||
auto find(const std::string &s) {
|
||||
return std::find_if(std::begin(data), std::end(data), [&s](const auto &d) { return d.first == s; });
|
||||
}
|
||||
|
||||
auto find(const std::string &s) const {
|
||||
return std::find_if(std::begin(data), std::end(data), [&s](const auto &d) { return d.first == s; });
|
||||
}
|
||||
|
||||
auto size() const {
|
||||
return data.size();
|
||||
}
|
||||
|
||||
auto begin() const {
|
||||
return data.begin();
|
||||
}
|
||||
|
||||
auto end() const {
|
||||
return data.end();
|
||||
}
|
||||
|
||||
|
||||
auto begin() {
|
||||
return data.begin();
|
||||
}
|
||||
|
||||
auto end() {
|
||||
return data.end();
|
||||
}
|
||||
|
||||
|
||||
JSON &operator[](const std::string &s) {
|
||||
const auto itr = find(s);
|
||||
if (itr != data.end()) {
|
||||
return itr->second;
|
||||
} else {
|
||||
data.emplace_back(s, JSON());
|
||||
return data.back().second;
|
||||
}
|
||||
}
|
||||
|
||||
JSON &at(const std::string &s) {
|
||||
const auto itr = find(s);
|
||||
if (itr != data.end()) {
|
||||
return itr->second;
|
||||
} else {
|
||||
throw std::out_of_range("Unknown key: " + s);
|
||||
}
|
||||
}
|
||||
|
||||
const JSON &at(const std::string &s) const {
|
||||
const auto itr = find(s);
|
||||
if (itr != data.end()) {
|
||||
return itr->second;
|
||||
} else {
|
||||
throw std::out_of_range("Unknown key: " + s);
|
||||
}
|
||||
}
|
||||
|
||||
size_t count(const std::string &s) const {
|
||||
return (find(s) != data.end())?1:0;
|
||||
}
|
||||
|
||||
std::vector<std::pair<std::string, JSON>> data;
|
||||
|
||||
using iterator = decltype(data)::iterator;
|
||||
using const_iterator = decltype(data)::const_iterator;
|
||||
|
||||
|
||||
};
|
||||
|
||||
struct Internal {
|
||||
template<typename T>
|
||||
auto clone(const std::unique_ptr<T> &ptr) {
|
||||
@@ -100,7 +173,7 @@ class JSON
|
||||
String.reset();
|
||||
|
||||
switch( type ) {
|
||||
case Class::Object: Map = std::make_unique<std::map<std::string,JSON>>(); break;
|
||||
case Class::Object: Map = std::make_unique<QuickFlatMap>(); break;
|
||||
case Class::Array: List = std::make_unique<std::vector<JSON>>(); break;
|
||||
case Class::String: String = std::make_unique<std::string>(); break;
|
||||
case Class::Floating: Float = 0.0; break;
|
||||
@@ -116,7 +189,7 @@ class JSON
|
||||
Internal &operator=(Internal &&) = default;
|
||||
|
||||
std::unique_ptr<std::vector<JSON>> List;
|
||||
std::unique_ptr<std::map<std::string,JSON>> Map;
|
||||
std::unique_ptr<QuickFlatMap> Map;
|
||||
std::unique_ptr<std::string> String;
|
||||
double Float = 0;
|
||||
long Int = 0;
|
||||
@@ -229,7 +302,7 @@ class JSON
|
||||
|
||||
bool has_key( const std::string &key ) const {
|
||||
if( internal.Type == Class::Object ) {
|
||||
return internal.Map->find( key ) != internal.Map->end();
|
||||
return internal.Map->count(key) != 0;
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -274,11 +347,11 @@ class JSON
|
||||
return ok ? internal.Bool : false;
|
||||
}
|
||||
|
||||
JSONWrapper<std::map<std::string,JSON>> object_range() {
|
||||
JSONWrapper<QuickFlatMap> object_range() {
|
||||
if( internal.Type == Class::Object ) {
|
||||
return JSONWrapper<std::map<std::string,JSON>>( internal.Map.get() );
|
||||
return JSONWrapper<QuickFlatMap>( internal.Map.get() );
|
||||
} else {
|
||||
return JSONWrapper<std::map<std::string,JSON>>( nullptr );
|
||||
return JSONWrapper<QuickFlatMap>( nullptr );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -290,11 +363,11 @@ class JSON
|
||||
}
|
||||
}
|
||||
|
||||
JSONConstWrapper<std::map<std::string,JSON>> object_range() const {
|
||||
JSONConstWrapper<QuickFlatMap> object_range() const {
|
||||
if( internal.Type == Class::Object ) {
|
||||
return JSONConstWrapper<std::map<std::string,JSON>>( internal.Map.get() );
|
||||
return JSONConstWrapper<QuickFlatMap>( internal.Map.get() );
|
||||
} else {
|
||||
return JSONConstWrapper<std::map<std::string,JSON>>( nullptr );
|
||||
return JSONConstWrapper<QuickFlatMap>( nullptr );
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -12,9 +12,8 @@
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "../chaiscript.hpp"
|
||||
#include "../dispatchkit/proxy_functions.hpp"
|
||||
#include "../dispatchkit/type_info.hpp"
|
||||
#include "../language/chaiscript_common.hpp"
|
||||
#include "../dispatchkit/register_function.hpp"
|
||||
#include "../dispatchkit/operators.hpp"
|
||||
|
||||
|
||||
|
@@ -43,10 +43,9 @@ languages:
|
||||
Requirements
|
||||
============
|
||||
|
||||
ChaiScript requires a C++11 compiler to build with support for variadic
|
||||
templates. It has been tested with gcc 4.6 and clang 3.1 (with libcxx). MacOS
|
||||
10.8 (Mountain Lion) is also known to support the C++11 build with Apple's
|
||||
clang 4.0. MSVC 2013 or newer is supports also. For more information see the build
|
||||
ChaiScript requires a C++14 compiler to build with support for variadic
|
||||
templates. It has been tested with gcc 4.9 and clang 3.6 (with libcxx).
|
||||
For more information see the build
|
||||
[dashboard](http://chaiscript.com/ChaiScript-BuildResults/index.html).
|
||||
|
||||
Usage
|
||||
|
@@ -1,6 +1,57 @@
|
||||
Notes:
|
||||
=======
|
||||
Current Version: 5.8.2
|
||||
Current Version: 6.0.0
|
||||
|
||||
### Changes since 5.8.6
|
||||
|
||||
*6.0.0 is a massive rework compared to 5.x. It now requires a C++14 enabled compiler*
|
||||
|
||||
#### Compiler Requirements
|
||||
|
||||
* MSVC 2015 or greater
|
||||
* g++ 4.9 or greater
|
||||
* clang 3.6 or greater
|
||||
|
||||
#### Breaking Changes
|
||||
|
||||
* Instantiating a ChaiScript object now, by default, builds the stdlib in
|
||||
* This was done to address the most common support issues of loading stdlib dynamically at runtime
|
||||
* If you want the old behavior, use include/chaiscript/chaiscript_basic.hpp
|
||||
* Headers have been reorganized to fully separate stdlib/parser/engine from each other (some faster builds)
|
||||
* Bootstrap functions no longer return a reference to the module added to (compile time savings)
|
||||
* It's now no longer possible modify AST_Nodes (compile time, runtime efficiency)
|
||||
* Function annotations no longer exist (simplifies code, reduces compile time, compile size)
|
||||
|
||||
#### New Features Added
|
||||
|
||||
* Modular optimization system; this can be accessed via the ChaiScript_Basic interface
|
||||
* Execution tracing capability; also accessed via ChaiScript_Basic interface
|
||||
* range-based for loops `for( id : container ) { }`
|
||||
|
||||
#### Improvements
|
||||
|
||||
* Compile time improvements
|
||||
* Compile size improvements
|
||||
* Significant runtime improvements (see "Modular optimization system")
|
||||
|
||||
#### Improvements Still Need To Be Made
|
||||
|
||||
* File location tracking has been rewritten; this currently means error location reporting is not as good as it was
|
||||
* Tracing capability needs to be tested and vetted
|
||||
|
||||
### Changes since 5.8.5
|
||||
* Optimize away `return` statements in lambdas also
|
||||
|
||||
### Changes since 5.8.4
|
||||
* Fix order of operations for prefix operators
|
||||
* Make sure atomics are initialized properly
|
||||
* Remove parsing of unused prefix `&` operator
|
||||
|
||||
### Changes since 5.8.3
|
||||
* Fix case with some numeric conversions mixed with numerics that do not need conversion
|
||||
|
||||
### Changes since 5.8.2
|
||||
* Add support for reference of pointer return types
|
||||
|
||||
### Changes since 5.8.1
|
||||
* Allow casting to non-const & std::shared_ptr<T>
|
||||
|
@@ -73,7 +73,7 @@ int main(int /*argc*/, char * /*argv*/[]) {
|
||||
|
||||
//Create a new system object and share it with the chaiscript engine
|
||||
System system;
|
||||
chai.add(var(&system), "system");
|
||||
chai.add_global(var(&system), "system");
|
||||
|
||||
//Add a bound callback method
|
||||
chai.add(fun(&System::add_callback, std::ref(system)), "add_callback_bound");
|
||||
|
@@ -1,5 +1,4 @@
|
||||
#include <chaiscript/chaiscript.hpp>
|
||||
#include <chaiscript/chaiscript_stdlib.hpp>
|
||||
|
||||
class Entity
|
||||
{
|
||||
@@ -57,7 +56,7 @@ class Factory
|
||||
|
||||
int main()
|
||||
{
|
||||
chaiscript::ChaiScript chai(chaiscript::Std_Lib::library());
|
||||
chaiscript::ChaiScript chai;
|
||||
|
||||
chai.add(chaiscript::fun(&Entity::width), "width");
|
||||
chai.add(chaiscript::fun(&Entity::height), "height");
|
||||
|
@@ -13,7 +13,6 @@
|
||||
#endif
|
||||
|
||||
#include <chaiscript/chaiscript.hpp>
|
||||
#include <chaiscript/chaiscript_stdlib.hpp>
|
||||
|
||||
#ifdef READLINE_AVAILABLE
|
||||
#include <readline/readline.h>
|
||||
@@ -291,7 +290,7 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
|
||||
//chaiscript::ChaiScript chai(modulepaths, usepaths);
|
||||
chaiscript::ChaiScript chai(chaiscript::Std_Lib::library(), usepaths);
|
||||
chaiscript::ChaiScript chai(usepaths);
|
||||
|
||||
chai.add(chaiscript::fun(&myexit), "exit");
|
||||
chai.add(chaiscript::fun(&myexit), "quit");
|
||||
|
@@ -1,5 +1,4 @@
|
||||
#include <chaiscript/chaiscript.hpp>
|
||||
#include <chaiscript/chaiscript_stdlib.hpp>
|
||||
|
||||
class BaseClass
|
||||
{
|
||||
@@ -70,7 +69,7 @@ class ChaiScriptDerived : public BaseClass
|
||||
|
||||
int main()
|
||||
{
|
||||
chaiscript::ChaiScript chai(chaiscript::Std_Lib::library());
|
||||
chaiscript::ChaiScript chai;
|
||||
chai.add(chaiscript::fun(&BaseClass::doSomething), "doSomething");
|
||||
chai.add(chaiscript::fun(&BaseClass::setValue), "setValue");
|
||||
chai.add(chaiscript::fun(&BaseClass::getValue), "getValue");
|
||||
|
@@ -1,7 +1,6 @@
|
||||
#include <iostream>
|
||||
|
||||
#include <chaiscript/chaiscript.hpp>
|
||||
#include <chaiscript/chaiscript_stdlib.hpp>
|
||||
|
||||
#ifdef READLINE_AVAILABLE
|
||||
#include <readline/readline.h>
|
||||
@@ -32,16 +31,9 @@ void function(void)
|
||||
class test
|
||||
{
|
||||
chaiscript::ChaiScript chai;
|
||||
chaiscript::ChaiScript::State backupState;
|
||||
chaiscript::ChaiScript::State backupState = chai.get_state();
|
||||
|
||||
public:
|
||||
test()
|
||||
: chai(chaiscript::Std_Lib::library())
|
||||
{
|
||||
backupState = chai.get_state();
|
||||
}
|
||||
~test(){}
|
||||
|
||||
void ResetState()
|
||||
{
|
||||
chai.set_state(backupState);
|
||||
|
@@ -1,11 +1,10 @@
|
||||
#include <chaiscript/chaiscript.hpp>
|
||||
#include <chaiscript/chaiscript_stdlib.hpp>
|
||||
#include <chaiscript/dispatchkit/bootstrap_stl.hpp>
|
||||
#include <chaiscript/dispatchkit/function_call.hpp>
|
||||
|
||||
int main( int /*argc*/ , char * /*argv*/[] )
|
||||
{
|
||||
chaiscript::ChaiScript ch( chaiscript::Std_Lib::library( ) );
|
||||
chaiscript::ChaiScript ch;
|
||||
|
||||
|
||||
try
|
||||
|
11
src/main.cpp
11
src/main.cpp
@@ -12,7 +12,10 @@
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
#endif
|
||||
|
||||
#include <chaiscript/chaiscript.hpp>
|
||||
#include <chaiscript/chaiscript_basic.hpp>
|
||||
#include "../static_libs/chaiscript_parser.hpp"
|
||||
#include "../static_libs/chaiscript_stdlib.hpp"
|
||||
|
||||
|
||||
#ifdef READLINE_AVAILABLE
|
||||
#include <readline/readline.h>
|
||||
@@ -125,7 +128,7 @@ std::vector<std::string> default_search_paths()
|
||||
size_t secondtolastslash = exepath.rfind('/', lastslash - 1);
|
||||
if (lastslash != std::string::npos)
|
||||
{
|
||||
paths.push_back(exepath.substr(0, lastslash));
|
||||
paths.push_back(exepath.substr(0, lastslash+1));
|
||||
}
|
||||
|
||||
if (secondtolastslash != std::string::npos)
|
||||
@@ -217,7 +220,7 @@ void myexit(int return_val) {
|
||||
exit(return_val);
|
||||
}
|
||||
|
||||
void interactive(chaiscript::ChaiScript& chai)
|
||||
void interactive(chaiscript::ChaiScript_Basic& chai)
|
||||
{
|
||||
using_history();
|
||||
|
||||
@@ -288,7 +291,7 @@ int main(int argc, char *argv[])
|
||||
modulepaths.push_back(modulepath);
|
||||
}
|
||||
|
||||
chaiscript::ChaiScript chai(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");
|
||||
|
@@ -4,7 +4,7 @@
|
||||
// Copyright 2009-2016, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#include <chaiscript/chaiscript.hpp>
|
||||
#include <chaiscript/chaiscript_basic.hpp>
|
||||
#include <chaiscript/dispatchkit/bootstrap_stl.hpp>
|
||||
#include <list>
|
||||
#include <string>
|
||||
|
@@ -1,5 +1,5 @@
|
||||
|
||||
#include <chaiscript/chaiscript.hpp>
|
||||
#include <chaiscript/chaiscript_basic.hpp>
|
||||
#include <chaiscript/dispatchkit/bootstrap.hpp>
|
||||
#include <string>
|
||||
|
||||
|
8
static_libs/chaiscript_parser.cpp
Normal file
8
static_libs/chaiscript_parser.cpp
Normal file
@@ -0,0 +1,8 @@
|
||||
#include "../include/chaiscript/language/chaiscript_parser.hpp"
|
||||
#include "chaiscript_parser.hpp"
|
||||
|
||||
std::unique_ptr<chaiscript::parser::ChaiScript_Parser_Base> create_chaiscript_parser()
|
||||
{
|
||||
return std::make_unique<chaiscript::parser::ChaiScript_Parser<chaiscript::eval::Noop_Tracer, chaiscript::optimizer::Optimizer_Default>>();
|
||||
}
|
||||
|
13
static_libs/chaiscript_parser.hpp
Normal file
13
static_libs/chaiscript_parser.hpp
Normal file
@@ -0,0 +1,13 @@
|
||||
|
||||
#ifndef CHAISCRIPT_PARSER_LIB
|
||||
#define CHAISCRIPT_PARSER_LIB
|
||||
|
||||
namespace chaiscript {
|
||||
namespace parser {
|
||||
class ChaiScript_Parser_Base;
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<chaiscript::parser::ChaiScript_Parser_Base> create_chaiscript_parser();
|
||||
|
||||
#endif
|
8
static_libs/chaiscript_stdlib.cpp
Normal file
8
static_libs/chaiscript_stdlib.cpp
Normal file
@@ -0,0 +1,8 @@
|
||||
#include "../include/chaiscript/chaiscript_stdlib.hpp"
|
||||
#include "chaiscript_stdlib.hpp"
|
||||
|
||||
std::shared_ptr<chaiscript::Module> create_chaiscript_stdlib()
|
||||
{
|
||||
return chaiscript::Std_Lib::library();
|
||||
}
|
||||
|
11
static_libs/chaiscript_stdlib.hpp
Normal file
11
static_libs/chaiscript_stdlib.hpp
Normal file
@@ -0,0 +1,11 @@
|
||||
|
||||
#ifndef CHAISCRIPT_STDLIB
|
||||
#define CHAISCRIPT_STDLIB
|
||||
|
||||
namespace chaiscript {
|
||||
class Module;
|
||||
}
|
||||
|
||||
std::shared_ptr<chaiscript::Module> create_chaiscript_stdlib();
|
||||
|
||||
#endif
|
@@ -1,7 +1,6 @@
|
||||
assert_equal(`==`, `==`);
|
||||
assert_not_equal(`==`, `<`);
|
||||
assert_equal(`<`.get_arity(), 2);
|
||||
assert_equal(`+`.get_annotation(), "Multiple method dispatch function wrapper.");
|
||||
assert_equal(get_arity.get_contained_functions().size(), 0);
|
||||
assert_equal(get_arity.get_arity(), 1);
|
||||
assert_equal(get_arity.get_param_types().size(), 2);
|
||||
|
@@ -35,4 +35,4 @@ def while_doing()
|
||||
|
||||
var f = fun() { while_doing(); }
|
||||
|
||||
assert_equal(get_eval_error(f).call_stack.size(), 16)
|
||||
assert_true(get_eval_error(f).call_stack.size() <= 16)
|
||||
|
@@ -10,7 +10,6 @@ def test_function(a)
|
||||
|
||||
// test_function tests
|
||||
assert_equal(test_function.get_arity(), 1);
|
||||
assert_equal(trim(test_function.get_annotation()), "#Test Function Description");
|
||||
assert_equal(test_function.get_contained_functions().size(), 0);
|
||||
assert_equal(test_function.get_param_types().size(), 2);
|
||||
|
||||
|
@@ -1,36 +0,0 @@
|
||||
var parser := ChaiScript_Parser()
|
||||
var parse_success = parser.parse("3 + 4", "INPUT")
|
||||
var a := parser.ast()
|
||||
|
||||
assert_equal(eval(a), 7)
|
||||
|
||||
var childs := a.children.front().children
|
||||
var node := childs[0]
|
||||
|
||||
var parser2 := ChaiScript_Parser()
|
||||
parser2.parse("9", "INPUT")
|
||||
|
||||
|
||||
a.children.front().replace_child(childs[0], parser2.ast())
|
||||
|
||||
assert_equal(eval(a), 13)
|
||||
assert_equal(node.filename, "INPUT")
|
||||
|
||||
|
||||
|
||||
def my_fun()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
assert_equal(true, my_fun.has_parse_tree());
|
||||
assert_equal(false, `+`.has_parse_tree());
|
||||
|
||||
assert_throws("Function does not have a parse tree", fun() { `+`.get_parse_tree(); } );
|
||||
|
||||
var parsetree := my_fun.get_parse_tree();
|
||||
|
||||
assert_equal(1, eval(parsetree));
|
||||
|
||||
print(parsetree.text());
|
@@ -1,4 +1,6 @@
|
||||
#include <chaiscript/chaiscript.hpp>
|
||||
#include <chaiscript/chaiscript_basic.hpp>
|
||||
#include "../static_libs/chaiscript_parser.hpp"
|
||||
#include "../static_libs/chaiscript_stdlib.hpp"
|
||||
|
||||
|
||||
extern "C"
|
||||
@@ -11,8 +13,7 @@ extern "C"
|
||||
|
||||
int main()
|
||||
{
|
||||
|
||||
chaiscript::ChaiScript chai;
|
||||
chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser());
|
||||
chai.add(chaiscript::fun(&do_something), "do_something");
|
||||
|
||||
return chai.eval<int>("do_something(101)") == 101 % 2?EXIT_SUCCESS:EXIT_FAILURE;
|
||||
|
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Catch v1.3.5
|
||||
* Generated: 2016-02-29 08:16:42.342094
|
||||
* Catch v1.5.7
|
||||
* Generated: 2016-09-27 10:45:46.824849
|
||||
* ----------------------------------------------------------
|
||||
* This file has been merged from multiple headers. Please don't edit it directly
|
||||
* Copyright (c) 2012 Two Blue Cubes Ltd. All rights reserved.
|
||||
@@ -62,7 +62,11 @@
|
||||
|
||||
#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( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __LINE__ )
|
||||
#ifdef CATCH_CONFIG_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__ )
|
||||
#endif
|
||||
|
||||
#define INTERNAL_CATCH_STRINGIFY2( expr ) #expr
|
||||
#define INTERNAL_CATCH_STRINGIFY( expr ) INTERNAL_CATCH_STRINGIFY2( expr )
|
||||
@@ -89,7 +93,7 @@
|
||||
// CATCH_CONFIG_CPP11_OR_GREATER : Is C++11 supported?
|
||||
|
||||
// CATCH_CONFIG_VARIADIC_MACROS : are variadic macros supported?
|
||||
|
||||
// CATCH_CONFIG_COUNTER : is the __COUNTER__ macro supported?
|
||||
// ****************
|
||||
// Note to maintainers: if new toggles are added please document them
|
||||
// in configuration.md, too
|
||||
@@ -102,8 +106,16 @@
|
||||
|
||||
// All the C++11 features can be disabled with CATCH_CONFIG_NO_CPP11
|
||||
|
||||
#if defined(__cplusplus) && __cplusplus >= 201103L
|
||||
# define CATCH_CPP11_OR_GREATER
|
||||
#ifdef __cplusplus
|
||||
|
||||
# if __cplusplus >= 201103L
|
||||
# define CATCH_CPP11_OR_GREATER
|
||||
# endif
|
||||
|
||||
# if __cplusplus >= 201402L
|
||||
# define CATCH_CPP14_OR_GREATER
|
||||
# endif
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __clang__
|
||||
@@ -185,6 +197,15 @@
|
||||
|
||||
#endif
|
||||
|
||||
// Use __COUNTER__ if the compiler supports it
|
||||
#if ( defined _MSC_VER && _MSC_VER >= 1300 ) || \
|
||||
( defined __GNUC__ && __GNUC__ >= 4 && __GNUC_MINOR__ >= 3 ) || \
|
||||
( defined __clang__ && __clang_major__ >= 3 )
|
||||
|
||||
#define CATCH_INTERNAL_CONFIG_COUNTER
|
||||
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// C++ language feature support
|
||||
|
||||
@@ -256,6 +277,9 @@
|
||||
#if defined(CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR) && !defined(CATCH_CONFIG_NO_UNIQUE_PTR) && !defined(CATCH_CONFIG_CPP11_UNIQUE_PTR) && !defined(CATCH_CONFIG_NO_CPP11)
|
||||
# define CATCH_CONFIG_CPP11_UNIQUE_PTR
|
||||
#endif
|
||||
#if defined(CATCH_INTERNAL_CONFIG_COUNTER) && !defined(CATCH_CONFIG_NO_COUNTER) && !defined(CATCH_CONFIG_COUNTER)
|
||||
# define CATCH_CONFIG_COUNTER
|
||||
#endif
|
||||
|
||||
#if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS)
|
||||
# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS
|
||||
@@ -686,24 +710,28 @@ void registerTestCaseFunction
|
||||
|
||||
#ifdef CATCH_CONFIG_VARIADIC_MACROS
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#define INTERNAL_CATCH_TESTCASE2( TestName, ... ) \
|
||||
static void TestName(); \
|
||||
namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &TestName, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( __VA_ARGS__ ) ); }\
|
||||
static void TestName()
|
||||
#define INTERNAL_CATCH_TESTCASE( ... ) \
|
||||
static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )(); \
|
||||
namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( __VA_ARGS__ ) ); }\
|
||||
static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )()
|
||||
INTERNAL_CATCH_TESTCASE2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), __VA_ARGS__ )
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, ... ) \
|
||||
namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); }
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, ... )\
|
||||
#define INTERNAL_CATCH_TEST_CASE_METHOD2( TestName, ClassName, ... )\
|
||||
namespace{ \
|
||||
struct INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ) : ClassName{ \
|
||||
struct TestName : ClassName{ \
|
||||
void test(); \
|
||||
}; \
|
||||
Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test, #ClassName, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); \
|
||||
Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &TestName::test, #ClassName, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); \
|
||||
} \
|
||||
void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test()
|
||||
void TestName::test()
|
||||
#define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, ... ) \
|
||||
INTERNAL_CATCH_TEST_CASE_METHOD2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), ClassName, __VA_ARGS__ )
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#define INTERNAL_CATCH_REGISTER_TESTCASE( Function, ... ) \
|
||||
@@ -711,24 +739,28 @@ void registerTestCaseFunction
|
||||
|
||||
#else
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#define INTERNAL_CATCH_TESTCASE2( TestName, Name, Desc ) \
|
||||
static void TestName(); \
|
||||
namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &TestName, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( Name, Desc ) ); }\
|
||||
static void TestName()
|
||||
#define INTERNAL_CATCH_TESTCASE( Name, Desc ) \
|
||||
static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )(); \
|
||||
namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( Name, Desc ) ); }\
|
||||
static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )()
|
||||
INTERNAL_CATCH_TESTCASE2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), Name, Desc )
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, Name, Desc ) \
|
||||
namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc( Name, Desc ), CATCH_INTERNAL_LINEINFO ); }
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, TestName, Desc )\
|
||||
#define INTERNAL_CATCH_TEST_CASE_METHOD2( TestCaseName, ClassName, TestName, Desc )\
|
||||
namespace{ \
|
||||
struct INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ) : ClassName{ \
|
||||
struct TestCaseName : ClassName{ \
|
||||
void test(); \
|
||||
}; \
|
||||
Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test, #ClassName, Catch::NameAndDesc( TestName, Desc ), CATCH_INTERNAL_LINEINFO ); \
|
||||
Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &TestCaseName::test, #ClassName, Catch::NameAndDesc( TestName, Desc ), CATCH_INTERNAL_LINEINFO ); \
|
||||
} \
|
||||
void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test()
|
||||
void TestCaseName::test()
|
||||
#define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, TestName, Desc )\
|
||||
INTERNAL_CATCH_TEST_CASE_METHOD2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), ClassName, TestName, Desc )
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#define INTERNAL_CATCH_REGISTER_TESTCASE( Function, Name, Desc ) \
|
||||
@@ -2041,7 +2073,7 @@ namespace Catch {
|
||||
__catchResult.useActiveException( Catch::ResultDisposition::Normal ); \
|
||||
} \
|
||||
INTERNAL_CATCH_REACT( __catchResult ) \
|
||||
} while( Catch::isTrue( false && static_cast<bool>(expr) ) ) // expr here is never evaluated at runtime but it forces the compiler to give it a look
|
||||
} while( Catch::isTrue( false && !!(expr) ) ) // expr here is never evaluated at runtime but it forces the compiler to give it a look
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#define INTERNAL_CATCH_IF( expr, resultDisposition, macroName ) \
|
||||
@@ -2578,10 +2610,12 @@ namespace Catch {
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#define INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) \
|
||||
static std::string INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator )( signature ); \
|
||||
namespace{ Catch::ExceptionTranslatorRegistrar INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionRegistrar )( &INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ) ); }\
|
||||
static std::string INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator )( signature )
|
||||
#define INTERNAL_CATCH_TRANSLATE_EXCEPTION2( translatorName, signature ) \
|
||||
static std::string translatorName( signature ); \
|
||||
namespace{ Catch::ExceptionTranslatorRegistrar INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionRegistrar )( &translatorName ); }\
|
||||
static std::string translatorName( signature )
|
||||
|
||||
#define INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION2( INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ), signature )
|
||||
|
||||
// #included from: internal/catch_approx.hpp
|
||||
#define TWOBLUECUBES_CATCH_APPROX_HPP_INCLUDED
|
||||
@@ -3189,10 +3223,11 @@ namespace Catch {
|
||||
|
||||
bool matches( TestCaseInfo const& testCase ) const {
|
||||
// All patterns in a filter must match for the filter to be a match
|
||||
for( std::vector<Ptr<Pattern> >::const_iterator it = m_patterns.begin(), itEnd = m_patterns.end(); it != itEnd; ++it )
|
||||
for( std::vector<Ptr<Pattern> >::const_iterator it = m_patterns.begin(), itEnd = m_patterns.end(); it != itEnd; ++it ) {
|
||||
if( !(*it)->matches( testCase ) )
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -3424,7 +3459,7 @@ namespace Catch {
|
||||
};
|
||||
|
||||
class DebugOutStream : public IStream {
|
||||
std::auto_ptr<StreamBufBase> m_streamBuf;
|
||||
CATCH_AUTO_PTR( StreamBufBase ) m_streamBuf;
|
||||
mutable std::ostream m_os;
|
||||
public:
|
||||
DebugOutStream();
|
||||
@@ -3572,7 +3607,7 @@ namespace Catch {
|
||||
}
|
||||
ConfigData m_data;
|
||||
|
||||
std::auto_ptr<IStream const> m_stream;
|
||||
CATCH_AUTO_PTR( IStream const ) m_stream;
|
||||
TestSpec m_testSpec;
|
||||
};
|
||||
|
||||
@@ -3592,7 +3627,7 @@ namespace Catch {
|
||||
#define STITCH_CLARA_OPEN_NAMESPACE namespace Catch {
|
||||
// #included from: ../external/clara.h
|
||||
|
||||
// Version 0.0.1.1
|
||||
// Version 0.0.2.4
|
||||
|
||||
// Only use header guard if we are not using an outer namespace
|
||||
#if !defined(TWOBLUECUBES_CLARA_H_INCLUDED) || defined(STITCH_CLARA_OPEN_NAMESPACE)
|
||||
@@ -3908,6 +3943,10 @@ namespace Tbc {
|
||||
#include <stdexcept>
|
||||
#include <memory>
|
||||
|
||||
#if defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER)
|
||||
#define CLARA_PLATFORM_WINDOWS
|
||||
#endif
|
||||
|
||||
// Use optional outer namespace
|
||||
#ifdef STITCH_CLARA_OPEN_NAMESPACE
|
||||
STITCH_CLARA_OPEN_NAMESPACE
|
||||
@@ -3931,9 +3970,6 @@ namespace Clara {
|
||||
const unsigned int consoleWidth = 80;
|
||||
#endif
|
||||
|
||||
// Use this to try and stop compiler from warning about unreachable code
|
||||
inline bool isTrue( bool value ) { return value; }
|
||||
|
||||
using namespace Tbc;
|
||||
|
||||
inline bool startsWith( std::string const& str, std::string const& prefix ) {
|
||||
@@ -3969,14 +4005,6 @@ namespace Clara {
|
||||
else
|
||||
throw std::runtime_error( "Expected a boolean value but did not recognise:\n '" + _source + "'" );
|
||||
}
|
||||
inline void convertInto( bool _source, bool& _dest ) {
|
||||
_dest = _source;
|
||||
}
|
||||
template<typename T>
|
||||
inline void convertInto( bool, T& ) {
|
||||
if( isTrue( true ) )
|
||||
throw std::runtime_error( "Invalid conversion" );
|
||||
}
|
||||
|
||||
template<typename ConfigT>
|
||||
struct IArgFunction {
|
||||
@@ -3986,7 +4014,6 @@ namespace Clara {
|
||||
IArgFunction( IArgFunction const& ) = default;
|
||||
#endif
|
||||
virtual void set( ConfigT& config, std::string const& value ) const = 0;
|
||||
virtual void setFlag( ConfigT& config ) const = 0;
|
||||
virtual bool takesArg() const = 0;
|
||||
virtual IArgFunction* clone() const = 0;
|
||||
};
|
||||
@@ -4008,9 +4035,6 @@ namespace Clara {
|
||||
void set( ConfigT& config, std::string const& value ) const {
|
||||
functionObj->set( config, value );
|
||||
}
|
||||
void setFlag( ConfigT& config ) const {
|
||||
functionObj->setFlag( config );
|
||||
}
|
||||
bool takesArg() const { return functionObj->takesArg(); }
|
||||
|
||||
bool isSet() const {
|
||||
@@ -4023,7 +4047,6 @@ namespace Clara {
|
||||
template<typename C>
|
||||
struct NullBinder : IArgFunction<C>{
|
||||
virtual void set( C&, std::string const& ) const {}
|
||||
virtual void setFlag( C& ) const {}
|
||||
virtual bool takesArg() const { return true; }
|
||||
virtual IArgFunction<C>* clone() const { return new NullBinder( *this ); }
|
||||
};
|
||||
@@ -4034,9 +4057,6 @@ namespace Clara {
|
||||
virtual void set( C& p, std::string const& stringValue ) const {
|
||||
convertInto( stringValue, p.*member );
|
||||
}
|
||||
virtual void setFlag( C& p ) const {
|
||||
convertInto( true, p.*member );
|
||||
}
|
||||
virtual bool takesArg() const { return !IsBool<M>::value; }
|
||||
virtual IArgFunction<C>* clone() const { return new BoundDataMember( *this ); }
|
||||
M C::* member;
|
||||
@@ -4049,11 +4069,6 @@ namespace Clara {
|
||||
convertInto( stringValue, value );
|
||||
(p.*member)( value );
|
||||
}
|
||||
virtual void setFlag( C& p ) const {
|
||||
typename RemoveConstRef<M>::type value;
|
||||
convertInto( true, value );
|
||||
(p.*member)( value );
|
||||
}
|
||||
virtual bool takesArg() const { return !IsBool<M>::value; }
|
||||
virtual IArgFunction<C>* clone() const { return new BoundUnaryMethod( *this ); }
|
||||
void (C::*member)( M );
|
||||
@@ -4067,9 +4082,6 @@ namespace Clara {
|
||||
if( value )
|
||||
(p.*member)();
|
||||
}
|
||||
virtual void setFlag( C& p ) const {
|
||||
(p.*member)();
|
||||
}
|
||||
virtual bool takesArg() const { return false; }
|
||||
virtual IArgFunction<C>* clone() const { return new BoundNullaryMethod( *this ); }
|
||||
void (C::*member)();
|
||||
@@ -4084,9 +4096,6 @@ namespace Clara {
|
||||
if( value )
|
||||
function( obj );
|
||||
}
|
||||
virtual void setFlag( C& p ) const {
|
||||
function( p );
|
||||
}
|
||||
virtual bool takesArg() const { return false; }
|
||||
virtual IArgFunction<C>* clone() const { return new BoundUnaryFunction( *this ); }
|
||||
void (*function)( C& );
|
||||
@@ -4100,11 +4109,6 @@ namespace Clara {
|
||||
convertInto( stringValue, value );
|
||||
function( obj, value );
|
||||
}
|
||||
virtual void setFlag( C& obj ) const {
|
||||
typename RemoveConstRef<T>::type value;
|
||||
convertInto( true, value );
|
||||
function( obj, value );
|
||||
}
|
||||
virtual bool takesArg() const { return !IsBool<T>::value; }
|
||||
virtual IArgFunction<C>* clone() const { return new BoundBinaryFunction( *this ); }
|
||||
void (*function)( C&, T );
|
||||
@@ -4112,8 +4116,20 @@ namespace Clara {
|
||||
|
||||
} // namespace Detail
|
||||
|
||||
struct Parser {
|
||||
Parser() : separators( " \t=:" ) {}
|
||||
inline std::vector<std::string> argsToVector( int argc, char const* const* const argv ) {
|
||||
std::vector<std::string> args( static_cast<std::size_t>( argc ) );
|
||||
for( std::size_t i = 0; i < static_cast<std::size_t>( argc ); ++i )
|
||||
args[i] = argv[i];
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
class Parser {
|
||||
enum Mode { None, MaybeShortOpt, SlashOpt, ShortOpt, LongOpt, Positional };
|
||||
Mode mode;
|
||||
std::size_t from;
|
||||
bool inQuotes;
|
||||
public:
|
||||
|
||||
struct Token {
|
||||
enum Type { Positional, ShortOpt, LongOpt };
|
||||
@@ -4122,38 +4138,75 @@ namespace Clara {
|
||||
std::string data;
|
||||
};
|
||||
|
||||
void parseIntoTokens( int argc, char const* const argv[], std::vector<Parser::Token>& tokens ) const {
|
||||
Parser() : mode( None ), from( 0 ), inQuotes( false ){}
|
||||
|
||||
void parseIntoTokens( std::vector<std::string> const& args, std::vector<Token>& tokens ) {
|
||||
const std::string doubleDash = "--";
|
||||
for( int i = 1; i < argc && argv[i] != doubleDash; ++i )
|
||||
parseIntoTokens( argv[i] , tokens);
|
||||
for( std::size_t i = 1; i < args.size() && args[i] != doubleDash; ++i )
|
||||
parseIntoTokens( args[i], tokens);
|
||||
}
|
||||
void parseIntoTokens( std::string arg, std::vector<Parser::Token>& tokens ) const {
|
||||
while( !arg.empty() ) {
|
||||
Parser::Token token( Parser::Token::Positional, arg );
|
||||
arg = "";
|
||||
if( token.data[0] == '-' ) {
|
||||
if( token.data.size() > 1 && token.data[1] == '-' ) {
|
||||
token = Parser::Token( Parser::Token::LongOpt, token.data.substr( 2 ) );
|
||||
}
|
||||
else {
|
||||
token = Parser::Token( Parser::Token::ShortOpt, token.data.substr( 1 ) );
|
||||
if( token.data.size() > 1 && separators.find( token.data[1] ) == std::string::npos ) {
|
||||
arg = "-" + token.data.substr( 1 );
|
||||
token.data = token.data.substr( 0, 1 );
|
||||
}
|
||||
}
|
||||
}
|
||||
if( token.type != Parser::Token::Positional ) {
|
||||
std::size_t pos = token.data.find_first_of( separators );
|
||||
if( pos != std::string::npos ) {
|
||||
arg = token.data.substr( pos+1 );
|
||||
token.data = token.data.substr( 0, pos );
|
||||
}
|
||||
}
|
||||
tokens.push_back( token );
|
||||
|
||||
void parseIntoTokens( std::string const& arg, std::vector<Token>& tokens ) {
|
||||
for( std::size_t i = 0; i <= arg.size(); ++i ) {
|
||||
char c = arg[i];
|
||||
if( c == '"' )
|
||||
inQuotes = !inQuotes;
|
||||
mode = handleMode( i, c, arg, tokens );
|
||||
}
|
||||
}
|
||||
std::string separators;
|
||||
Mode handleMode( std::size_t i, char c, std::string const& arg, std::vector<Token>& tokens ) {
|
||||
switch( mode ) {
|
||||
case None: return handleNone( i, c );
|
||||
case MaybeShortOpt: return handleMaybeShortOpt( i, c );
|
||||
case ShortOpt:
|
||||
case LongOpt:
|
||||
case SlashOpt: return handleOpt( i, c, arg, tokens );
|
||||
case Positional: return handlePositional( i, c, arg, tokens );
|
||||
default: throw std::logic_error( "Unknown mode" );
|
||||
}
|
||||
}
|
||||
|
||||
Mode handleNone( std::size_t i, char c ) {
|
||||
if( inQuotes ) {
|
||||
from = i;
|
||||
return Positional;
|
||||
}
|
||||
switch( c ) {
|
||||
case '-': return MaybeShortOpt;
|
||||
#ifdef CLARA_PLATFORM_WINDOWS
|
||||
case '/': from = i+1; return SlashOpt;
|
||||
#endif
|
||||
default: from = i; return Positional;
|
||||
}
|
||||
}
|
||||
Mode handleMaybeShortOpt( std::size_t i, char c ) {
|
||||
switch( c ) {
|
||||
case '-': from = i+1; return LongOpt;
|
||||
default: from = i; return ShortOpt;
|
||||
}
|
||||
}
|
||||
Mode handleOpt( std::size_t i, char c, std::string const& arg, std::vector<Token>& tokens ) {
|
||||
if( std::string( ":=\0", 3 ).find( c ) == std::string::npos )
|
||||
return mode;
|
||||
|
||||
std::string optName = arg.substr( from, i-from );
|
||||
if( mode == ShortOpt )
|
||||
for( std::size_t j = 0; j < optName.size(); ++j )
|
||||
tokens.push_back( Token( Token::ShortOpt, optName.substr( j, 1 ) ) );
|
||||
else if( mode == SlashOpt && optName.size() == 1 )
|
||||
tokens.push_back( Token( Token::ShortOpt, optName ) );
|
||||
else
|
||||
tokens.push_back( Token( Token::LongOpt, optName ) );
|
||||
return None;
|
||||
}
|
||||
Mode handlePositional( std::size_t i, char c, std::string const& arg, std::vector<Token>& tokens ) {
|
||||
if( inQuotes || std::string( "\0", 1 ).find( c ) == std::string::npos )
|
||||
return mode;
|
||||
|
||||
std::string data = arg.substr( from, i-from );
|
||||
tokens.push_back( Token( Token::Positional, data ) );
|
||||
return None;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename ConfigT>
|
||||
@@ -4456,21 +4509,21 @@ namespace Clara {
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
ConfigT parse( int argc, char const* const argv[] ) const {
|
||||
ConfigT parse( std::vector<std::string> const& args ) const {
|
||||
ConfigT config;
|
||||
parseInto( argc, argv, config );
|
||||
parseInto( args, config );
|
||||
return config;
|
||||
}
|
||||
|
||||
std::vector<Parser::Token> parseInto( int argc, char const* argv[], ConfigT& config ) const {
|
||||
std::string processName = argv[0];
|
||||
std::vector<Parser::Token> parseInto( std::vector<std::string> const& args, ConfigT& config ) const {
|
||||
std::string processName = args[0];
|
||||
std::size_t lastSlash = processName.find_last_of( "/\\" );
|
||||
if( lastSlash != std::string::npos )
|
||||
processName = processName.substr( lastSlash+1 );
|
||||
m_boundProcessName.set( config, processName );
|
||||
std::vector<Parser::Token> tokens;
|
||||
Parser parser;
|
||||
parser.parseIntoTokens( argc, argv, tokens );
|
||||
parser.parseIntoTokens( args, tokens );
|
||||
return populate( tokens, config );
|
||||
}
|
||||
|
||||
@@ -4501,7 +4554,7 @@ namespace Clara {
|
||||
arg.boundField.set( config, tokens[++i].data );
|
||||
}
|
||||
else {
|
||||
arg.boundField.setFlag( config );
|
||||
arg.boundField.set( config, "true" );
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -4667,8 +4720,11 @@ namespace Catch {
|
||||
std::string line;
|
||||
while( std::getline( f, line ) ) {
|
||||
line = trim(line);
|
||||
if( !line.empty() && !startsWith( line, "#" ) )
|
||||
addTestOrTags( config, "\"" + line + "\"," );
|
||||
if( !line.empty() && !startsWith( line, "#" ) ) {
|
||||
if( !startsWith( line, "\"" ) )
|
||||
line = "\"" + line + "\"";
|
||||
addTestOrTags( config, line + "," );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5209,6 +5265,8 @@ namespace Catch
|
||||
bool aborting;
|
||||
};
|
||||
|
||||
class MultipleReporters;
|
||||
|
||||
struct IStreamingReporter : IShared {
|
||||
virtual ~IStreamingReporter();
|
||||
|
||||
@@ -5236,6 +5294,8 @@ namespace Catch
|
||||
virtual void testRunEnded( TestRunStats const& testRunStats ) = 0;
|
||||
|
||||
virtual void skipTest( TestCaseInfo const& testInfo ) = 0;
|
||||
|
||||
virtual MultipleReporters* tryAsMulti() { return CATCH_NULL; }
|
||||
};
|
||||
|
||||
struct IReporterFactory : IShared {
|
||||
@@ -5312,7 +5372,10 @@ namespace Catch {
|
||||
++it ) {
|
||||
matchedTests++;
|
||||
TestCaseInfo const& testCaseInfo = it->getTestCaseInfo();
|
||||
Catch::cout() << testCaseInfo.name << std::endl;
|
||||
if( startsWith( testCaseInfo.name, "#" ) )
|
||||
Catch::cout() << "\"" << testCaseInfo.name << "\"" << std::endl;
|
||||
else
|
||||
Catch::cout() << testCaseInfo.name << std::endl;
|
||||
}
|
||||
return matchedTests;
|
||||
}
|
||||
@@ -5453,6 +5516,10 @@ namespace TestCaseTracking {
|
||||
virtual void addChild( Ptr<ITracker> const& child ) = 0;
|
||||
virtual ITracker* findChild( std::string const& name ) = 0;
|
||||
virtual void openChild() = 0;
|
||||
|
||||
// Debug/ checking
|
||||
virtual bool isSectionTracker() const = 0;
|
||||
virtual bool isIndexTracker() const = 0;
|
||||
};
|
||||
|
||||
class TrackerContext {
|
||||
@@ -5577,6 +5644,10 @@ namespace TestCaseTracking {
|
||||
m_parent->openChild();
|
||||
}
|
||||
}
|
||||
|
||||
virtual bool isSectionTracker() const CATCH_OVERRIDE { return false; }
|
||||
virtual bool isIndexTracker() const CATCH_OVERRIDE { return false; }
|
||||
|
||||
void open() {
|
||||
m_runState = Executing;
|
||||
moveToThis();
|
||||
@@ -5640,13 +5711,16 @@ namespace TestCaseTracking {
|
||||
{}
|
||||
virtual ~SectionTracker();
|
||||
|
||||
virtual bool isSectionTracker() const CATCH_OVERRIDE { return true; }
|
||||
|
||||
static SectionTracker& acquire( TrackerContext& ctx, std::string const& name ) {
|
||||
SectionTracker* section = CATCH_NULL;
|
||||
|
||||
ITracker& currentTracker = ctx.currentTracker();
|
||||
if( ITracker* childTracker = currentTracker.findChild( name ) ) {
|
||||
section = dynamic_cast<SectionTracker*>( childTracker );
|
||||
assert( section );
|
||||
assert( childTracker );
|
||||
assert( childTracker->isSectionTracker() );
|
||||
section = static_cast<SectionTracker*>( childTracker );
|
||||
}
|
||||
else {
|
||||
section = new SectionTracker( name, ctx, ¤tTracker );
|
||||
@@ -5671,13 +5745,16 @@ namespace TestCaseTracking {
|
||||
{}
|
||||
virtual ~IndexTracker();
|
||||
|
||||
virtual bool isIndexTracker() const CATCH_OVERRIDE { return true; }
|
||||
|
||||
static IndexTracker& acquire( TrackerContext& ctx, std::string const& name, int size ) {
|
||||
IndexTracker* tracker = CATCH_NULL;
|
||||
|
||||
ITracker& currentTracker = ctx.currentTracker();
|
||||
if( ITracker* childTracker = currentTracker.findChild( name ) ) {
|
||||
tracker = dynamic_cast<IndexTracker*>( childTracker );
|
||||
assert( tracker );
|
||||
assert( childTracker );
|
||||
assert( childTracker->isIndexTracker() );
|
||||
tracker = static_cast<IndexTracker*>( childTracker );
|
||||
}
|
||||
else {
|
||||
tracker = new IndexTracker( name, ctx, ¤tTracker, size );
|
||||
@@ -5884,6 +5961,11 @@ namespace Catch {
|
||||
while( getCurrentContext().advanceGeneratorsForCurrentTest() && !aborting() );
|
||||
|
||||
Totals deltaTotals = m_totals.delta( prevTotals );
|
||||
if( testInfo.expectedToFail() && deltaTotals.testCases.passed > 0 ) {
|
||||
deltaTotals.assertions.failed++;
|
||||
deltaTotals.testCases.passed--;
|
||||
deltaTotals.testCases.failed++;
|
||||
}
|
||||
m_totals.testCases += deltaTotals.testCases;
|
||||
m_reporter->testCaseEnded( TestCaseStats( testInfo,
|
||||
deltaTotals,
|
||||
@@ -6275,10 +6357,10 @@ namespace Catch {
|
||||
Catch::cout() << "For more detail usage please see the project docs\n" << std::endl;
|
||||
}
|
||||
|
||||
int applyCommandLine( int argc, char const* argv[], OnUnusedOptions::DoWhat unusedOptionBehaviour = OnUnusedOptions::Fail ) {
|
||||
int applyCommandLine( int argc, char const* const* const argv, OnUnusedOptions::DoWhat unusedOptionBehaviour = OnUnusedOptions::Fail ) {
|
||||
try {
|
||||
m_cli.setThrowOnUnrecognisedTokens( unusedOptionBehaviour == OnUnusedOptions::Fail );
|
||||
m_unusedTokens = m_cli.parseInto( argc, argv, m_configData );
|
||||
m_unusedTokens = m_cli.parseInto( Clara::argsToVector( argc, argv ), m_configData );
|
||||
if( m_configData.showHelp )
|
||||
showHelp( m_configData.processName );
|
||||
m_config.reset();
|
||||
@@ -6302,16 +6384,13 @@ namespace Catch {
|
||||
m_config.reset();
|
||||
}
|
||||
|
||||
int run( int argc, char const* argv[] ) {
|
||||
int run( int argc, char const* const* const argv ) {
|
||||
|
||||
int returnCode = applyCommandLine( argc, argv );
|
||||
if( returnCode == 0 )
|
||||
returnCode = run();
|
||||
return returnCode;
|
||||
}
|
||||
int run( int argc, char* argv[] ) {
|
||||
return run( argc, const_cast<char const**>( argv ) );
|
||||
}
|
||||
|
||||
int run() {
|
||||
if( m_configData.showHelp )
|
||||
@@ -6375,13 +6454,31 @@ namespace Catch {
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
|
||||
#ifdef CATCH_CPP14_OR_GREATER
|
||||
#include <random>
|
||||
#endif
|
||||
|
||||
namespace Catch {
|
||||
|
||||
struct LexSort {
|
||||
bool operator() (TestCase i,TestCase j) const { return (i<j);}
|
||||
};
|
||||
struct RandomNumberGenerator {
|
||||
int operator()( int n ) const { return std::rand() % n; }
|
||||
typedef int result_type;
|
||||
|
||||
result_type operator()( result_type n ) const { return std::rand() % n; }
|
||||
|
||||
#ifdef CATCH_CPP14_OR_GREATER
|
||||
static constexpr result_type min() { return 0; }
|
||||
static constexpr result_type max() { return 1000000; }
|
||||
result_type operator()() const { return std::rand() % max(); }
|
||||
#endif
|
||||
template<typename V>
|
||||
static void shuffle( V& vector ) {
|
||||
RandomNumberGenerator rng;
|
||||
#ifdef CATCH_CPP14_OR_GREATER
|
||||
std::shuffle( vector.begin(), vector.end(), rng );
|
||||
#else
|
||||
std::random_shuffle( vector.begin(), vector.end(), rng );
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
inline std::vector<TestCase> sortTests( IConfig const& config, std::vector<TestCase> const& unsortedTestCases ) {
|
||||
@@ -6390,14 +6487,12 @@ namespace Catch {
|
||||
|
||||
switch( config.runOrder() ) {
|
||||
case RunTests::InLexicographicalOrder:
|
||||
std::sort( sorted.begin(), sorted.end(), LexSort() );
|
||||
std::sort( sorted.begin(), sorted.end() );
|
||||
break;
|
||||
case RunTests::InRandomOrder:
|
||||
{
|
||||
seedRng( config );
|
||||
|
||||
RandomNumberGenerator rng;
|
||||
std::random_shuffle( sorted.begin(), sorted.end(), rng );
|
||||
RandomNumberGenerator::shuffle( sorted );
|
||||
}
|
||||
break;
|
||||
case RunTests::InDeclarationOrder:
|
||||
@@ -6416,13 +6511,15 @@ namespace Catch {
|
||||
it != itEnd;
|
||||
++it ) {
|
||||
std::pair<std::set<TestCase>::const_iterator, bool> prev = seenFunctions.insert( *it );
|
||||
if( !prev.second ){
|
||||
Catch::cerr()
|
||||
<< Colour( Colour::Red )
|
||||
<< "error: TEST_CASE( \"" << it->name << "\" ) already defined.\n"
|
||||
<< "\tFirst seen at " << prev.first->getTestCaseInfo().lineInfo << "\n"
|
||||
<< "\tRedefined at " << it->getTestCaseInfo().lineInfo << std::endl;
|
||||
exit(1);
|
||||
if( !prev.second ) {
|
||||
std::ostringstream ss;
|
||||
|
||||
ss << Colour( Colour::Red )
|
||||
<< "error: TEST_CASE( \"" << it->name << "\" ) already defined.\n"
|
||||
<< "\tFirst seen at " << prev.first->getTestCaseInfo().lineInfo << "\n"
|
||||
<< "\tRedefined at " << it->getTestCaseInfo().lineInfo << std::endl;
|
||||
|
||||
throw std::runtime_error(ss.str());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7481,7 +7578,7 @@ namespace Catch {
|
||||
return os;
|
||||
}
|
||||
|
||||
Version libraryVersion( 1, 3, 5, "", 0 );
|
||||
Version libraryVersion( 1, 5, 7, "", 0 );
|
||||
|
||||
}
|
||||
|
||||
@@ -8460,13 +8557,18 @@ public: // IStreamingReporter
|
||||
++it )
|
||||
(*it)->skipTest( testInfo );
|
||||
}
|
||||
|
||||
virtual MultipleReporters* tryAsMulti() CATCH_OVERRIDE {
|
||||
return this;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
Ptr<IStreamingReporter> addReporter( Ptr<IStreamingReporter> const& existingReporter, Ptr<IStreamingReporter> const& additionalReporter ) {
|
||||
Ptr<IStreamingReporter> resultingReporter;
|
||||
|
||||
if( existingReporter ) {
|
||||
MultipleReporters* multi = dynamic_cast<MultipleReporters*>( existingReporter.get() );
|
||||
MultipleReporters* multi = existingReporter->tryAsMulti();
|
||||
if( !multi ) {
|
||||
multi = new MultipleReporters;
|
||||
resultingReporter = Ptr<IStreamingReporter>( multi );
|
||||
@@ -8646,7 +8748,7 @@ namespace Catch {
|
||||
|
||||
virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE {}
|
||||
|
||||
virtual bool assertionEnded( AssertionStats const& assertionStats ) {
|
||||
virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE {
|
||||
assert( !m_sectionStack.empty() );
|
||||
SectionNode& sectionNode = *m_sectionStack.back();
|
||||
sectionNode.assertions.push_back( assertionStats );
|
||||
@@ -8856,9 +8958,10 @@ namespace Catch {
|
||||
break;
|
||||
|
||||
default:
|
||||
// Escape control chars - based on contribution by @espenalb in PR #465
|
||||
// Escape control chars - based on contribution by @espenalb in PR #465 and
|
||||
// by @mrpi PR #588
|
||||
if ( ( c < '\x09' ) || ( c > '\x0D' && c < '\x20') || c=='\x7F' )
|
||||
os << "&#x" << std::uppercase << std::hex << static_cast<int>( c );
|
||||
os << "&#x" << std::uppercase << std::hex << std::setfill('0') << std::setw(2) << static_cast<int>( c ) << ';';
|
||||
else
|
||||
os << c;
|
||||
}
|
||||
@@ -8913,13 +9016,20 @@ namespace Catch {
|
||||
: m_tagIsOpen( false ),
|
||||
m_needsNewline( false ),
|
||||
m_os( &Catch::cout() )
|
||||
{}
|
||||
{
|
||||
// We encode control characters, which requires
|
||||
// XML 1.1
|
||||
// see http://stackoverflow.com/questions/404107/why-are-control-characters-illegal-in-xml-1-0
|
||||
*m_os << "<?xml version=\"1.1\" encoding=\"UTF-8\"?>\n";
|
||||
}
|
||||
|
||||
XmlWriter( std::ostream& os )
|
||||
: m_tagIsOpen( false ),
|
||||
m_needsNewline( false ),
|
||||
m_os( &os )
|
||||
{}
|
||||
{
|
||||
*m_os << "<?xml version=\"1.1\" encoding=\"UTF-8\"?>\n";
|
||||
}
|
||||
|
||||
~XmlWriter() {
|
||||
while( !m_tags.empty() )
|
||||
@@ -9086,7 +9196,7 @@ namespace Catch {
|
||||
|
||||
virtual void testCaseStarting( TestCaseInfo const& testInfo ) CATCH_OVERRIDE {
|
||||
StreamingReporterBase::testCaseStarting(testInfo);
|
||||
m_xml.startElement( "TestCase" ).writeAttribute( "name", trim( testInfo.name ) );
|
||||
m_xml.startElement( "TestCase" ).writeAttribute( "name", testInfo.name );
|
||||
|
||||
if ( m_config->showDurations() == ShowDurations::Always )
|
||||
m_testCaseTimer.start();
|
||||
@@ -9777,7 +9887,7 @@ namespace Catch {
|
||||
if( totals.testCases.total() == 0 ) {
|
||||
stream << Colour( Colour::Warning ) << "No tests ran\n";
|
||||
}
|
||||
else if( totals.assertions.total() > 0 && totals.assertions.allPassed() ) {
|
||||
else if( totals.assertions.total() > 0 && totals.testCases.allPassed() ) {
|
||||
stream << Colour( Colour::ResultSuccess ) << "All tests passed";
|
||||
stream << " ("
|
||||
<< pluralise( totals.assertions.passed, "assertion" ) << " in "
|
||||
|
@@ -16,9 +16,12 @@
|
||||
|
||||
|
||||
#include <chaiscript/chaiscript.hpp>
|
||||
#include <chaiscript/chaiscript_basic.hpp>
|
||||
#include <chaiscript/utility/utility.hpp>
|
||||
#include <chaiscript/dispatchkit/bootstrap_stl.hpp>
|
||||
|
||||
#include "../static_libs/chaiscript_parser.hpp"
|
||||
#include "../static_libs/chaiscript_stdlib.hpp"
|
||||
|
||||
|
||||
|
||||
@@ -34,7 +37,7 @@ TEST_CASE("C++11 Lambdas Can Be Registered")
|
||||
|
||||
// We cannot deduce the type of a lambda expression, you must either wrap it
|
||||
// in an std::function or provide the signature
|
||||
chaiscript::ChaiScript chai;
|
||||
chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser());
|
||||
|
||||
chai.add(chaiscript::fun([]()->std::string { return "hello"; } ), "f1");
|
||||
|
||||
@@ -49,7 +52,7 @@ TEST_CASE("C++11 Lambdas Can Be Registered")
|
||||
// dynamic_object tests
|
||||
TEST_CASE("Dynamic_Object attributes can be shared with C++")
|
||||
{
|
||||
chaiscript::ChaiScript chai;
|
||||
chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser());
|
||||
|
||||
chai("attr bob::z; def bob::bob() { this.z = 10 }; auto x = bob()");
|
||||
|
||||
@@ -77,7 +80,7 @@ TEST_CASE("Dynamic_Object attributes can be shared with C++")
|
||||
TEST_CASE("Function objects can be created from chaiscript functions")
|
||||
{
|
||||
|
||||
chaiscript::ChaiScript chai;
|
||||
chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser());
|
||||
|
||||
chai.eval("def func() { print(\"Hello World\"); } ");
|
||||
|
||||
@@ -91,7 +94,7 @@ TEST_CASE("Function objects can be created from chaiscript functions")
|
||||
|
||||
TEST_CASE("ChaiScript can be created and destroyed on heap")
|
||||
{
|
||||
chaiscript::ChaiScript *chai = new chaiscript::ChaiScript();
|
||||
auto *chai = new chaiscript::ChaiScript_Basic(create_chaiscript_stdlib(),create_chaiscript_parser());
|
||||
delete chai;
|
||||
}
|
||||
|
||||
@@ -123,7 +126,7 @@ void arithmetic_conversions_f_func_return(const std::function<unsigned int (unsi
|
||||
|
||||
TEST_CASE("Test automatic arithmetic conversions")
|
||||
{
|
||||
chaiscript::ChaiScript chai;
|
||||
chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser());
|
||||
|
||||
chai.add(chaiscript::fun(&arithmetic_conversions_f1), "f1");
|
||||
chai.add(chaiscript::fun(&arithmetic_conversions_f2), "f2");
|
||||
@@ -164,7 +167,7 @@ TEST_CASE("Test automatic arithmetic conversions")
|
||||
|
||||
TEST_CASE("Generic exception handling with C++")
|
||||
{
|
||||
chaiscript::ChaiScript chai;
|
||||
chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser());
|
||||
|
||||
try {
|
||||
chai.eval("throw(runtime_error(\"error\"));");
|
||||
@@ -177,7 +180,7 @@ TEST_CASE("Generic exception handling with C++")
|
||||
|
||||
TEST_CASE("Throw an int")
|
||||
{
|
||||
chaiscript::ChaiScript chai;
|
||||
chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser());
|
||||
|
||||
try {
|
||||
chai.eval("throw(1)", chaiscript::exception_specification<int>());
|
||||
@@ -189,7 +192,7 @@ TEST_CASE("Throw an int")
|
||||
|
||||
TEST_CASE("Throw int or double")
|
||||
{
|
||||
chaiscript::ChaiScript chai;
|
||||
chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser());
|
||||
|
||||
try {
|
||||
chai.eval("throw(1.0)", chaiscript::exception_specification<int, double>());
|
||||
@@ -201,7 +204,7 @@ TEST_CASE("Throw int or double")
|
||||
|
||||
TEST_CASE("Throw a runtime_error")
|
||||
{
|
||||
chaiscript::ChaiScript chai;
|
||||
chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser());
|
||||
|
||||
try {
|
||||
chai.eval("throw(runtime_error(\"error\"))", chaiscript::exception_specification<int, double, float, const std::string &, const std::exception &>());
|
||||
@@ -221,7 +224,7 @@ TEST_CASE("Throw a runtime_error")
|
||||
|
||||
TEST_CASE("Throw unhandled type")
|
||||
{
|
||||
chaiscript::ChaiScript chai;
|
||||
chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser());
|
||||
|
||||
try {
|
||||
chai.eval("throw(\"error\")", chaiscript::exception_specification<int, double, float, const std::exception &>());
|
||||
@@ -250,7 +253,7 @@ int expected_eval_errors_test_one(const int &)
|
||||
|
||||
TEST_CASE("No unexpected exceptions leak")
|
||||
{
|
||||
chaiscript::ChaiScript chai;
|
||||
chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser());
|
||||
chai.add(chaiscript::fun(&expected_eval_errors_test_one), "test_fun");
|
||||
|
||||
chai.eval("def guard_fun(i) : i.get_type_info().is_type_arithmetic() {} ");
|
||||
@@ -313,7 +316,7 @@ int function_ordering_test_two(int &)
|
||||
|
||||
TEST_CASE("Function ordering")
|
||||
{
|
||||
chaiscript::ChaiScript chai;
|
||||
chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser());
|
||||
chai.eval("def test_fun(x) { return 3; }");
|
||||
chai.eval("def test_fun(x) : x == \"hi\" { return 4; }");
|
||||
chai.eval("def test_fun(double d) { return 5; }");
|
||||
@@ -339,7 +342,7 @@ int functor_cast_test_call(const std::function<int (int)> &f, int val)
|
||||
TEST_CASE("Functor cast")
|
||||
{
|
||||
|
||||
chaiscript::ChaiScript chai;
|
||||
chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser());
|
||||
|
||||
chai.add(chaiscript::fun(&functor_cast_test_call), "test_call");
|
||||
|
||||
@@ -358,10 +361,10 @@ int set_state_test_myfun()
|
||||
|
||||
TEST_CASE("Set and restore chai state")
|
||||
{
|
||||
chaiscript::ChaiScript chai;
|
||||
chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser());
|
||||
|
||||
// save the initial state of globals and locals
|
||||
chaiscript::ChaiScript::State firststate = chai.get_state();
|
||||
auto firststate = chai.get_state();
|
||||
std::map<std::string, chaiscript::Boxed_Value> locals = chai.get_locals();
|
||||
|
||||
// add some new globals and locals
|
||||
@@ -404,7 +407,7 @@ class Short_Comparison_Test {
|
||||
|
||||
TEST_CASE("Short comparison with int")
|
||||
{
|
||||
chaiscript::ChaiScript chai;
|
||||
chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser());
|
||||
chai.add(chaiscript::user_type<Short_Comparison_Test>(), "Test");
|
||||
chai.add(chaiscript::constructor<Short_Comparison_Test()>(), "Test");
|
||||
|
||||
@@ -427,7 +430,7 @@ class Type_Name_MyClass
|
||||
|
||||
TEST_CASE("Test lookup of type names")
|
||||
{
|
||||
chaiscript::ChaiScript chai;
|
||||
chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser());
|
||||
auto type = chaiscript::user_type<Type_Name_MyClass>();
|
||||
chai.add(type, "MyClass");
|
||||
|
||||
@@ -453,13 +456,13 @@ int simultaneous_chaiscript_do_something_else(int i)
|
||||
|
||||
TEST_CASE("Simultaneous ChaiScript tests")
|
||||
{
|
||||
chaiscript::ChaiScript chai;
|
||||
chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser());
|
||||
chai.add(chaiscript::fun(&simultaneous_chaiscript_do_something), "do_something");
|
||||
chai.add(chaiscript::var(1), "i");
|
||||
|
||||
for (int i = 0; i < 10; ++i)
|
||||
{
|
||||
chaiscript::ChaiScript chai2;
|
||||
chaiscript::ChaiScript_Basic chai2(create_chaiscript_stdlib(),create_chaiscript_parser());
|
||||
chai2.add(chaiscript::fun(&simultaneous_chaiscript_do_something_else), "do_something_else");
|
||||
|
||||
CHECK(chai.eval<int>("do_something(" + std::to_string(i) + ")") == i + 2);
|
||||
@@ -508,7 +511,7 @@ TEST_CASE("Utility_Test utility class wrapper")
|
||||
);
|
||||
|
||||
|
||||
chaiscript::ChaiScript chai;
|
||||
chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser());
|
||||
chai.add(m);
|
||||
|
||||
CHECK(chai.eval<std::string>("auto t = Utility_Test(); t.function2(); ") == "Function2");
|
||||
@@ -551,7 +554,7 @@ TEST_CASE("Utility_Test utility class wrapper for enum")
|
||||
);
|
||||
|
||||
|
||||
chaiscript::ChaiScript chai;
|
||||
chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser());
|
||||
chai.add(m);
|
||||
|
||||
CHECK(chai.eval<Utility_Test_Numbers>("ONE ") == 0);
|
||||
@@ -646,7 +649,7 @@ TEST_CASE("Object copy counts")
|
||||
m->add(chaiscript::constructor<Object_Copy_Count_Test(const Object_Copy_Count_Test &)>(), "Object_Copy_Count_Test");
|
||||
m->add(chaiscript::fun(&object_copy_count_create), "create");
|
||||
|
||||
chaiscript::ChaiScript chai;
|
||||
chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser());
|
||||
chai.add(m);
|
||||
|
||||
chai.eval(" { auto i = create(); } ");
|
||||
@@ -702,7 +705,7 @@ TEST_CASE("Object lifetime tests")
|
||||
m->add(chaiscript::constructor<Object_Lifetime_Test(const Object_Lifetime_Test &)>(), "Object_Lifetime_Test");
|
||||
m->add(chaiscript::fun(&Object_Lifetime_Test::count), "count");
|
||||
|
||||
chaiscript::ChaiScript chai;
|
||||
chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser());
|
||||
chai.add(m);
|
||||
|
||||
CHECK(chai.eval<int>("count()") == 0);
|
||||
@@ -755,7 +758,7 @@ Object_Lifetime_Vector2<float> Object_Lifetime_Vector2_GetValue()
|
||||
|
||||
TEST_CASE("Object lifetime test 2")
|
||||
{
|
||||
chaiscript::ChaiScript _script;
|
||||
chaiscript::ChaiScript_Basic _script(create_chaiscript_stdlib(),create_chaiscript_parser());
|
||||
|
||||
//Registering stuff
|
||||
_script.add(chaiscript::user_type<Object_Lifetime_Vector2<float>>(), "Object_Lifetime_Vector2f");
|
||||
@@ -796,7 +799,7 @@ int myfunction(Non_Poly_Base *)
|
||||
|
||||
TEST_CASE("Test Derived->Base with non-polymorphic classes")
|
||||
{
|
||||
chaiscript::ChaiScript chai;
|
||||
chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser());
|
||||
chai.add(chaiscript::base_class<Non_Poly_Base, Non_Poly_Derived>());
|
||||
Non_Poly_Derived d;
|
||||
chai.add(chaiscript::var(&d), "d");
|
||||
@@ -815,7 +818,7 @@ struct TestCppVariableScope
|
||||
|
||||
TEST_CASE("Variable Scope When Calling From C++")
|
||||
{
|
||||
chaiscript::ChaiScript chai;
|
||||
chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser());
|
||||
chai.add(chaiscript::user_type<TestCppVariableScope>(), "Test");
|
||||
chai.add(chaiscript::constructor<TestCppVariableScope()>(), "Test");
|
||||
chai.add(chaiscript::fun(&TestCppVariableScope::print), "print");
|
||||
@@ -838,7 +841,7 @@ TEST_CASE("Variable Scope When Calling From C++")
|
||||
|
||||
TEST_CASE("Variable Scope When Calling From C++ 2")
|
||||
{
|
||||
chaiscript::ChaiScript chai;
|
||||
chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser());
|
||||
chai.eval("var obj = 2;");
|
||||
auto func = chai.eval<std::function<void()>>("fun(){ return obj; }");
|
||||
CHECK_THROWS(func());
|
||||
@@ -855,7 +858,7 @@ void longlong(long long i) {
|
||||
|
||||
TEST_CASE("Test long long dispatch")
|
||||
{
|
||||
chaiscript::ChaiScript chai;
|
||||
chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser());
|
||||
chai.add(chaiscript::fun(&longlong), "longlong");
|
||||
chai.add(chaiscript::fun(&ulonglong), "ulonglong");
|
||||
chai.eval("longlong(15)");
|
||||
@@ -875,7 +878,7 @@ struct Returned_Converted_Config
|
||||
|
||||
TEST_CASE("Return of converted type from script")
|
||||
{
|
||||
chaiscript::ChaiScript chai;
|
||||
chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser());
|
||||
|
||||
chai.add(chaiscript::constructor<Returned_Converted_Config ()>(), "Returned_Converted_Config");
|
||||
chai.add(chaiscript::fun(&Returned_Converted_Config::num_iterations), "num_iterations");
|
||||
@@ -923,7 +926,7 @@ int get_value_a(const std::map<std::string, int> &t_m)
|
||||
|
||||
TEST_CASE("Map conversions")
|
||||
{
|
||||
chaiscript::ChaiScript chai;
|
||||
chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser());
|
||||
chai.add(chaiscript::map_conversion<std::map<std::string, int>>());
|
||||
chai.add(chaiscript::fun(&get_value_a), "get_value_a");
|
||||
|
||||
@@ -943,7 +946,7 @@ TEST_CASE("Parse floats with non-posix locale")
|
||||
#else
|
||||
std::setlocale(LC_ALL, "en_ZA.utf8");
|
||||
#endif
|
||||
chaiscript::ChaiScript chai;
|
||||
chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser());
|
||||
const double parsed = chai.eval<double>("print(1.3); 1.3");
|
||||
CHECK(parsed == Approx(1.3));
|
||||
const std::string str = chai.eval<std::string>("to_string(1.3)");
|
||||
@@ -952,4 +955,110 @@ TEST_CASE("Parse floats with non-posix locale")
|
||||
|
||||
|
||||
|
||||
bool FindBitmap(int &ox, int &oy, long) {
|
||||
ox = 1;
|
||||
oy = 2;
|
||||
return true;
|
||||
}
|
||||
|
||||
TEST_CASE("Mismatched numeric types only convert necessary params")
|
||||
{
|
||||
chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser());
|
||||
|
||||
chai.add(chaiscript::fun(&FindBitmap), "FindBitmap");
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
chai.add(chaiscript::var(&x), "x");
|
||||
chai.add(chaiscript::var(&y), "y");
|
||||
chai.eval( "if ( FindBitmap ( x, y, 0) ) { print(\"found at \" + to_string(x) + \", \" + to_string(y))}" );
|
||||
CHECK(x == 1);
|
||||
CHECK(y == 2);
|
||||
|
||||
}
|
||||
|
||||
TEST_CASE("type_conversion to bool")
|
||||
{
|
||||
auto module = std::make_shared<chaiscript::Module>();
|
||||
struct T {
|
||||
operator bool() const { return true; }
|
||||
};
|
||||
module->add(chaiscript::type_conversion<T, bool>());
|
||||
}
|
||||
|
||||
TEST_CASE("Make sure ChaiScript object still compiles / executes")
|
||||
{
|
||||
chaiscript::ChaiScript chai;
|
||||
}
|
||||
|
||||
TEST_CASE("Test stdlib options")
|
||||
{
|
||||
const auto test_has_external_scripts = [](chaiscript::ChaiScript_Basic &chai) {
|
||||
CHECK_NOTHROW(chai.eval("`use`"));
|
||||
CHECK_NOTHROW(chai.eval("`eval_file`"));
|
||||
};
|
||||
|
||||
const auto test_no_external_scripts = [](chaiscript::ChaiScript_Basic &chai) {
|
||||
CHECK_THROWS(chai.eval("`use`"));
|
||||
CHECK_THROWS(chai.eval("`eval_file`"));
|
||||
};
|
||||
|
||||
const auto test_has_load_modules = [](chaiscript::ChaiScript_Basic &chai) {
|
||||
CHECK_NOTHROW(chai.eval("`load_module`"));
|
||||
};
|
||||
|
||||
const auto test_no_load_modules = [](chaiscript::ChaiScript_Basic &chai) {
|
||||
CHECK_THROWS(chai.eval("`load_module`"));
|
||||
};
|
||||
|
||||
SECTION( "Defaults" ) {
|
||||
chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser());
|
||||
test_has_external_scripts(chai);
|
||||
test_has_load_modules(chai);
|
||||
}
|
||||
|
||||
SECTION( "Load_Modules, External_Scripts" ) {
|
||||
chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser(), {}, {},
|
||||
{chaiscript::Options::Load_Modules, chaiscript::Options::External_Scripts} );
|
||||
test_has_external_scripts(chai);
|
||||
test_has_load_modules(chai);
|
||||
}
|
||||
|
||||
SECTION( "No_Load_Modules, No_External_Scripts" ) {
|
||||
chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser(), {}, {},
|
||||
{chaiscript::Options::No_Load_Modules, chaiscript::Options::No_External_Scripts} );
|
||||
test_no_external_scripts(chai);
|
||||
test_no_load_modules(chai);
|
||||
}
|
||||
|
||||
SECTION( "No_Load_Modules, Load_Modules" ) {
|
||||
chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser(), {}, {},
|
||||
{chaiscript::Options::No_Load_Modules, chaiscript::Options::Load_Modules} );
|
||||
test_no_external_scripts(chai);
|
||||
test_no_load_modules(chai);
|
||||
}
|
||||
|
||||
SECTION( "No_External_Scripts, External_Scripts" ) {
|
||||
chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser(), {}, {},
|
||||
{chaiscript::Options::No_External_Scripts, chaiscript::Options::External_Scripts} );
|
||||
test_no_external_scripts(chai);
|
||||
test_no_load_modules(chai);
|
||||
}
|
||||
|
||||
SECTION( "No_External_Scripts, Load_Modules" ) {
|
||||
chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser(), {}, {},
|
||||
{chaiscript::Options::No_External_Scripts, chaiscript::Options::Load_Modules} );
|
||||
test_no_external_scripts(chai);
|
||||
test_has_load_modules(chai);
|
||||
}
|
||||
|
||||
SECTION( "External_Scripts, No_Load_Modules" ) {
|
||||
chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser(), {}, {},
|
||||
{chaiscript::Options::External_Scripts, chaiscript::Options::No_Load_Modules} );
|
||||
test_has_external_scripts(chai);
|
||||
test_no_load_modules(chai);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
17
unittests/conversion_to_bool.chai
Normal file
17
unittests/conversion_to_bool.chai
Normal file
@@ -0,0 +1,17 @@
|
||||
|
||||
// all we care is that this executes, really
|
||||
|
||||
add_type_conversion(type("int"), type("bool"), fun(int i) { return i != 0; });
|
||||
|
||||
if (0) {
|
||||
assert_true(false);
|
||||
}
|
||||
|
||||
while (0) {
|
||||
assert_true(false);
|
||||
}
|
||||
|
||||
for (; 0; ) {
|
||||
assert_true(false);
|
||||
}
|
||||
|
@@ -1,7 +1,6 @@
|
||||
assert_equal(`==`, `==`);
|
||||
assert_not_equal(`==`, `<`);
|
||||
assert_equal(`<`.get_arity(), 2);
|
||||
assert_equal(`+`.get_annotation(), "Multiple method dispatch function wrapper.");
|
||||
assert_equal(get_arity.get_contained_functions().size(), 0);
|
||||
assert_equal(get_arity.get_arity(), 1);
|
||||
assert_equal(get_arity.get_param_types().size(), 2);
|
||||
|
@@ -35,4 +35,4 @@ def while_doing()
|
||||
|
||||
auto f = fun() { while_doing(); }
|
||||
|
||||
assert_equal(get_eval_error(f).call_stack.size(), 16)
|
||||
assert_true(get_eval_error(f).call_stack.size() <= 16)
|
||||
|
42
unittests/execution_context.chai
Normal file
42
unittests/execution_context.chai
Normal file
@@ -0,0 +1,42 @@
|
||||
|
||||
|
||||
assert_equal(__LINE__, 3)
|
||||
|
||||
def f() {
|
||||
[__LINE__, __CLASS__, __FUNC__]
|
||||
}
|
||||
|
||||
var res = f()
|
||||
|
||||
assert_equal(res[0], 6)
|
||||
assert_equal(res[1], "NOT_IN_CLASS")
|
||||
assert_equal(res[2], "f")
|
||||
|
||||
assert_equal(__CLASS__, "NOT_IN_CLASS")
|
||||
assert_equal(__FUNC__, "NOT_IN_FUNCTION")
|
||||
|
||||
class C
|
||||
{
|
||||
def C() {}
|
||||
def member() { [__LINE__, __CLASS__, __FUNC__]; }
|
||||
}
|
||||
|
||||
var c = C();
|
||||
|
||||
var res2 = c.member();
|
||||
|
||||
assert_equal(res2[0], 21)
|
||||
assert_equal(res2[1], "C")
|
||||
assert_equal(res2[2], "member")
|
||||
|
||||
def C::member2() { [__LINE__, __CLASS__, __FUNC__]; }
|
||||
|
||||
var res3 = c.member2();
|
||||
|
||||
assert_equal(res3[0], 32)
|
||||
assert_equal(res3[1], "C")
|
||||
assert_equal(res3[2], "member2")
|
||||
|
||||
assert_true(__FILE__.find("execution_context.chai") != -1)
|
||||
|
||||
|
@@ -10,7 +10,6 @@ def test_function(a)
|
||||
|
||||
// test_function tests
|
||||
assert_equal(test_function.get_arity(), 1);
|
||||
assert_equal(trim(test_function.get_annotation()), "#Test Function Description");
|
||||
assert_equal(test_function.get_contained_functions().size(), 0);
|
||||
assert_equal(test_function.get_param_types().size(), 2);
|
||||
|
||||
|
Binary file not shown.
BIN
unittests/fuzzy_tests-2016-06-29.tar.bz2
Normal file
BIN
unittests/fuzzy_tests-2016-06-29.tar.bz2
Normal file
Binary file not shown.
@@ -16,3 +16,8 @@ def f() {
|
||||
|
||||
f();
|
||||
|
||||
|
||||
global &h = v;
|
||||
assert_true(h == v)
|
||||
v = 3;
|
||||
assert_true(h == 3)
|
||||
|
7
unittests/init_if.chai
Normal file
7
unittests/init_if.chai
Normal file
@@ -0,0 +1,7 @@
|
||||
if (var x = 2; x == 3) {
|
||||
assert_true(false);
|
||||
} else if (var y = 3; y == 6) {
|
||||
assert_true(false);
|
||||
} else {
|
||||
assert_equal(5, y + x);
|
||||
}
|
@@ -1,4 +1,7 @@
|
||||
#include <chaiscript/chaiscript.hpp>
|
||||
#include <chaiscript/chaiscript_basic.hpp>
|
||||
#include "../static_libs/chaiscript_parser.hpp"
|
||||
#include "../static_libs/chaiscript_stdlib.hpp"
|
||||
|
||||
|
||||
#define TEST_LITERAL(v) test_literal(v, #v)
|
||||
|
||||
@@ -6,7 +9,7 @@ template<typename T>
|
||||
bool test_literal(T val, const std::string &str)
|
||||
{
|
||||
std::cout << "Comparing : " << val;
|
||||
chaiscript::ChaiScript chai;
|
||||
chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser());
|
||||
T val2 = chai.eval<T>(str);
|
||||
std::cout << " " << val2 << '\n';
|
||||
return val == val2;
|
||||
|
@@ -1,14 +1,16 @@
|
||||
#include "multifile_test_chai.hpp"
|
||||
|
||||
#include <chaiscript/chaiscript_stdlib.hpp>
|
||||
#include <chaiscript/language/chaiscript_parser.hpp>
|
||||
|
||||
Multi_Test_Chai::Multi_Test_Chai()
|
||||
: m_chai(new chaiscript::ChaiScript(chaiscript::Std_Lib::library()))
|
||||
: m_chai(new chaiscript::ChaiScript_Basic(chaiscript::Std_Lib::library(),
|
||||
std::make_unique<chaiscript::parser::ChaiScript_Parser<chaiscript::eval::Noop_Tracer, chaiscript::optimizer::Optimizer_Default>>()))
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
std::shared_ptr<chaiscript::ChaiScript> Multi_Test_Chai::get_chai()
|
||||
std::shared_ptr<chaiscript::ChaiScript_Basic> Multi_Test_Chai::get_chai()
|
||||
{
|
||||
return m_chai;
|
||||
}
|
||||
|
@@ -1,14 +1,14 @@
|
||||
#include <chaiscript/chaiscript.hpp>
|
||||
#include <chaiscript/chaiscript_basic.hpp>
|
||||
|
||||
class Multi_Test_Chai
|
||||
{
|
||||
public:
|
||||
Multi_Test_Chai();
|
||||
|
||||
std::shared_ptr<chaiscript::ChaiScript> get_chai();
|
||||
std::shared_ptr<chaiscript::ChaiScript_Basic> get_chai();
|
||||
|
||||
private:
|
||||
std::shared_ptr<chaiscript::ChaiScript> m_chai;
|
||||
std::shared_ptr<chaiscript::ChaiScript_Basic> m_chai;
|
||||
};
|
||||
|
||||
|
||||
|
@@ -1,14 +1,14 @@
|
||||
#include "multifile_test_chai.hpp"
|
||||
#include "multifile_test_module.hpp"
|
||||
|
||||
#include <chaiscript/chaiscript.hpp>
|
||||
#include <chaiscript/chaiscript_basic.hpp>
|
||||
|
||||
int main()
|
||||
{
|
||||
Multi_Test_Chai chaitest;
|
||||
Multi_Test_Module chaimodule;
|
||||
|
||||
std::shared_ptr<chaiscript::ChaiScript> chai = chaitest.get_chai();
|
||||
std::shared_ptr<chaiscript::ChaiScript_Basic> chai = chaitest.get_chai();
|
||||
chai->add(chaimodule.get_module());
|
||||
return chai->eval<int>("get_module_value()");
|
||||
}
|
||||
|
@@ -1,4 +1,4 @@
|
||||
#include <chaiscript/chaiscript.hpp>
|
||||
#include <chaiscript/chaiscript_basic.hpp>
|
||||
|
||||
#include "multifile_test_module.hpp"
|
||||
|
||||
|
@@ -1,4 +1,4 @@
|
||||
#include <chaiscript/chaiscript.hpp>
|
||||
#include <chaiscript/chaiscript_basic.hpp>
|
||||
|
||||
class Multi_Test_Module
|
||||
{
|
||||
|
@@ -2,7 +2,8 @@
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include <chaiscript/chaiscript.hpp>
|
||||
#include <chaiscript/chaiscript_basic.hpp>
|
||||
#include <chaiscript/language/chaiscript_parser.hpp>
|
||||
|
||||
int expected_value(int num_iters)
|
||||
{
|
||||
@@ -15,7 +16,7 @@ int expected_value(int num_iters)
|
||||
return i;
|
||||
}
|
||||
|
||||
void do_work(chaiscript::ChaiScript &c, const size_t id)
|
||||
void do_work(chaiscript::ChaiScript_Basic &c, const size_t id)
|
||||
{
|
||||
try{
|
||||
std::stringstream ss;
|
||||
@@ -62,7 +63,12 @@ int main()
|
||||
modulepaths.push_back(modulepath);
|
||||
}
|
||||
|
||||
chaiscript::ChaiScript chai(modulepaths,usepaths);
|
||||
|
||||
// For this test we are going to load the dynamic stdlib
|
||||
// to make sure it continues to work
|
||||
chaiscript::ChaiScript_Basic chai(
|
||||
std::make_unique<chaiscript::parser::ChaiScript_Parser<chaiscript::eval::Noop_Tracer, chaiscript::optimizer::Optimizer_Default>>(),
|
||||
modulepaths,usepaths);
|
||||
|
||||
std::vector<std::shared_ptr<std::thread> > threads;
|
||||
|
||||
|
4
unittests/precedence_4.chai
Normal file
4
unittests/precedence_4.chai
Normal file
@@ -0,0 +1,4 @@
|
||||
|
||||
var i = 2;
|
||||
|
||||
assert_equal(++i * i, 9)
|
21
unittests/ranged_for.chai
Normal file
21
unittests/ranged_for.chai
Normal file
@@ -0,0 +1,21 @@
|
||||
var sum = 0;
|
||||
|
||||
for (x : [1,2,3,4]) {
|
||||
sum += x;
|
||||
}
|
||||
|
||||
assert_equal(sum, 10)
|
||||
|
||||
var result = 0.0;
|
||||
|
||||
for (x : retro(range([1,2,3,4]))) {
|
||||
if (result == 0.0) {
|
||||
result = x;
|
||||
} else {
|
||||
result /= x;
|
||||
}
|
||||
}
|
||||
|
||||
assert_true(result > .6 && result < .7);
|
||||
|
||||
|
@@ -1,22 +1,9 @@
|
||||
auto& parser = ChaiScript_Parser()
|
||||
auto parse_success = parser.parse("3 + 4", "INPUT")
|
||||
auto& a = parser.ast()
|
||||
auto a = parse("3 + 4")
|
||||
|
||||
assert_equal(eval(a), 7)
|
||||
|
||||
auto& childs = a.children.front().children
|
||||
auto& node = childs[0]
|
||||
|
||||
auto& parser2 = ChaiScript_Parser()
|
||||
parser2.parse("9", "INPUT")
|
||||
|
||||
|
||||
a.children.front().replace_child(childs[0], parser2.ast())
|
||||
|
||||
assert_equal(eval(a), 13)
|
||||
assert_equal(node.filename, "INPUT")
|
||||
|
||||
|
||||
assert_equal(1, a.children.size());
|
||||
assert_equal("3 + 4", a.children[0].text());
|
||||
|
||||
def my_fun()
|
||||
{
|
||||
|
8
unittests/string_unicode_ascii.chai
Normal file
8
unittests/string_unicode_ascii.chai
Normal file
@@ -0,0 +1,8 @@
|
||||
assert_equal('\u0020', ' ')
|
||||
assert_equal('\u0021', '!')
|
||||
assert_equal('\u0030', '0')
|
||||
assert_equal('\u0040', '@')
|
||||
assert_equal('\u005B', '[')
|
||||
assert_equal('\u005d', ']')
|
||||
assert_equal('\u0061', 'a')
|
||||
assert_equal('\u007e', '~')
|
11
unittests/string_unicode_parse.chai
Normal file
11
unittests/string_unicode_parse.chai
Normal file
@@ -0,0 +1,11 @@
|
||||
assert_equal('\u00aa', '\u00AA')
|
||||
assert_equal('\u00bb', '\uBB')
|
||||
assert_equal('\ucc', '\u00CC')
|
||||
assert_equal('\udd', '\uDD')
|
||||
|
||||
assert_equal('\u0ee', '\uEE')
|
||||
assert_equal('\ue', '\u000E')
|
||||
|
||||
assert_equal("\u30\u31\u32", "012")
|
||||
assert_equal("\u33Test", "3Test")
|
||||
assert_equal("Test\u0040", "Test@")
|
5
unittests/string_unicode_unicode.chai
Normal file
5
unittests/string_unicode_unicode.chai
Normal file
@@ -0,0 +1,5 @@
|
||||
assert_equal("\uc39c", "Ü")
|
||||
assert_equal("U for \uc39cmlauts", "U for Ümlauts")
|
||||
assert_equal("More \uc39cml\uc3a4\uc3bcts", "More Ümläüts")
|
||||
|
||||
assert_equal("Thorn \uc3be sign", "Thorn þ sign")
|
Reference in New Issue
Block a user