commit
7d3c23fc22
@ -10,12 +10,12 @@ compilers:
|
||||
cmake_extra_flags: -DUSE_LIBCXX:BOOL=ON -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON
|
||||
- name: "clang"
|
||||
build_tag: AddressSanitizer
|
||||
version: "3.5"
|
||||
version: "3.6"
|
||||
skip_packaging: true
|
||||
cmake_extra_flags: -DUSE_LIBCXX:BOOL=OFF -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DENABLE_ADDRESS_SANITIZER:BOOL=ON
|
||||
- name: "clang"
|
||||
build_tag: ThreadSanitizer
|
||||
version: "3.5"
|
||||
version: "3.6"
|
||||
skip_packaging: true
|
||||
cmake_extra_flags: -DUSE_LIBCXX:BOOL=OFF -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DENABLE_THREAD_SANITIZER:BOOL=ON
|
||||
- name: "gcc"
|
||||
|
45
.travis.yml
45
.travis.yml
@ -2,24 +2,34 @@ language: cpp
|
||||
compiler:
|
||||
- gcc
|
||||
env:
|
||||
- GCC_VER=4.6
|
||||
- GCC_VER=4.8
|
||||
matrix:
|
||||
- GCC_VER="4.6"
|
||||
- GCC_VER="4.8"
|
||||
|
||||
global:
|
||||
- secure: eiaR6pXiiEpyB8+LLQ1NvZdl0Yylru1BLy9lMoHl+IpUNGGQGywmW/2WAn77rFfmR1OPA2qWQLfgPwgK0HxUA9HHlot9tre5QhiN2Lw8NOT8tCZ6tTm2+QntDBjBGJyal/knRvQkn/6qs6GxlXRerz4ArnnuPL1vESt3zwB0YtU=
|
||||
# The next declaration is the encrypted COVERITY_SCAN_TOKEN, created
|
||||
- secure: "LfolGjP8tWm3yAwthfu3yp8Zn40aueFae580UUR34gusG87cyglq2tQDtxdy+63gWEeNfArbv9n5rZv+bDW3ggHyPjuCKKc1PlZAy07lfXUXf1uz+SFhNvNoYTn3mQG3VZ08o116p4Le2p8yqu4bylJ8wckEq7PrTwvSGVQWTWM="
|
||||
|
||||
before_install:
|
||||
- export CXX="g++-$GCC_VER" CC="gcc-$GCC_VER" GCOV="gcov-$GCC_VER"
|
||||
- if [ "$GCC_VER" = "4.8" ]; then export COVERAGE=1 CPPCHECK=1; fi
|
||||
- if [ ${COVERAGE} = 1 ]; then export FUZZY_CMD="-D RUN_FUZZY_TESTS:BOOL=TRUE"; fi
|
||||
- sudo pip install cpp-coveralls
|
||||
- sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y
|
||||
- sudo apt-get update
|
||||
- sudo apt-get install -qq g++-4.8
|
||||
- if [ "$GCC_VER" = "4.8" ]; then export CXX="g++-4.8" CC="gcc-4.8" GCOV="gcov-4.8"; else export CXX="g++-4.6" CC="gcc-4.6" GCOV="gcov-4.6"; fi
|
||||
- sudo apt-get install -qq g++-$GCC_VER
|
||||
|
||||
script:
|
||||
- cmake -D ENABLE_COVERAGE:BOOL=TRUE -D CMAKE_BUILD_TYPE:STRING=Debug .
|
||||
- make -j2
|
||||
- if [ ${COVERITY_SCAN_BRANCH} != 1 ]; then cmake -D ENABLE_COVERAGE:BOOL=TRUE -D CMAKE_BUILD_TYPE:STRING=Debug $FUZZY_CMD . ; fi
|
||||
- if [ ${COVERITY_SCAN_BRANCH} != 1 ]; then make -j2 ; fi
|
||||
- make test
|
||||
- mkdir gcov
|
||||
- find CMakeFiles/ -name "*.gc*" -exec mv {} gcov/ \;
|
||||
- $GCOV -d -o gcov gcov/*.gcda
|
||||
- coveralls -n -E ".*\.cpp"
|
||||
- if [ ${COVERAGE} = 1 ]; then bash <(curl -s https://raw.githubusercontent.com/codecov/codecov-bash/master/codecov) -x $GCOV -a "-s `pwd`" ; fi
|
||||
|
||||
after_script:
|
||||
- contrib/codeanalysis/runcppcheck.sh
|
||||
- if [ ${CPPCHECK} = 1 ]; then contrib/codeanalysis/runcppcheck.sh ; fi
|
||||
|
||||
|
||||
notifications:
|
||||
email:
|
||||
recipients:
|
||||
@ -32,8 +42,15 @@ notifications:
|
||||
on_success: change # options: [always|never|change] default: always
|
||||
on_failure: always # options: [always|never|change] default: always
|
||||
on_start: false # default: false
|
||||
env:
|
||||
global:
|
||||
secure: eiaR6pXiiEpyB8+LLQ1NvZdl0Yylru1BLy9lMoHl+IpUNGGQGywmW/2WAn77rFfmR1OPA2qWQLfgPwgK0HxUA9HHlot9tre5QhiN2Lw8NOT8tCZ6tTm2+QntDBjBGJyal/knRvQkn/6qs6GxlXRerz4ArnnuPL1vESt3zwB0YtU=
|
||||
|
||||
addons:
|
||||
coverity_scan:
|
||||
project:
|
||||
name: "ChaiScript/ChaiScript"
|
||||
description: "Build submitted via Travis CI"
|
||||
notification_email: jason@emptycrate.com
|
||||
build_command_prepend: "cmake -D ENABLE_COVERAGE:BOOL=TRUE -D CMAKE_BUILD_TYPE:STRING=Debug . "
|
||||
build_command: "cmake --build . -- -j2"
|
||||
branch_pattern: coverity_scan
|
||||
|
||||
|
||||
|
@ -18,6 +18,7 @@ option(MULTITHREAD_SUPPORT_ENABLED "Multithreaded Support Enabled" TRUE)
|
||||
|
||||
option(BUILD_MODULES "Build Extra Modules (stl)" TRUE)
|
||||
option(BUILD_SAMPLES "Build Samples Folder" FALSE)
|
||||
option(RUN_FUZZY_TESTS "Run tests generated by AFL" FALSE)
|
||||
option(USE_STD_MAKE_SHARED "Use std::make_shared instead of chaiscript::make_shared" FALSE)
|
||||
|
||||
mark_as_advanced(USE_STD_MAKE_SHARED)
|
||||
@ -94,7 +95,7 @@ set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/description.txt"
|
||||
|
||||
set(CPACK_PACKAGE_VERSION_MAJOR 5)
|
||||
set(CPACK_PACKAGE_VERSION_MINOR 7)
|
||||
set(CPACK_PACKAGE_VERSION_PATCH 0)
|
||||
set(CPACK_PACKAGE_VERSION_PATCH 1)
|
||||
|
||||
set(CPACK_PACKAGE_EXECUTABLES "chai;ChaiScript Eval")
|
||||
set(CPACK_PACKAGE_VENDOR "ChaiScript.com")
|
||||
@ -269,9 +270,51 @@ if(BUILD_MODULES)
|
||||
endif()
|
||||
|
||||
file(GLOB UNIT_TESTS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/unittests/ ${CMAKE_CURRENT_SOURCE_DIR}/unittests/*.chai ${CMAKE_CURRENT_SOURCE_DIR}/unittests/3.x/*.chai)
|
||||
|
||||
list(SORT UNIT_TESTS)
|
||||
|
||||
|
||||
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
|
||||
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/unittests
|
||||
)
|
||||
|
||||
|
||||
file(GLOB FUZZY_CRASH_TESTS RELATIVE ${CMAKE_BINARY_DIR}/unittests/ ${CMAKE_BINARY_DIR}/unittests/fuzzy_tests/crashes/id*)
|
||||
list(SORT FUZZY_CRASH_TESTS)
|
||||
|
||||
file(GLOB FUZZY_EXCEPTION_TESTS RELATIVE ${CMAKE_BINARY_DIR}/unittests/ ${CMAKE_BINARY_DIR}/unittests/fuzzy_tests/exceptions/id*)
|
||||
list(SORT FUZZY_EXCEPTION_TESTS)
|
||||
|
||||
|
||||
foreach(filename ${FUZZY_CRASH_TESTS})
|
||||
message(STATUS "Adding test ${filename}")
|
||||
add_test(${filename} chai "-e" ${CMAKE_BINARY_DIR}/unittests/fuzzy_tests/crashes/unit_test.inc ${CMAKE_BINARY_DIR}/unittests/${filename})
|
||||
endforeach()
|
||||
|
||||
set_property(TEST ${FUZZY_CRASH_TESTS}
|
||||
PROPERTY ENVIRONMENT
|
||||
"CHAI_USE_PATH=${CMAKE_BINARY_DIR}/unittests/"
|
||||
"CHAI_MODULE_PATH=${CMAKE_CURRENT_BINARY_DIR}/"
|
||||
)
|
||||
|
||||
foreach(filename ${FUZZY_EXCEPTION_TESTS})
|
||||
message(STATUS "Adding test ${filename}")
|
||||
add_test(${filename} chai "--exception" ${CMAKE_BINARY_DIR}/unittests/fuzzy_tests/exceptions/unit_test.inc ${CMAKE_BINARY_DIR}/unittests/${filename})
|
||||
endforeach()
|
||||
|
||||
set_property(TEST ${FUZZY_EXCEPTION_TESTS}
|
||||
PROPERTY ENVIRONMENT
|
||||
"CHAI_USE_PATH=${CMAKE_CURRENT_SOURCE_DIR}/unittests/"
|
||||
"CHAI_MODULE_PATH=${CMAKE_CURRENT_BINARY_DIR}/"
|
||||
)
|
||||
|
||||
endif()
|
||||
|
||||
|
||||
if(BUILD_TESTING)
|
||||
|
||||
# Add catch tests macro
|
||||
@ -314,6 +357,19 @@ if(BUILD_TESTING)
|
||||
"CHAI_MODULE_PATH=${CMAKE_CURRENT_BINARY_DIR}/"
|
||||
)
|
||||
|
||||
add_test(version_check_2 chai --version )
|
||||
set_property(TEST version_check_2
|
||||
PROPERTY ENVIRONMENT
|
||||
"CHAI_MODULE_PATH=${CMAKE_CURRENT_BINARY_DIR}/"
|
||||
PROPERTY PASS_REGULAR_EXPRESSION "${CHAI_VERSION}"
|
||||
)
|
||||
|
||||
add_test(help chai --help )
|
||||
set_property(TEST help
|
||||
PROPERTY ENVIRONMENT
|
||||
"CHAI_MODULE_PATH=${CMAKE_CURRENT_BINARY_DIR}/"
|
||||
)
|
||||
|
||||
|
||||
foreach(filename ${UNIT_TESTS})
|
||||
message(STATUS "Adding test ${filename}")
|
||||
|
@ -1,3 +1,13 @@
|
||||
# ChaiScript Versioning
|
||||
|
||||
ChaiScript tries to follow the [Semantic Versioning](http://semver.org/) scheme. This basically means:
|
||||
|
||||
* Major Version Number: API changes / breaking changes
|
||||
* Minor Version Number: New Features
|
||||
* Patch Version Number: Minor changes / enhancements
|
||||
|
||||
|
||||
|
||||
# Initializing ChaiScript
|
||||
|
||||
```
|
||||
@ -30,6 +40,19 @@ chai.add(chaiscript::fun<ReturnType (ParamType1, ParamType2)>(&function_with_ove
|
||||
```
|
||||
chai.add(chaiscript::fun(std::static_cast<ReturnType (*)(ParamType1, ParamType2)>(&function_with_overloads)), "function_name");
|
||||
```
|
||||
This overload technique is also used when exposing base member using derived type
|
||||
|
||||
```
|
||||
struct Base
|
||||
{
|
||||
int data;
|
||||
};
|
||||
|
||||
struct Derived : public Base
|
||||
{};
|
||||
|
||||
chai.add(chaiscript::fun(static_cast<int(Derived::*)>(&Derived::data)), "data");
|
||||
```
|
||||
|
||||
### Lambda
|
||||
|
||||
@ -57,6 +80,18 @@ It's not strictly necessary to add types, but it helps with many things. Cloning
|
||||
chai.add(chaiscript::user_type<MyClass>, "MyClass");
|
||||
```
|
||||
|
||||
## Adding Type Conversions
|
||||
|
||||
User defined type conversions are possible, defined in either script or in C++.
|
||||
|
||||
A helper function exists for strongly typed and ChaiScript `Vector` function conversion definition:
|
||||
|
||||
```
|
||||
chai.add(chaiscript::vector_conversion<std::vector<int>>());
|
||||
```
|
||||
|
||||
This allows you to pass a ChaiScript function to a function requiring `std::vector<int>`
|
||||
|
||||
## Adding Objects
|
||||
|
||||
```
|
||||
@ -68,6 +103,22 @@ chai.add(chaiscript::const_var(somevar), "somevar"); // copied in and made const
|
||||
chai.add_global_const(chaiscript::const_var(somevar), "somevar"); // global const. Throws if value is non-const
|
||||
chai.add_global(chaiscript::var(somevar), "somevar"); // global non-const
|
||||
```
|
||||
# Using STL
|
||||
ChaiScript recognize many types from STL, but you have to add specific instantiation yourself.
|
||||
|
||||
```
|
||||
typedef std::vector<std::pair<int, std::string>> data_list;
|
||||
data_list my_list{ make_pair(0, "Hello"), make_pair(1, "World") };
|
||||
chai.add(chaiscript::bootstrap::standard_library::vector_type<data_list>("DataList"));
|
||||
chai.add(chaiscript::bootstrap::standard_library::pair_type<data_list::value_type>("DataElement"));
|
||||
chai.add(chaiscript::var(&my_list), "data_list");
|
||||
chai.eval(R"_(
|
||||
for(var i=0; i<data_list.size(); ++i)
|
||||
{
|
||||
print(to_string(data_list[i].first) + " " + data_list[i].second)
|
||||
}
|
||||
)_");
|
||||
```
|
||||
|
||||
# Executing Script
|
||||
|
||||
@ -80,6 +131,8 @@ chai.eval(R"(print("Hello World"))");
|
||||
|
||||
## Unboxing Return Values
|
||||
|
||||
Returns values are of the type `Boxed_Value` which is meant to be opaque to the programmer. Use one of the unboxing methods to access the internal data.
|
||||
|
||||
### Prefered
|
||||
|
||||
```
|
||||
@ -152,7 +205,7 @@ p(5, 6); // calls chaiscript's '+' function, returning 11
|
||||
```
|
||||
|
||||
```
|
||||
auto p = chai.eval<std::function<std::string (int, double)>>(fun(x,y) { to_string(x) + to_string(y); });
|
||||
auto p = chai.eval<std::function<std::string (int, double)>>("fun(x,y) { to_string(x) + to_string(y); }");
|
||||
p(3,4.2); // evaluates the lambda function, returning the string "34.2" to C++
|
||||
```
|
||||
|
||||
@ -183,7 +236,7 @@ var m = ["a":1, "b":2]; // map of string:value pairs
|
||||
```
|
||||
|
||||
Floating point values default to `double` type and integers default to `int` type. All C++ suffixes
|
||||
such as `f`, `ll`, `u` as well as scientific notion is supported
|
||||
such as `f`, `ll`, `u` as well as scientific notation are supported
|
||||
|
||||
```
|
||||
1.0 // double
|
||||
@ -201,6 +254,9 @@ on your platform.
|
||||
|
||||
## Functions
|
||||
|
||||
Note that any type of ChaiScript function can be passed freely to C++ and automatically
|
||||
converted into an `std::function` object.
|
||||
|
||||
### General
|
||||
|
||||
```
|
||||
|
@ -35,6 +35,10 @@
|
||||
#define CHAISCRIPT_HAS_THREAD_LOCAL
|
||||
#endif
|
||||
|
||||
#if (defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ == 6)
|
||||
#define CHAISCRIPT_GCC_4_6
|
||||
#endif
|
||||
|
||||
#if (defined(__GNUC__) && __GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7) || defined(CHAISCRIPT_MSVC) || defined(__llvm__)
|
||||
#define CHAISCRIPT_OVERRIDE override
|
||||
#else
|
||||
@ -61,7 +65,7 @@
|
||||
namespace chaiscript {
|
||||
static const int version_major = 5;
|
||||
static const int version_minor = 7;
|
||||
static const int version_patch = 0;
|
||||
static const int version_patch = 1;
|
||||
|
||||
template<typename B, typename D, typename ...Arg>
|
||||
inline std::shared_ptr<B> make_shared(Arg && ... arg)
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "dispatchkit/bootstrap.hpp"
|
||||
#include "dispatchkit/bootstrap_stl.hpp"
|
||||
#include "dispatchkit/boxed_value.hpp"
|
||||
#include "language/chaiscript_prelude.chai"
|
||||
|
||||
#ifndef CHAISCRIPT_NO_THREADS
|
||||
#include <future>
|
||||
@ -47,9 +48,11 @@ namespace chaiscript
|
||||
|
||||
#ifndef CHAISCRIPT_NO_THREADS
|
||||
lib->add(standard_library::future_type<std::future<chaiscript::Boxed_Value>>("future"));
|
||||
lib->add(chaiscript::fun<std::future<Boxed_Value> (const std::function<chaiscript::Boxed_Value ()> &)>([](const std::function<chaiscript::Boxed_Value ()> &t_func){ return std::async(std::launch::async, t_func);}), "async");
|
||||
lib->add(chaiscript::fun([](const std::function<chaiscript::Boxed_Value ()> &t_func){ return std::async(std::launch::async, t_func);}), "async");
|
||||
#endif
|
||||
|
||||
lib->eval(ChaiScript_Prelude::chaiscript_prelude() /*, "standard prelude"*/ );
|
||||
|
||||
return lib;
|
||||
}
|
||||
|
||||
|
@ -14,8 +14,10 @@
|
||||
#include <thread>
|
||||
#include <mutex>
|
||||
#else
|
||||
#ifndef CHAISCRIPT_NO_THREADS_WARNING
|
||||
#pragma message ("ChaiScript is compiling without thread safety.")
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include "chaiscript_defines.hpp"
|
||||
|
||||
@ -153,6 +155,7 @@ namespace chaiscript
|
||||
|
||||
|
||||
private:
|
||||
/// \todo this leaks thread instances. It needs to be culled from time to time
|
||||
std::shared_ptr<T> get_tls() const
|
||||
{
|
||||
unique_lock<mutex> lock(m_mutex);
|
||||
|
@ -36,7 +36,7 @@ namespace chaiscript
|
||||
}
|
||||
|
||||
bad_boxed_cast(Type_Info t_from, const std::type_info &t_to)
|
||||
: from(std::move(t_from)), to(&t_to), m_what("Cannot perform boxed_cast")
|
||||
: from(std::move(t_from)), to(&t_to), m_what("Cannot perform boxed_cast: " + t_from.name() + " to: " + t_to.name())
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -57,7 +57,7 @@ namespace chaiscript
|
||||
typedef typename std::remove_extent<T>::type ReturnType;
|
||||
const auto extent = std::extent<T>::value;
|
||||
m->add(user_type<T>(), type);
|
||||
m->add(fun<ReturnType& (T &, size_t)>(
|
||||
m->add(fun(
|
||||
[extent](T& t, size_t index)->ReturnType &{
|
||||
if (extent > 0 && index >= extent) {
|
||||
throw std::range_error("Array index out of range. Received: " + std::to_string(index) + " expected < " + std::to_string(extent));
|
||||
@ -68,7 +68,7 @@ namespace chaiscript
|
||||
), "[]"
|
||||
);
|
||||
|
||||
m->add(fun<const ReturnType& (const T &, size_t)>(
|
||||
m->add(fun(
|
||||
[extent](const T &t, size_t index)->const ReturnType &{
|
||||
if (extent > 0 && index >= extent) {
|
||||
throw std::range_error("Array index out of range. Received: " + std::to_string(index) + " expected < " + std::to_string(extent));
|
||||
@ -79,7 +79,7 @@ namespace chaiscript
|
||||
), "[]"
|
||||
);
|
||||
|
||||
m->add(fun<size_t (const T &)>(
|
||||
m->add(fun(
|
||||
[extent](const T &) {
|
||||
return extent;
|
||||
}), "size");
|
||||
@ -157,7 +157,12 @@ namespace chaiscript
|
||||
/// Internal function for converting from a string to a value
|
||||
/// uses ostream operator >> to perform the conversion
|
||||
template<typename Input>
|
||||
Input parse_string(const std::string &i)
|
||||
auto parse_string(const std::string &i)
|
||||
-> typename std::enable_if<
|
||||
!std::is_same<Input, wchar_t>::value
|
||||
&& !std::is_same<Input, char16_t>::value
|
||||
&& !std::is_same<Input, char32_t>::value,
|
||||
Input>::type
|
||||
{
|
||||
std::stringstream ss(i);
|
||||
Input t;
|
||||
@ -165,6 +170,17 @@ namespace chaiscript
|
||||
return t;
|
||||
}
|
||||
|
||||
template<typename Input>
|
||||
auto parse_string(const std::string &)
|
||||
-> typename std::enable_if<
|
||||
std::is_same<Input, wchar_t>::value
|
||||
|| std::is_same<Input, char16_t>::value
|
||||
|| std::is_same<Input, char32_t>::value,
|
||||
Input>::type
|
||||
{
|
||||
throw std::runtime_error("Parsing of wide characters is not yet supported");
|
||||
}
|
||||
|
||||
|
||||
/// Add all common functions for a POD type. All operators, and
|
||||
/// common conversions
|
||||
@ -175,11 +191,6 @@ namespace chaiscript
|
||||
m->add(constructor<T()>(), name);
|
||||
construct_pod<T>(name, m);
|
||||
|
||||
auto to_s = fun(&to_string<T>);
|
||||
|
||||
if (!m->has_function(to_s, "to_string")) {
|
||||
m->add(to_s, "to_string");
|
||||
}
|
||||
m->add(fun(&parse_string<T>), "to_" + name);
|
||||
return m;
|
||||
}
|
||||
@ -293,13 +304,17 @@ namespace chaiscript
|
||||
/// the remaining parameters are the args to bind into the result
|
||||
static Boxed_Value bind_function(const std::vector<Boxed_Value> ¶ms)
|
||||
{
|
||||
if (params.size() < 2)
|
||||
{
|
||||
throw exception::arity_error(static_cast<int>(params.size()), 2);
|
||||
if (params.empty()) {
|
||||
throw exception::arity_error(0, 1);
|
||||
}
|
||||
|
||||
Const_Proxy_Function f = boxed_cast<Const_Proxy_Function>(params[0]);
|
||||
|
||||
if (f->get_arity() != -1 && size_t(f->get_arity()) != params.size() - 1)
|
||||
{
|
||||
throw exception::arity_error(static_cast<int>(params.size()), f->get_arity());
|
||||
}
|
||||
|
||||
return Boxed_Value(Const_Proxy_Function(std::make_shared<dispatch::Bound_Function>(std::move(f),
|
||||
std::vector<Boxed_Value>(params.begin() + 1, params.end()))));
|
||||
}
|
||||
@ -408,6 +423,12 @@ namespace chaiscript
|
||||
m->add(fun(return_boxed_value_vector(&dispatch::Proxy_Function_Base::get_contained_functions)), "get_contained_functions");
|
||||
|
||||
|
||||
m->add(user_type<std::out_of_range>(), "out_of_range");
|
||||
m->add(user_type<std::logic_error>(), "logic_error");
|
||||
m->add(chaiscript::base_class<std::exception, std::logic_error>());
|
||||
m->add(chaiscript::base_class<std::logic_error, std::out_of_range>());
|
||||
m->add(chaiscript::base_class<std::exception, std::out_of_range>());
|
||||
|
||||
m->add(user_type<std::runtime_error>(), "runtime_error");
|
||||
m->add(chaiscript::base_class<std::exception, std::runtime_error>());
|
||||
|
||||
@ -465,12 +486,15 @@ namespace chaiscript
|
||||
operators::assign<bool>(m);
|
||||
operators::equal<bool>(m);
|
||||
|
||||
m->add(fun<std::string (const std::string &t_ss)>([](const std::string &s) -> std::string { return s; }), "to_string");
|
||||
m->add(fun([](const std::string &s) -> std::string { return s; }), "to_string");
|
||||
m->add(fun(&Bootstrap::bool_to_string), "to_string");
|
||||
m->add(fun(&unknown_assign), "=");
|
||||
m->add(fun(&throw_exception), "throw");
|
||||
m->add(fun(&what), "what");
|
||||
|
||||
m->add(fun(&to_string<char>), "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);
|
||||
@ -480,6 +504,9 @@ namespace chaiscript
|
||||
bootstrap_pod_type<unsigned long>("unsigned_long", m);
|
||||
bootstrap_pod_type<size_t>("size_t", m);
|
||||
bootstrap_pod_type<char>("char", m);
|
||||
bootstrap_pod_type<wchar_t>("wchar_t", m);
|
||||
bootstrap_pod_type<char16_t>("char16_t", m);
|
||||
bootstrap_pod_type<char32_t>("char32_t", m);
|
||||
bootstrap_pod_type<std::int8_t>("int8_t", m);
|
||||
bootstrap_pod_type<std::int16_t>("int16_t", m);
|
||||
bootstrap_pod_type<std::int32_t>("int32_t", m);
|
||||
@ -497,13 +524,13 @@ namespace chaiscript
|
||||
m->add(fun(&print), "print_string");
|
||||
m->add(fun(&println), "println_string");
|
||||
|
||||
m->add(chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Dynamic_Proxy_Function>(&bind_function), "bind");
|
||||
m->add(dispatch::make_dynamic_proxy_function(&bind_function), "bind");
|
||||
|
||||
m->add(fun(&shared_ptr_unconst_clone<dispatch::Proxy_Function_Base>), "clone");
|
||||
m->add(fun(&ptr_assign<std::remove_const<dispatch::Proxy_Function_Base>::type>), "=");
|
||||
m->add(fun(&ptr_assign<std::add_const<dispatch::Proxy_Function_Base>::type>), "=");
|
||||
m->add(chaiscript::base_class<dispatch::Proxy_Function_Base, dispatch::Assignable_Proxy_Function>());
|
||||
m->add(fun<void (dispatch::Assignable_Proxy_Function &, const std::shared_ptr<const dispatch::Proxy_Function_Base> &)>(
|
||||
m->add(fun(
|
||||
[](dispatch::Assignable_Proxy_Function &t_lhs, const std::shared_ptr<const dispatch::Proxy_Function_Base> &t_rhs) {
|
||||
t_lhs.assign(t_rhs);
|
||||
}
|
||||
|
@ -243,18 +243,18 @@ namespace chaiscript
|
||||
template<typename ContainerType>
|
||||
ModulePtr random_access_container_type(const std::string &/*type*/, ModulePtr m = std::make_shared<Module>())
|
||||
{
|
||||
// cppcheck-suppress syntaxError
|
||||
typedef typename ContainerType::reference(ContainerType::*indexoper)(size_t);
|
||||
|
||||
//In the interest of runtime safety for the m, we prefer the at() method for [] access,
|
||||
//to throw an exception in an out of bounds condition.
|
||||
m->add(
|
||||
fun(std::function<typename ContainerType::reference (ContainerType *, int)>
|
||||
(std::mem_fn(static_cast<indexoper>(&ContainerType::at)))), "[]");
|
||||
fun(
|
||||
[](ContainerType &c, int index) -> typename ContainerType::reference {
|
||||
return c.at(index);
|
||||
}), "[]");
|
||||
|
||||
m->add(
|
||||
fun<typename ContainerType::const_reference (const ContainerType *, int)>(
|
||||
[](const ContainerType *c, int index) -> typename ContainerType::const_reference {
|
||||
return c->at(index);
|
||||
fun(
|
||||
[](const ContainerType &c, int index) -> typename ContainerType::const_reference {
|
||||
return c.at(index);
|
||||
}), "[]");
|
||||
|
||||
return m;
|
||||
@ -277,9 +277,9 @@ namespace chaiscript
|
||||
template<typename ContainerType>
|
||||
ModulePtr container_type(const std::string &/*type*/, ModulePtr m = std::make_shared<Module>())
|
||||
{
|
||||
m->add(fun<size_t (const ContainerType *)>([](const ContainerType *a) { return a->size(); } ), "size");
|
||||
m->add(fun<bool (const ContainerType *)>([](const ContainerType *a) { return a->empty(); } ), "empty");
|
||||
m->add(fun<void (ContainerType *)>([](ContainerType *a) { a->clear(); } ), "clear");
|
||||
m->add(fun([](const ContainerType *a) { return a->size(); } ), "size");
|
||||
m->add(fun([](const ContainerType *a) { return a->empty(); } ), "empty");
|
||||
m->add(fun([](ContainerType *a) { a->clear(); } ), "clear");
|
||||
return m;
|
||||
}
|
||||
|
||||
@ -319,7 +319,7 @@ namespace chaiscript
|
||||
/// Add back insertion sequence concept to the given ContainerType
|
||||
/// http://www.sgi.com/tech/stl/BackInsertionSequence.html
|
||||
template<typename ContainerType>
|
||||
ModulePtr back_insertion_sequence_type(const std::string &/*type*/, ModulePtr m = std::make_shared<Module>())
|
||||
ModulePtr back_insertion_sequence_type(const std::string &type, ModulePtr m = std::make_shared<Module>())
|
||||
{
|
||||
typedef typename ContainerType::reference (ContainerType::*backptr)();
|
||||
|
||||
@ -328,8 +328,16 @@ namespace chaiscript
|
||||
|
||||
typedef void (ContainerType::*push_back)(const typename ContainerType::value_type &);
|
||||
m->add(fun(static_cast<push_back>(&ContainerType::push_back)),
|
||||
[]()->std::string{
|
||||
if (typeid(typename ContainerType::value_type) == typeid(Boxed_Value)) {
|
||||
[&]()->std::string{
|
||||
if (typeid(typename ContainerType::value_type) == typeid(Boxed_Value)) {
|
||||
m->eval(
|
||||
"# Pushes the second value onto the container while making a clone of the value\n"
|
||||
"def push_back(" + type + " container, x)\n"
|
||||
"{ \n"
|
||||
" container.push_back_ref(clone(x)) \n"
|
||||
"} \n"
|
||||
);
|
||||
|
||||
return "push_back_ref";
|
||||
} else {
|
||||
return "push_back";
|
||||
@ -345,7 +353,7 @@ namespace chaiscript
|
||||
/// Front insertion sequence
|
||||
/// http://www.sgi.com/tech/stl/FrontInsertionSequence.html
|
||||
template<typename ContainerType>
|
||||
ModulePtr front_insertion_sequence_type(const std::string &, ModulePtr m = std::make_shared<Module>())
|
||||
ModulePtr front_insertion_sequence_type(const std::string &type, ModulePtr m = std::make_shared<Module>())
|
||||
{
|
||||
typedef typename ContainerType::reference (ContainerType::*front_ptr)();
|
||||
typedef typename ContainerType::const_reference (ContainerType::*const_front_ptr)() const;
|
||||
@ -356,8 +364,15 @@ namespace chaiscript
|
||||
m->add(fun(static_cast<const_front_ptr>(&ContainerType::front)), "front");
|
||||
|
||||
m->add(fun(static_cast<push_ptr>(&ContainerType::push_front)),
|
||||
[]()->std::string{
|
||||
[&]()->std::string{
|
||||
if (typeid(typename ContainerType::value_type) == typeid(Boxed_Value)) {
|
||||
m->eval(
|
||||
"# Pushes the second value onto the front of container while making a clone of the value\n"
|
||||
"def push_front(" + type + " container, x)\n"
|
||||
"{ \n"
|
||||
" container.push_front_ref(clone(x)) \n"
|
||||
"} \n"
|
||||
);
|
||||
return "push_front_ref";
|
||||
} else {
|
||||
return "push_front";
|
||||
@ -438,9 +453,13 @@ namespace chaiscript
|
||||
m->add(user_type<MapType>(), type);
|
||||
|
||||
typedef typename MapType::mapped_type &(MapType::*elem_access)(const typename MapType::key_type &);
|
||||
typedef const typename MapType::mapped_type &(MapType::*const_elem_access)(const typename MapType::key_type &) const;
|
||||
|
||||
m->add(fun(static_cast<elem_access>(&MapType::operator[])), "[]");
|
||||
|
||||
m->add(fun(static_cast<elem_access>(&MapType::at)), "at");
|
||||
m->add(fun(static_cast<const_elem_access>(&MapType::at)), "at");
|
||||
|
||||
container_type<MapType>(type, m);
|
||||
default_constructible_type<MapType>(type, m);
|
||||
assignable_type<MapType>(type, m);
|
||||
@ -547,23 +566,20 @@ namespace chaiscript
|
||||
}());
|
||||
|
||||
|
||||
typedef std::function<size_t (const String *, const String &, size_t)> find_func;
|
||||
m->add(fun([](const String *s, const String &f, size_t pos) { return s->find(f, pos); } ), "find");
|
||||
m->add(fun([](const String *s, const String &f, size_t pos) { return s->rfind(f, pos); } ), "rfind");
|
||||
m->add(fun([](const String *s, const String &f, size_t pos) { return s->find_first_of(f, pos); } ), "find_first_of");
|
||||
m->add(fun([](const String *s, const String &f, size_t pos) { return s->find_last_of(f, pos); } ), "find_last_of");
|
||||
m->add(fun([](const String *s, const String &f, size_t pos) { return s->find_last_not_of(f, pos); } ), "find_last_not_of");
|
||||
m->add(fun([](const String *s, const String &f, size_t pos) { return s->find_first_not_of(f, pos); } ), "find_first_not_of");
|
||||
|
||||
m->add(fun([](String *s) { s->clear(); } ), "clear");
|
||||
m->add(fun([](const String *s) { return s->empty(); } ), "empty");
|
||||
m->add(fun([](const String *s) { return s->size(); } ), "size");
|
||||
|
||||
m->add(fun(find_func( [](const String *s, const String &f, size_t pos) { return s->find(f, pos); } )), "find");
|
||||
m->add(fun(find_func( [](const String *s, const String &f, size_t pos) { return s->rfind(f, pos); } ) ), "rfind");
|
||||
m->add(fun(find_func( [](const String *s, const String &f, size_t pos) { return s->find_first_of(f, pos); } ) ), "find_first_of");
|
||||
m->add(fun(find_func( [](const String *s, const String &f, size_t pos) { return s->find_last_of(f, pos); } ) ), "find_last_of");
|
||||
m->add(fun(find_func( [](const String *s, const String &f, size_t pos) { return s->find_last_not_of(f, pos); } ) ), "find_last_not_of");
|
||||
m->add(fun(find_func( [](const String *s, const String &f, size_t pos) { return s->find_first_not_of(f, pos); } ) ), "find_first_not_of");
|
||||
|
||||
m->add(fun( std::function<void (String *)>( [](String *s) { return s->clear(); } ) ), "clear");
|
||||
m->add(fun( std::function<bool (const String *)>( [](const String *s) { return s->empty(); } ) ), "empty");
|
||||
m->add(fun( std::function<size_t (const String *)>( [](const String *s) { return s->size(); } ) ), "size");
|
||||
|
||||
m->add(fun( std::function<const char *(const String *)>( [](const String *s) { return s->c_str(); } ) ), "c_str");
|
||||
m->add(fun( std::function<const char *(const String *)>( [](const String *s) { return s->data(); } ) ), "data");
|
||||
m->add(fun( std::function<String (const String *, size_t, size_t)>( [](const String *s, size_t pos, size_t len) { return s->substr(pos, len); } ) ), "substr");
|
||||
m->add(fun([](const String *s) { return s->c_str(); } ), "c_str");
|
||||
m->add(fun([](const String *s) { return s->data(); } ), "data");
|
||||
m->add(fun([](const String *s, size_t pos, size_t len) { return s->substr(pos, len); } ), "substr");
|
||||
|
||||
return m;
|
||||
}
|
||||
@ -577,7 +593,7 @@ namespace chaiscript
|
||||
{
|
||||
m->add(user_type<FutureType>(), type);
|
||||
|
||||
m->add(fun<bool (const FutureType &)>([](const FutureType &t) { return t.valid(); }), "valid");
|
||||
m->add(fun([](const FutureType &t) { return t.valid(); }), "valid");
|
||||
m->add(fun(&FutureType::get), "get");
|
||||
m->add(fun(&FutureType::wait), "wait");
|
||||
|
||||
|
@ -79,13 +79,6 @@ namespace chaiscript
|
||||
}
|
||||
|
||||
|
||||
#ifdef CHAISCRIPT_MSVC
|
||||
//Thank you MSVC, yes we know that a constant value is being used in the if
|
||||
// statment in THIS VERSION of the template instantiation
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4127)
|
||||
#endif
|
||||
|
||||
if (t_conversions && t_conversions->convertable_type<Type>())
|
||||
{
|
||||
try {
|
||||
@ -108,10 +101,6 @@ namespace chaiscript
|
||||
throw exception::bad_boxed_cast(bv.get_type_info(), typeid(Type));
|
||||
}
|
||||
|
||||
#ifdef CHAISCRIPT_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -58,6 +58,7 @@ namespace chaiscript
|
||||
{
|
||||
};
|
||||
|
||||
|
||||
/// Cast_Helper_Inner for casting to a const * type
|
||||
template<typename Result>
|
||||
struct Cast_Helper_Inner<const Result *>
|
||||
@ -81,11 +82,11 @@ namespace chaiscript
|
||||
typedef Result * Result_Type;
|
||||
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *)
|
||||
{
|
||||
if (ob.is_ref())
|
||||
if (!ob.get_type_info().is_const() && ob.get_type_info() == typeid(Result))
|
||||
{
|
||||
return &(ob.get().cast<std::reference_wrapper<Result> >()).get();
|
||||
return static_cast<Result *>(throw_if_null(ob.get_ptr()));
|
||||
} else {
|
||||
return (ob.get().cast<std::shared_ptr<Result> >()).get();
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -149,7 +150,6 @@ namespace chaiscript
|
||||
{
|
||||
};
|
||||
|
||||
|
||||
/// Cast_Helper_Inner for casting to a const std::shared_ptr<const> & type
|
||||
template<typename Result>
|
||||
struct Cast_Helper_Inner<const std::shared_ptr<const Result> > : Cast_Helper_Inner<std::shared_ptr<const Result> >
|
||||
@ -162,7 +162,6 @@ namespace chaiscript
|
||||
};
|
||||
|
||||
|
||||
|
||||
/// Cast_Helper_Inner for casting to a Boxed_Value type
|
||||
template<>
|
||||
struct Cast_Helper_Inner<Boxed_Value>
|
||||
|
@ -43,7 +43,7 @@ namespace chaiscript
|
||||
// this is OK, so we're disabling size/and sign type warnings
|
||||
#ifdef CHAISCRIPT_MSVC
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4244 4018 4389 4146 4365)
|
||||
#pragma warning(disable : 4244 4018 4389 4146 4365 4267)
|
||||
#endif
|
||||
|
||||
|
||||
@ -59,8 +59,22 @@ namespace chaiscript
|
||||
class Boxed_Number
|
||||
{
|
||||
private:
|
||||
enum class Common_Types {
|
||||
t_int32,
|
||||
t_double,
|
||||
t_uint8,
|
||||
t_int8,
|
||||
t_uint16,
|
||||
t_int16,
|
||||
t_uint32,
|
||||
t_uint64,
|
||||
t_int64,
|
||||
t_float,
|
||||
t_long_double
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
static void check_divide_by_zero(T t, typename std::enable_if<std::is_integral<T>::value>::type* = nullptr)
|
||||
static inline void check_divide_by_zero(T t, typename std::enable_if<std::is_integral<T>::value>::type* = nullptr)
|
||||
{
|
||||
#ifndef CHAISCRIPT_NO_PROTECT_DIVIDEBYZERO
|
||||
if (t == 0) {
|
||||
@ -70,292 +84,401 @@ namespace chaiscript
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static void check_divide_by_zero(T, typename std::enable_if<std::is_floating_point<T>::value>::type* = nullptr)
|
||||
static inline void check_divide_by_zero(T, typename std::enable_if<std::is_floating_point<T>::value>::type* = nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
struct boolean
|
||||
static CHAISCRIPT_CONSTEXPR Common_Types get_common_type(size_t t_size, bool t_signed)
|
||||
{
|
||||
return (t_size == 1 && t_signed)?(Common_Types::t_int8)
|
||||
:(t_size == 1)?(Common_Types::t_uint8)
|
||||
:(t_size == 2 && t_signed)?(Common_Types::t_int16)
|
||||
:(t_size == 2)?(Common_Types::t_uint16)
|
||||
:(t_size == 4 && t_signed)?(Common_Types::t_int32)
|
||||
:(t_size == 4)?(Common_Types::t_uint32)
|
||||
:(t_size == 8 && t_signed)?(Common_Types::t_int64)
|
||||
:(Common_Types::t_uint64);
|
||||
}
|
||||
|
||||
template<typename T, typename U>
|
||||
static Boxed_Value go(Operators::Opers t_oper, const T &t, const U &u, const Boxed_Value &)
|
||||
{
|
||||
switch (t_oper)
|
||||
{
|
||||
case Operators::equals:
|
||||
return const_var(t == u);
|
||||
case Operators::less_than:
|
||||
return const_var(t < u);
|
||||
case Operators::greater_than:
|
||||
return const_var(t > u);
|
||||
case Operators::less_than_equal:
|
||||
return const_var(t <= u);
|
||||
case Operators::greater_than_equal:
|
||||
return const_var(t >= u);
|
||||
case Operators::not_equal:
|
||||
return const_var(t != u);
|
||||
default:
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
}
|
||||
static Common_Types get_common_type(const Boxed_Value &t_bv)
|
||||
{
|
||||
const Type_Info &inp_ = t_bv.get_type_info();
|
||||
|
||||
if (inp_ == typeid(int)) {
|
||||
return get_common_type(sizeof(int), true);
|
||||
} else if (inp_ == typeid(double)) {
|
||||
return Common_Types::t_double;
|
||||
} else if (inp_ == typeid(long double)) {
|
||||
return Common_Types::t_long_double;
|
||||
} else if (inp_ == typeid(float)) {
|
||||
return Common_Types::t_float;
|
||||
} else if (inp_ == typeid(char)) {
|
||||
return get_common_type(sizeof(char), std::is_signed<char>::value);
|
||||
} else if (inp_ == typeid(unsigned char)) {
|
||||
return get_common_type(sizeof(unsigned char), false);
|
||||
} else if (inp_ == typeid(unsigned int)) {
|
||||
return get_common_type(sizeof(unsigned int), false);
|
||||
} else if (inp_ == typeid(long)) {
|
||||
return get_common_type(sizeof(long), true);
|
||||
} else if (inp_ == typeid(unsigned long)) {
|
||||
return get_common_type(sizeof(unsigned long), false);
|
||||
} else if (inp_ == typeid(std::int8_t)) {
|
||||
return Common_Types::t_int8;
|
||||
} else if (inp_ == typeid(std::int16_t)) {
|
||||
return Common_Types::t_int16;
|
||||
} else if (inp_ == typeid(std::int32_t)) {
|
||||
return Common_Types::t_int32;
|
||||
} else if (inp_ == typeid(std::int64_t)) {
|
||||
return Common_Types::t_int64;
|
||||
} else if (inp_ == typeid(std::uint8_t)) {
|
||||
return Common_Types::t_uint8;
|
||||
} else if (inp_ == typeid(std::uint16_t)) {
|
||||
return Common_Types::t_uint16;
|
||||
} else if (inp_ == typeid(std::uint32_t)) {
|
||||
return Common_Types::t_uint32;
|
||||
} else if (inp_ == typeid(std::uint64_t)) {
|
||||
return Common_Types::t_uint64;
|
||||
} else if (inp_ == typeid(wchar_t)) {
|
||||
return get_common_type(sizeof(wchar_t), std::is_signed<wchar_t>::value);
|
||||
} else if (inp_ == typeid(char16_t)) {
|
||||
return get_common_type(sizeof(char16_t), std::is_signed<char16_t>::value);
|
||||
} else if (inp_ == typeid(char32_t)) {
|
||||
return get_common_type(sizeof(char32_t), std::is_signed<char32_t>::value);
|
||||
} else {
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
struct binary
|
||||
template<typename T>
|
||||
static Boxed_Value boolean_go(Operators::Opers t_oper, const T &t, const T &u)
|
||||
{
|
||||
template<typename T, typename U>
|
||||
static Boxed_Value go(Operators::Opers t_oper, T &t, const U &u, const Boxed_Value &t_lhs)
|
||||
switch (t_oper)
|
||||
{
|
||||
switch (t_oper)
|
||||
{
|
||||
case Operators::assign:
|
||||
t = u;
|
||||
break;
|
||||
case Operators::pre_increment:
|
||||
++t;
|
||||
break;
|
||||
case Operators::pre_decrement:
|
||||
--t;
|
||||
break;
|
||||
case Operators::assign_product:
|
||||
t *= u;
|
||||
break;
|
||||
case Operators::assign_sum:
|
||||
t += u;
|
||||
break;
|
||||
case Operators::assign_quotient:
|
||||
check_divide_by_zero(u);
|
||||
t /= u;
|
||||
break;
|
||||
case Operators::assign_difference:
|
||||
t -= u;
|
||||
break;
|
||||
default:
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
}
|
||||
|
||||
return t_lhs;
|
||||
}
|
||||
};
|
||||
|
||||
struct binary_int
|
||||
{
|
||||
template<typename T, typename U>
|
||||
static Boxed_Value go(Operators::Opers t_oper, T &t, const U &u, const Boxed_Value &t_lhs)
|
||||
{
|
||||
switch (t_oper)
|
||||
{
|
||||
case Operators::assign_bitwise_and:
|
||||
t &= u;
|
||||
break;
|
||||
case Operators::assign_bitwise_or:
|
||||
t |= u;
|
||||
break;
|
||||
case Operators::assign_shift_left:
|
||||
t <<= u;
|
||||
break;
|
||||
case Operators::assign_shift_right:
|
||||
t >>= u;
|
||||
break;
|
||||
case Operators::assign_remainder:
|
||||
check_divide_by_zero(u);
|
||||
t %= u;
|
||||
break;
|
||||
case Operators::assign_bitwise_xor:
|
||||
t ^= u;
|
||||
break;
|
||||
default:
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
}
|
||||
return t_lhs;
|
||||
}
|
||||
};
|
||||
|
||||
struct const_binary_int
|
||||
{
|
||||
template<typename T, typename U>
|
||||
static Boxed_Value go(Operators::Opers t_oper, const T &t, const U &u, const Boxed_Value &)
|
||||
{
|
||||
switch (t_oper)
|
||||
{
|
||||
case Operators::shift_left:
|
||||
return const_var(t << u);
|
||||
case Operators::shift_right:
|
||||
return const_var(t >> u);
|
||||
case Operators::remainder:
|
||||
check_divide_by_zero(u);
|
||||
return const_var(t % u);
|
||||
case Operators::bitwise_and:
|
||||
return const_var(t & u);
|
||||
case Operators::bitwise_or:
|
||||
return const_var(t | u);
|
||||
case Operators::bitwise_xor:
|
||||
return const_var(t ^ u);
|
||||
case Operators::bitwise_complement:
|
||||
return const_var(~t);
|
||||
default:
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct const_binary
|
||||
{
|
||||
template<typename T, typename U>
|
||||
static Boxed_Value go(Operators::Opers t_oper, const T &t, const U &u, const Boxed_Value &)
|
||||
{
|
||||
switch (t_oper)
|
||||
{
|
||||
case Operators::sum:
|
||||
return const_var(t + u);
|
||||
case Operators::quotient:
|
||||
check_divide_by_zero(u);
|
||||
return const_var(t / u);
|
||||
case Operators::product:
|
||||
return const_var(t * u);
|
||||
case Operators::difference:
|
||||
return const_var(t - u);
|
||||
case Operators::unary_minus:
|
||||
return const_var(-t);
|
||||
case Operators::unary_plus:
|
||||
return const_var(+t);
|
||||
default:
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<typename LHS, typename RHS, bool Float>
|
||||
struct Go
|
||||
{
|
||||
static Boxed_Value go(Operators::Opers t_oper, const Boxed_Value &t_lhs, const Boxed_Value &t_rhs)
|
||||
{
|
||||
if (t_oper > Operators::boolean_flag && t_oper < Operators::non_const_flag)
|
||||
{
|
||||
return boolean::go<LHS, RHS>(t_oper, *static_cast<const LHS *>(t_lhs.get_const_ptr()), *static_cast<const RHS *>(t_rhs.get_const_ptr()), t_lhs);
|
||||
} else if (t_oper > Operators::non_const_flag && t_oper < Operators::non_const_int_flag && !t_lhs.is_const() && !t_lhs.is_return_value()) {
|
||||
return binary::go<LHS, RHS>(t_oper, *static_cast<LHS *>(t_lhs.get_ptr()), *static_cast<const RHS *>(t_rhs.get_const_ptr()), 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()) {
|
||||
return binary_int::go<LHS, RHS>(t_oper, *static_cast<LHS *>(t_lhs.get_ptr()), *static_cast<const RHS *>(t_rhs.get_const_ptr()), t_lhs);
|
||||
} else if (t_oper > Operators::const_int_flag && t_oper < Operators::const_flag) {
|
||||
return const_binary_int::go<LHS, RHS>(t_oper, *static_cast<const LHS *>(t_lhs.get_const_ptr()), *static_cast<const RHS *>(t_rhs.get_const_ptr()), t_lhs);
|
||||
} else if (t_oper > Operators::const_flag) {
|
||||
return const_binary::go<LHS, RHS>(t_oper, *static_cast<const LHS *>(t_lhs.get_const_ptr()), *static_cast<const RHS *>(t_rhs.get_const_ptr()), t_lhs);
|
||||
} else {
|
||||
case Operators::equals:
|
||||
return const_var(t == u);
|
||||
case Operators::less_than:
|
||||
return const_var(t < u);
|
||||
case Operators::greater_than:
|
||||
return const_var(t > u);
|
||||
case Operators::less_than_equal:
|
||||
return const_var(t <= u);
|
||||
case Operators::greater_than_equal:
|
||||
return const_var(t >= u);
|
||||
case Operators::not_equal:
|
||||
return const_var(t != u);
|
||||
default:
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static Boxed_Value unary_go(Operators::Opers t_oper, T &t, const Boxed_Value &t_lhs)
|
||||
{
|
||||
switch (t_oper)
|
||||
{
|
||||
case Operators::pre_increment:
|
||||
++t;
|
||||
break;
|
||||
case Operators::pre_decrement:
|
||||
--t;
|
||||
break;
|
||||
default:
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
}
|
||||
|
||||
return t_lhs;
|
||||
}
|
||||
|
||||
template<typename T, typename U>
|
||||
static Boxed_Value binary_go(Operators::Opers t_oper, T &t, const U &u, const Boxed_Value &t_lhs)
|
||||
{
|
||||
switch (t_oper)
|
||||
{
|
||||
case Operators::assign:
|
||||
t = u;
|
||||
break;
|
||||
case Operators::assign_product:
|
||||
t *= u;
|
||||
break;
|
||||
case Operators::assign_sum:
|
||||
t += u;
|
||||
break;
|
||||
case Operators::assign_quotient:
|
||||
check_divide_by_zero(u);
|
||||
t /= u;
|
||||
break;
|
||||
case Operators::assign_difference:
|
||||
t -= u;
|
||||
break;
|
||||
default:
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
}
|
||||
|
||||
return t_lhs;
|
||||
}
|
||||
|
||||
template<typename T, typename U>
|
||||
static Boxed_Value binary_int_go(Operators::Opers t_oper, T &t, const U &u, const Boxed_Value &t_lhs)
|
||||
{
|
||||
switch (t_oper)
|
||||
{
|
||||
case Operators::assign_bitwise_and:
|
||||
t &= u;
|
||||
break;
|
||||
case Operators::assign_bitwise_or:
|
||||
t |= u;
|
||||
break;
|
||||
case Operators::assign_shift_left:
|
||||
t <<= u;
|
||||
break;
|
||||
case Operators::assign_shift_right:
|
||||
t >>= u;
|
||||
break;
|
||||
case Operators::assign_remainder:
|
||||
check_divide_by_zero(u);
|
||||
t %= u;
|
||||
break;
|
||||
case Operators::assign_bitwise_xor:
|
||||
t ^= u;
|
||||
break;
|
||||
default:
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
}
|
||||
return t_lhs;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static Boxed_Value const_unary_int_go(Operators::Opers t_oper, const T &t)
|
||||
{
|
||||
switch (t_oper)
|
||||
{
|
||||
case Operators::bitwise_complement:
|
||||
return const_var(~t);
|
||||
default:
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static Boxed_Value const_binary_int_go(Operators::Opers t_oper, const T &t, const T &u)
|
||||
{
|
||||
switch (t_oper)
|
||||
{
|
||||
case Operators::shift_left:
|
||||
return const_var(t << u);
|
||||
case Operators::shift_right:
|
||||
return const_var(t >> u);
|
||||
case Operators::remainder:
|
||||
check_divide_by_zero(u);
|
||||
return const_var(t % u);
|
||||
case Operators::bitwise_and:
|
||||
return const_var(t & u);
|
||||
case Operators::bitwise_or:
|
||||
return const_var(t | u);
|
||||
case Operators::bitwise_xor:
|
||||
return const_var(t ^ u);
|
||||
default:
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static Boxed_Value const_unary_go(Operators::Opers t_oper, const T &t)
|
||||
{
|
||||
switch (t_oper)
|
||||
{
|
||||
case Operators::unary_minus:
|
||||
return const_var(-t);
|
||||
case Operators::unary_plus:
|
||||
return const_var(+t);
|
||||
default:
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static Boxed_Value const_binary_go(Operators::Opers t_oper, const T &t, const T &u)
|
||||
{
|
||||
switch (t_oper)
|
||||
{
|
||||
case Operators::sum:
|
||||
return const_var(t + u);
|
||||
case Operators::quotient:
|
||||
check_divide_by_zero(u);
|
||||
return const_var(t / u);
|
||||
case Operators::product:
|
||||
return const_var(t * u);
|
||||
case Operators::difference:
|
||||
return const_var(t - u);
|
||||
default:
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
}
|
||||
}
|
||||
|
||||
template<typename LHS, typename RHS>
|
||||
struct Go<LHS, RHS, true>
|
||||
static auto go(Operators::Opers t_oper, const Boxed_Value &t_lhs, const Boxed_Value &t_rhs)
|
||||
-> typename std::enable_if<!std::is_floating_point<LHS>::value && !std::is_floating_point<RHS>::value, Boxed_Value>::type
|
||||
{
|
||||
static Boxed_Value go(Operators::Opers t_oper, const Boxed_Value &t_lhs, const Boxed_Value &t_rhs)
|
||||
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::boolean_flag && t_oper < Operators::non_const_flag)
|
||||
{
|
||||
return boolean::go<LHS, RHS>(t_oper, *static_cast<const LHS *>(t_lhs.get_const_ptr()), *static_cast<const RHS *>(t_rhs.get_const_ptr()), t_lhs);
|
||||
} else if (t_oper > Operators::non_const_flag && t_oper < Operators::non_const_int_flag && !t_lhs.is_const() && !t_lhs.is_return_value()) {
|
||||
return binary::go<LHS, RHS>(t_oper, *static_cast<LHS *>(t_lhs.get_ptr()), *static_cast<const RHS *>(t_rhs.get_const_ptr()), t_lhs);
|
||||
} else if (t_oper > Operators::non_const_int_flag && t_oper < Operators::const_int_flag) {
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
} else if (t_oper > Operators::const_int_flag && t_oper < Operators::const_flag) {
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
} else if (t_oper > Operators::const_flag) {
|
||||
return const_binary::go<LHS, RHS>(t_oper, *static_cast<const LHS *>(t_lhs.get_const_ptr()), *static_cast<const RHS *>(t_rhs.get_const_ptr()), t_lhs);
|
||||
} else {
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
}
|
||||
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()) {
|
||||
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()) {
|
||||
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) {
|
||||
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) {
|
||||
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();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
template<typename LHS, bool Float>
|
||||
static Boxed_Value oper_rhs(Operators::Opers t_oper, const Boxed_Value &t_lhs, const Boxed_Value &t_rhs)
|
||||
template<typename LHS, typename RHS>
|
||||
static auto go(Operators::Opers t_oper, const Boxed_Value &t_lhs, const Boxed_Value &t_rhs)
|
||||
-> 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)
|
||||
{
|
||||
const auto &inp_ = t_rhs.get_type_info();
|
||||
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()) {
|
||||
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) {
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
if (inp_ == typeid(int)) {
|
||||
return Go<LHS, int, Float>::go(t_oper, t_lhs, t_rhs);
|
||||
} else if (inp_ == typeid(double)) {
|
||||
return Go<LHS, double, true>::go(t_oper, t_lhs, t_rhs);
|
||||
} else if (inp_ == typeid(float)) {
|
||||
return Go<LHS, float, true>::go(t_oper, t_lhs, t_rhs);
|
||||
} else if (inp_ == typeid(long double)) {
|
||||
return Go<LHS, long double, true>::go(t_oper, t_lhs, t_rhs);
|
||||
} else if (inp_ == typeid(char)) {
|
||||
return Go<LHS, char, Float>::go(t_oper, t_lhs, t_rhs);
|
||||
} else if (inp_ == typeid(unsigned int)) {
|
||||
return Go<LHS, unsigned int, Float>::go(t_oper, t_lhs, t_rhs);
|
||||
} else if (inp_ == typeid(long)) {
|
||||
return Go<LHS, long, Float>::go(t_oper, t_lhs, t_rhs);
|
||||
} else if (inp_ == typeid(unsigned long)) {
|
||||
return Go<LHS, unsigned long, Float>::go(t_oper, t_lhs, t_rhs);
|
||||
} else if (inp_ == typeid(std::int8_t)) {
|
||||
return Go<LHS, std::int8_t, Float>::go(t_oper, t_lhs, t_rhs);
|
||||
} else if (inp_ == typeid(std::int16_t)) {
|
||||
return Go<LHS, std::int16_t, Float>::go(t_oper, t_lhs, t_rhs);
|
||||
} else if (inp_ == typeid(std::int32_t)) {
|
||||
return Go<LHS, std::int32_t, Float>::go(t_oper, t_lhs, t_rhs);
|
||||
} else if (inp_ == typeid(std::int64_t)) {
|
||||
return Go<LHS, std::int64_t, Float>::go(t_oper, t_lhs, t_rhs);
|
||||
} else if (inp_ == typeid(std::uint8_t)) {
|
||||
return Go<LHS, std::uint8_t, Float>::go(t_oper, t_lhs, t_rhs);
|
||||
} else if (inp_ == typeid(std::uint16_t)) {
|
||||
return Go<LHS, std::uint16_t, Float>::go(t_oper, t_lhs, t_rhs);
|
||||
} else if (inp_ == typeid(std::uint32_t)) {
|
||||
return Go<LHS, std::uint32_t, Float>::go(t_oper, t_lhs, t_rhs);
|
||||
} else if (inp_ == typeid(std::uint64_t)) {
|
||||
return Go<LHS, std::uint64_t, Float>::go(t_oper, t_lhs, t_rhs);
|
||||
} else {
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
}
|
||||
}
|
||||
// Unary
|
||||
template<typename LHS>
|
||||
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()) {
|
||||
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) {
|
||||
return const_unary_int_go(t_oper, *static_cast<const LHS *>(t_lhs.get_const_ptr()));
|
||||
} else if (t_oper > Operators::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();
|
||||
}
|
||||
}
|
||||
|
||||
static Boxed_Value oper(Operators::Opers t_oper, const Boxed_Value &t_lhs, const Boxed_Value &t_rhs)
|
||||
template<typename LHS>
|
||||
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()) {
|
||||
return unary_go(t_oper, *static_cast<LHS *>(t_lhs.get_ptr()), t_lhs);
|
||||
} else if (t_oper > Operators::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();
|
||||
}
|
||||
}
|
||||
|
||||
template<typename LHS>
|
||||
inline static Boxed_Value oper_rhs(Operators::Opers t_oper, const Boxed_Value &t_lhs, const Boxed_Value &t_rhs)
|
||||
{
|
||||
const Type_Info &inp_ = t_lhs.get_type_info();
|
||||
|
||||
if (inp_ == typeid(int)) {
|
||||
return oper_rhs<int, false>(t_oper, t_lhs, t_rhs);
|
||||
} else if (inp_ == typeid(double)) {
|
||||
return oper_rhs<double, true>(t_oper, t_lhs, t_rhs);
|
||||
} else if (inp_ == typeid(long double)) {
|
||||
return oper_rhs<long double, true>(t_oper, t_lhs, t_rhs);
|
||||
} else if (inp_ == typeid(float)) {
|
||||
return oper_rhs<float, true>(t_oper, t_lhs, t_rhs);
|
||||
} else if (inp_ == typeid(char)) {
|
||||
return oper_rhs<char, false>(t_oper, t_lhs, t_rhs);
|
||||
} else if (inp_ == typeid(unsigned int)) {
|
||||
return oper_rhs<unsigned int, false>(t_oper, t_lhs, t_rhs);
|
||||
} else if (inp_ == typeid(long)) {
|
||||
return oper_rhs<long, false>(t_oper, t_lhs, t_rhs);
|
||||
} else if (inp_ == typeid(unsigned long)) {
|
||||
return oper_rhs<unsigned long, false>(t_oper, t_lhs, t_rhs);
|
||||
} else if (inp_ == typeid(std::int8_t)) {
|
||||
return oper_rhs<std::int8_t, false>(t_oper, t_lhs, t_rhs);
|
||||
} else if (inp_ == typeid(std::int16_t)) {
|
||||
return oper_rhs<std::int16_t, false>(t_oper, t_lhs, t_rhs);
|
||||
} else if (inp_ == typeid(std::int32_t)) {
|
||||
return oper_rhs<std::int32_t, false>(t_oper, t_lhs, t_rhs);
|
||||
} else if (inp_ == typeid(std::int64_t)) {
|
||||
return oper_rhs<std::int64_t, false>(t_oper, t_lhs, t_rhs);
|
||||
} else if (inp_ == typeid(std::uint8_t)) {
|
||||
return oper_rhs<std::uint8_t, false>(t_oper, t_lhs, t_rhs);
|
||||
} else if (inp_ == typeid(std::uint16_t)) {
|
||||
return oper_rhs<std::uint16_t, false>(t_oper, t_lhs, t_rhs);
|
||||
} else if (inp_ == typeid(std::uint32_t)) {
|
||||
return oper_rhs<std::uint32_t, false>(t_oper, t_lhs, t_rhs);
|
||||
} else if (inp_ == typeid(std::uint64_t)) {
|
||||
return oper_rhs<std::uint64_t, false>(t_oper, t_lhs, t_rhs);
|
||||
} else {
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
switch (get_common_type(t_rhs)) {
|
||||
case Common_Types::t_int32:
|
||||
return go<LHS, int32_t>(t_oper, t_lhs, t_rhs);
|
||||
case Common_Types::t_uint8:
|
||||
return go<LHS, uint8_t>(t_oper, t_lhs, t_rhs);
|
||||
case Common_Types::t_int8:
|
||||
return go<LHS, int8_t>(t_oper, t_lhs, t_rhs);
|
||||
case Common_Types::t_uint16:
|
||||
return go<LHS, uint16_t>(t_oper, t_lhs, t_rhs);
|
||||
case Common_Types::t_int16:
|
||||
return go<LHS, int16_t>(t_oper, t_lhs, t_rhs);
|
||||
case Common_Types::t_uint32:
|
||||
return go<LHS, uint32_t>(t_oper, t_lhs, t_rhs);
|
||||
case Common_Types::t_uint64:
|
||||
return go<LHS, uint64_t>(t_oper, t_lhs, t_rhs);
|
||||
case Common_Types::t_int64:
|
||||
return go<LHS, int64_t>(t_oper, t_lhs, t_rhs);
|
||||
case Common_Types::t_double:
|
||||
return go<LHS, double>(t_oper, t_lhs, t_rhs);
|
||||
case Common_Types::t_float:
|
||||
return go<LHS, float>(t_oper, t_lhs, t_rhs);
|
||||
case Common_Types::t_long_double:
|
||||
return go<LHS, long double>(t_oper, t_lhs, t_rhs);
|
||||
}
|
||||
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
}
|
||||
|
||||
inline static Boxed_Value oper(Operators::Opers t_oper, const Boxed_Value &t_lhs)
|
||||
{
|
||||
switch (get_common_type(t_lhs)) {
|
||||
case Common_Types::t_int32:
|
||||
return go<int32_t>(t_oper, t_lhs);
|
||||
case Common_Types::t_uint8:
|
||||
return go<uint8_t>(t_oper, t_lhs);
|
||||
case Common_Types::t_int8:
|
||||
return go<int8_t>(t_oper, t_lhs);
|
||||
case Common_Types::t_uint16:
|
||||
return go<uint16_t>(t_oper, t_lhs);
|
||||
case Common_Types::t_int16:
|
||||
return go<int16_t>(t_oper, t_lhs);
|
||||
case Common_Types::t_uint32:
|
||||
return go<uint32_t>(t_oper, t_lhs);
|
||||
case Common_Types::t_uint64:
|
||||
return go<uint64_t>(t_oper, t_lhs);
|
||||
case Common_Types::t_int64:
|
||||
return go<int64_t>(t_oper, t_lhs);
|
||||
case Common_Types::t_double:
|
||||
return go<double>(t_oper, t_lhs);
|
||||
case Common_Types::t_float:
|
||||
return go<float>(t_oper, t_lhs);
|
||||
case Common_Types::t_long_double:
|
||||
return go<long double>(t_oper, t_lhs);
|
||||
}
|
||||
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
}
|
||||
|
||||
|
||||
inline static Boxed_Value oper(Operators::Opers t_oper, const Boxed_Value &t_lhs, const Boxed_Value &t_rhs)
|
||||
{
|
||||
switch (get_common_type(t_lhs)) {
|
||||
case Common_Types::t_int32:
|
||||
return oper_rhs<int32_t>(t_oper, t_lhs, t_rhs);
|
||||
case Common_Types::t_uint8:
|
||||
return oper_rhs<uint8_t>(t_oper, t_lhs, t_rhs);
|
||||
case Common_Types::t_int8:
|
||||
return oper_rhs<int8_t>(t_oper, t_lhs, t_rhs);
|
||||
case Common_Types::t_uint16:
|
||||
return oper_rhs<uint16_t>(t_oper, t_lhs, t_rhs);
|
||||
case Common_Types::t_int16:
|
||||
return oper_rhs<int16_t>(t_oper, t_lhs, t_rhs);
|
||||
case Common_Types::t_uint32:
|
||||
return oper_rhs<uint32_t>(t_oper, t_lhs, t_rhs);
|
||||
case Common_Types::t_uint64:
|
||||
return oper_rhs<uint64_t>(t_oper, t_lhs, t_rhs);
|
||||
case Common_Types::t_int64:
|
||||
return oper_rhs<int64_t>(t_oper, t_lhs, t_rhs);
|
||||
case Common_Types::t_double:
|
||||
return oper_rhs<double>(t_oper, t_lhs, t_rhs);
|
||||
case Common_Types::t_float:
|
||||
return oper_rhs<float>(t_oper, t_lhs, t_rhs);
|
||||
case Common_Types::t_long_double:
|
||||
return oper_rhs<long double>(t_oper, t_lhs, t_rhs);
|
||||
}
|
||||
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
}
|
||||
|
||||
template<typename Target, typename Source>
|
||||
Target get_as_aux() const
|
||||
{
|
||||
return static_cast<Target>(*static_cast<const Source *>(bv.get_const_ptr()));
|
||||
}
|
||||
static inline Target get_as_aux(const Boxed_Value &t_bv)
|
||||
{
|
||||
return static_cast<Target>(*static_cast<const Source *>(t_bv.get_const_ptr()));
|
||||
}
|
||||
|
||||
template<typename Source>
|
||||
static std::string to_string_aux(const Boxed_Value &v)
|
||||
@ -402,6 +525,14 @@ namespace chaiscript
|
||||
return Boxed_Number(get_as<long double>());
|
||||
} else if (inp_.bare_equal_type_info(typeid(char))) {
|
||||
return Boxed_Number(get_as<char>());
|
||||
} else if (inp_.bare_equal_type_info(typeid(unsigned char))) {
|
||||
return Boxed_Number(get_as<unsigned char>());
|
||||
} else if (inp_.bare_equal_type_info(typeid(wchar_t))) {
|
||||
return Boxed_Number(get_as<wchar_t>());
|
||||
} else if (inp_.bare_equal_type_info(typeid(char16_t))) {
|
||||
return Boxed_Number(get_as<char16_t>());
|
||||
} else if (inp_.bare_equal_type_info(typeid(char32_t))) {
|
||||
return Boxed_Number(get_as<char32_t>());
|
||||
} else if (inp_.bare_equal_type_info(typeid(unsigned int))) {
|
||||
return Boxed_Number(get_as<unsigned int>());
|
||||
} else if (inp_.bare_equal_type_info(typeid(long))) {
|
||||
@ -432,84 +563,62 @@ namespace chaiscript
|
||||
|
||||
template<typename Target> Target get_as() const
|
||||
{
|
||||
const Type_Info &inp_ = bv.get_type_info();
|
||||
|
||||
if (inp_ == typeid(int)) {
|
||||
return get_as_aux<Target, int>();
|
||||
} else if (inp_ == typeid(double)) {
|
||||
return get_as_aux<Target, double>();
|
||||
} else if (inp_ == typeid(float)) {
|
||||
return get_as_aux<Target, float>();
|
||||
} else if (inp_ == typeid(long double)) {
|
||||
return get_as_aux<Target, long double>();
|
||||
} else if (inp_ == typeid(char)) {
|
||||
return get_as_aux<Target, char>();
|
||||
} else if (inp_ == typeid(unsigned int)) {
|
||||
return get_as_aux<Target, unsigned int>();
|
||||
} else if (inp_ == typeid(long)) {
|
||||
return get_as_aux<Target, long>();
|
||||
} else if (inp_ == typeid(unsigned long)) {
|
||||
return get_as_aux<Target, unsigned long>();
|
||||
} else if (inp_ == typeid(std::int8_t)) {
|
||||
return get_as_aux<Target, std::int8_t>();
|
||||
} else if (inp_ == typeid(std::int16_t)) {
|
||||
return get_as_aux<Target, std::int16_t>();
|
||||
} else if (inp_ == typeid(std::int32_t)) {
|
||||
return get_as_aux<Target, std::int32_t>();
|
||||
} else if (inp_ == typeid(std::int64_t)) {
|
||||
return get_as_aux<Target, std::int64_t>();
|
||||
} else if (inp_ == typeid(std::uint8_t)) {
|
||||
return get_as_aux<Target, std::uint8_t>();
|
||||
} else if (inp_ == typeid(std::uint16_t)) {
|
||||
return get_as_aux<Target, std::uint16_t>();
|
||||
} else if (inp_ == typeid(std::uint32_t)) {
|
||||
return get_as_aux<Target, std::uint32_t>();
|
||||
} else if (inp_ == typeid(std::uint64_t)) {
|
||||
return get_as_aux<Target, std::uint64_t>();
|
||||
} else {
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
switch (get_common_type(bv)) {
|
||||
case Common_Types::t_int32:
|
||||
return get_as_aux<Target, int32_t>(bv);
|
||||
case Common_Types::t_uint8:
|
||||
return get_as_aux<Target, uint8_t>(bv);
|
||||
case Common_Types::t_int8:
|
||||
return get_as_aux<Target, int8_t>(bv);
|
||||
case Common_Types::t_uint16:
|
||||
return get_as_aux<Target, uint16_t>(bv);
|
||||
case Common_Types::t_int16:
|
||||
return get_as_aux<Target, int16_t>(bv);
|
||||
case Common_Types::t_uint32:
|
||||
return get_as_aux<Target, uint32_t>(bv);
|
||||
case Common_Types::t_uint64:
|
||||
return get_as_aux<Target, uint64_t>(bv);
|
||||
case Common_Types::t_int64:
|
||||
return get_as_aux<Target, int64_t>(bv);
|
||||
case Common_Types::t_double:
|
||||
return get_as_aux<Target, double>(bv);
|
||||
case Common_Types::t_float:
|
||||
return get_as_aux<Target, float>(bv);
|
||||
case Common_Types::t_long_double:
|
||||
return get_as_aux<Target, long double>(bv);
|
||||
}
|
||||
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
}
|
||||
|
||||
std::string to_string() const
|
||||
{
|
||||
const Type_Info &inp_ = bv.get_type_info();
|
||||
|
||||
if (inp_ == typeid(int)) {
|
||||
return to_string_aux<int>(bv);
|
||||
} else if (inp_ == typeid(double)) {
|
||||
return to_string_aux<double>(bv);
|
||||
} else if (inp_ == typeid(float)) {
|
||||
return to_string_aux<float>(bv);
|
||||
} else if (inp_ == typeid(long double)) {
|
||||
return to_string_aux<long double>(bv);
|
||||
} else if (inp_ == typeid(char)) {
|
||||
return to_string_aux<int>(Boxed_Value(get_as_aux<int, char>()));
|
||||
} else if (inp_ == typeid(unsigned int)) {
|
||||
return to_string_aux<unsigned int>(bv);
|
||||
} else if (inp_ == typeid(long)) {
|
||||
return to_string_aux<long>(bv);
|
||||
} else if (inp_ == typeid(unsigned long)) {
|
||||
return to_string_aux<unsigned long>(bv);
|
||||
} else if (inp_ == typeid(std::int8_t)) {
|
||||
return to_string_aux<int>(Boxed_Value(get_as_aux<int, std::int8_t>()));
|
||||
} else if (inp_ == typeid(std::int16_t)) {
|
||||
return to_string_aux<std::int16_t>(bv);
|
||||
} else if (inp_ == typeid(std::int32_t)) {
|
||||
return to_string_aux<std::int32_t>(bv);
|
||||
} else if (inp_ == typeid(std::int64_t)) {
|
||||
return to_string_aux<std::int64_t>(bv);
|
||||
} else if (inp_ == typeid(std::uint8_t)) {
|
||||
return to_string_aux<unsigned int>(Boxed_Value(get_as_aux<unsigned int, std::uint8_t>()));
|
||||
} else if (inp_ == typeid(std::uint16_t)) {
|
||||
return to_string_aux<std::uint16_t>(bv);
|
||||
} else if (inp_ == typeid(std::uint32_t)) {
|
||||
return to_string_aux<std::uint32_t>(bv);
|
||||
} else if (inp_ == typeid(std::uint64_t)) {
|
||||
return to_string_aux<std::uint64_t>(bv);
|
||||
} else {
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
switch (get_common_type(bv)) {
|
||||
case Common_Types::t_int32:
|
||||
return std::to_string(get_as<int32_t>());
|
||||
case Common_Types::t_uint8:
|
||||
return std::to_string(get_as<uint32_t>());
|
||||
case Common_Types::t_int8:
|
||||
return std::to_string(get_as<int32_t>());
|
||||
case Common_Types::t_uint16:
|
||||
return std::to_string(get_as<uint16_t>());
|
||||
case Common_Types::t_int16:
|
||||
return std::to_string(get_as<int16_t>());
|
||||
case Common_Types::t_uint32:
|
||||
return std::to_string(get_as<uint32_t>());
|
||||
case Common_Types::t_uint64:
|
||||
return std::to_string(get_as<uint64_t>());
|
||||
case Common_Types::t_int64:
|
||||
return std::to_string(get_as<int64_t>());
|
||||
case Common_Types::t_double:
|
||||
return to_string_aux<double>(bv);
|
||||
case Common_Types::t_float:
|
||||
return to_string_aux<float>(bv);
|
||||
case Common_Types::t_long_double:
|
||||
return to_string_aux<long double>(bv);
|
||||
}
|
||||
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
}
|
||||
|
||||
bool operator==(const Boxed_Number &t_rhs) const
|
||||
@ -544,12 +653,12 @@ namespace chaiscript
|
||||
|
||||
Boxed_Number operator--()
|
||||
{
|
||||
return oper(Operators::pre_decrement, this->bv, var(0));
|
||||
return oper(Operators::pre_decrement, this->bv);
|
||||
}
|
||||
|
||||
Boxed_Number operator++()
|
||||
{
|
||||
return oper(Operators::pre_increment, this->bv, var(0));
|
||||
return oper(Operators::pre_increment, this->bv);
|
||||
}
|
||||
|
||||
Boxed_Number operator+(const Boxed_Number &t_rhs) const
|
||||
@ -559,12 +668,12 @@ namespace chaiscript
|
||||
|
||||
Boxed_Number operator+() const
|
||||
{
|
||||
return oper(Operators::unary_plus, this->bv, Boxed_Value(0));
|
||||
return oper(Operators::unary_plus, this->bv);
|
||||
}
|
||||
|
||||
Boxed_Number operator-() const
|
||||
{
|
||||
return oper(Operators::unary_minus, this->bv, Boxed_Value(0));
|
||||
return oper(Operators::unary_minus, this->bv);
|
||||
}
|
||||
|
||||
Boxed_Number operator-(const Boxed_Number &t_rhs) const
|
||||
@ -637,7 +746,7 @@ namespace chaiscript
|
||||
|
||||
Boxed_Number operator~() const
|
||||
{
|
||||
return oper(Operators::bitwise_complement, this->bv, Boxed_Value(0));
|
||||
return oper(Operators::bitwise_complement, this->bv);
|
||||
}
|
||||
|
||||
Boxed_Number operator^(const Boxed_Number &t_rhs) const
|
||||
@ -726,12 +835,12 @@ namespace chaiscript
|
||||
|
||||
static Boxed_Number pre_decrement(Boxed_Number t_lhs)
|
||||
{
|
||||
return oper(Operators::pre_decrement, t_lhs.bv, var(0));
|
||||
return oper(Operators::pre_decrement, t_lhs.bv);
|
||||
}
|
||||
|
||||
static Boxed_Number pre_increment(Boxed_Number t_lhs)
|
||||
{
|
||||
return oper(Operators::pre_increment, t_lhs.bv, var(0));
|
||||
return oper(Operators::pre_increment, t_lhs.bv);
|
||||
}
|
||||
|
||||
static const Boxed_Number sum(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs)
|
||||
@ -741,12 +850,12 @@ namespace chaiscript
|
||||
|
||||
static const Boxed_Number unary_plus(const Boxed_Number &t_lhs)
|
||||
{
|
||||
return oper(Operators::unary_plus, t_lhs.bv, Boxed_Value(0));
|
||||
return oper(Operators::unary_plus, t_lhs.bv);
|
||||
}
|
||||
|
||||
static const Boxed_Number unary_minus(const Boxed_Number &t_lhs)
|
||||
{
|
||||
return oper(Operators::unary_minus, t_lhs.bv, Boxed_Value(0));
|
||||
return oper(Operators::unary_minus, t_lhs.bv);
|
||||
}
|
||||
|
||||
static const Boxed_Number difference(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs)
|
||||
@ -862,7 +971,7 @@ namespace chaiscript
|
||||
|
||||
static Boxed_Value do_oper(Operators::Opers t_oper, const Boxed_Value &t_lhs)
|
||||
{
|
||||
return oper(t_oper, t_lhs, const_var(0));
|
||||
return oper(t_oper, t_lhs);
|
||||
}
|
||||
|
||||
|
||||
|
96
include/chaiscript/dispatchkit/callable_traits.hpp
Normal file
96
include/chaiscript/dispatchkit/callable_traits.hpp
Normal file
@ -0,0 +1,96 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#ifndef CHAISCRIPT_CALLABLE_TRAITS_HPP_
|
||||
#define CHAISCRIPT_CALLABLE_TRAITS_HPP_
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace chaiscript {
|
||||
namespace dispatch {
|
||||
namespace detail {
|
||||
|
||||
template<typename Class, typename ... Param>
|
||||
struct Constructor
|
||||
{
|
||||
template<typename ... Inner>
|
||||
std::shared_ptr<Class> operator()(Inner&& ... inner) const {
|
||||
return std::make_shared<Class>(std::forward<Inner>(inner)...);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Ret, typename Class, typename ... Param>
|
||||
struct Const_Caller
|
||||
{
|
||||
Const_Caller(Ret (Class::*t_func)(Param...) const) : m_func(t_func) {}
|
||||
|
||||
template<typename ... Inner>
|
||||
Ret operator()(const Class &o, Inner&& ... inner) const {
|
||||
return (o.*m_func)(std::forward<Inner>(inner)...);
|
||||
}
|
||||
|
||||
Ret (Class::*m_func)(Param...) const;
|
||||
};
|
||||
|
||||
template<typename Ret, typename ... Param>
|
||||
struct Fun_Caller
|
||||
{
|
||||
Fun_Caller(Ret( * t_func)(Param...) ) : m_func(t_func) {}
|
||||
|
||||
template<typename ... Inner>
|
||||
Ret operator()(Inner&& ... inner) const {
|
||||
return (m_func)(std::forward<Inner>(inner)...);
|
||||
}
|
||||
|
||||
Ret(*m_func)(Param...);
|
||||
};
|
||||
|
||||
template<typename Ret, typename Class, typename ... Param>
|
||||
struct Caller
|
||||
{
|
||||
Caller(Ret (Class::*t_func)(Param...)) : m_func(t_func) {}
|
||||
|
||||
template<typename ... Inner>
|
||||
Ret operator()(Class &o, Inner&& ... inner) const {
|
||||
return (o.*m_func)(std::forward<Inner>(inner)...);
|
||||
}
|
||||
|
||||
Ret (Class::*m_func)(Param...);
|
||||
};
|
||||
|
||||
|
||||
template<typename T>
|
||||
struct Function_Signature
|
||||
{
|
||||
};
|
||||
|
||||
template<typename Ret, typename ... Params>
|
||||
struct Function_Signature<Ret (Params...)>
|
||||
{
|
||||
typedef Ret Return_Type;
|
||||
typedef Ret (Signature)(Params...);
|
||||
};
|
||||
|
||||
template<typename Ret, typename T, typename ... Params>
|
||||
struct Function_Signature<Ret (T::*)(Params...) const>
|
||||
{
|
||||
typedef Ret Return_Type;
|
||||
typedef Ret (Signature)(Params...);
|
||||
};
|
||||
|
||||
|
||||
template<typename T>
|
||||
struct Callable_Traits
|
||||
{
|
||||
typedef typename Function_Signature<decltype(&T::operator())>::Signature Signature;
|
||||
typedef typename Function_Signature<decltype(&T::operator())>::Return_Type Return_Type;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -22,6 +22,7 @@
|
||||
|
||||
#include "../chaiscript_defines.hpp"
|
||||
#include "../chaiscript_threading.hpp"
|
||||
#include "bad_boxed_cast.hpp"
|
||||
#include "boxed_cast.hpp"
|
||||
#include "boxed_cast_helper.hpp"
|
||||
#include "boxed_value.hpp"
|
||||
@ -384,19 +385,41 @@ namespace chaiscript
|
||||
|
||||
namespace detail
|
||||
{
|
||||
struct Stack_Holder
|
||||
{
|
||||
typedef std::vector<std::pair<std::string, Boxed_Value>> Scope;
|
||||
typedef std::vector<Scope> StackData;
|
||||
|
||||
Stack_Holder()
|
||||
: call_depth(0)
|
||||
{
|
||||
stacks.reserve(2);
|
||||
stacks.emplace_back(1);
|
||||
call_params.emplace_back();
|
||||
call_params.back().reserve(2);
|
||||
}
|
||||
|
||||
std::vector<StackData> stacks;
|
||||
|
||||
std::vector<std::vector<Boxed_Value>> call_params;
|
||||
int call_depth;
|
||||
};
|
||||
|
||||
/// Main class for the dispatchkit. Handles management
|
||||
/// of the object stack, functions and registered types.
|
||||
class Dispatch_Engine
|
||||
{
|
||||
|
||||
public:
|
||||
typedef std::map<std::string, chaiscript::Type_Info> Type_Name_Map;
|
||||
typedef std::map<std::string, Boxed_Value> Scope;
|
||||
typedef std::vector<std::pair<std::string, Boxed_Value>> Scope;
|
||||
typedef std::vector<Scope> StackData;
|
||||
|
||||
struct State
|
||||
{
|
||||
std::map<std::string, std::vector<Proxy_Function> > m_functions;
|
||||
std::map<std::string, Proxy_Function> m_function_objects;
|
||||
std::map<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;
|
||||
@ -407,8 +430,7 @@ namespace chaiscript
|
||||
};
|
||||
|
||||
Dispatch_Engine()
|
||||
: m_stack_holder(this),
|
||||
m_place_holder(std::make_shared<dispatch::Placeholder_Object>())
|
||||
: m_stack_holder(this)
|
||||
{
|
||||
}
|
||||
|
||||
@ -438,14 +460,18 @@ namespace chaiscript
|
||||
|
||||
/// Set the value of an object, by name. If the object
|
||||
/// is not available in the current scope it is created
|
||||
void add(const Boxed_Value &obj, const std::string &name)
|
||||
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)
|
||||
{
|
||||
auto itr = stack_elem->find(name);
|
||||
auto itr = std::find_if(stack_elem->begin(), stack_elem->end(),
|
||||
[&](const std::pair<std::string, Boxed_Value> &o) {
|
||||
return o.first == name;
|
||||
});
|
||||
|
||||
if (itr != stack_elem->end())
|
||||
{
|
||||
itr->second = std::move(obj);
|
||||
@ -460,12 +486,20 @@ namespace chaiscript
|
||||
/// Adds a named object to the current scope
|
||||
/// \warning This version does not check the validity of the name
|
||||
/// it is meant for internal use only
|
||||
void add_object(const std::string &name, const Boxed_Value &obj)
|
||||
void add_object(const std::string &name, Boxed_Value obj)
|
||||
{
|
||||
if (!get_stack_data().back().insert(std::make_pair(name, obj)).second)
|
||||
auto &stack_elem = get_stack_data().back();
|
||||
|
||||
if (std::any_of(stack_elem.begin(), stack_elem.end(),
|
||||
[&](const std::pair<std::string, Boxed_Value> &o) {
|
||||
return o.first == name;
|
||||
}))
|
||||
{
|
||||
throw chaiscript::exception::name_conflict_error(name);
|
||||
}
|
||||
|
||||
get_stack_data().back().emplace_back(name, std::move(obj));
|
||||
|
||||
}
|
||||
|
||||
/// Adds a new global shared object, between all the threads
|
||||
@ -524,15 +558,27 @@ namespace chaiscript
|
||||
/// Adds a new scope to the stack
|
||||
void new_scope()
|
||||
{
|
||||
get_stack_data().emplace_back();
|
||||
m_stack_holder->call_params.emplace_back();
|
||||
new_scope(*m_stack_holder);
|
||||
}
|
||||
|
||||
/// Pops the current scope from the stack
|
||||
void pop_scope()
|
||||
{
|
||||
m_stack_holder->call_params.pop_back();
|
||||
StackData &stack = get_stack_data();
|
||||
pop_scope(*m_stack_holder);
|
||||
}
|
||||
|
||||
/// Adds a new scope to the stack
|
||||
void new_scope(Stack_Holder &t_holder)
|
||||
{
|
||||
get_stack_data(t_holder).emplace_back();
|
||||
t_holder.call_params.emplace_back();
|
||||
}
|
||||
|
||||
/// Pops the current scope from the stack
|
||||
void pop_scope(Stack_Holder &t_holder)
|
||||
{
|
||||
t_holder.call_params.pop_back();
|
||||
StackData &stack = get_stack_data(t_holder);
|
||||
if (stack.size() > 1)
|
||||
{
|
||||
stack.pop_back();
|
||||
@ -543,38 +589,56 @@ namespace chaiscript
|
||||
|
||||
|
||||
/// Pushes a new stack on to the list of stacks
|
||||
void new_stack()
|
||||
void new_stack(Stack_Holder &t_holder)
|
||||
{
|
||||
// add a new Stack with 1 element
|
||||
m_stack_holder->stacks.emplace_back(1);
|
||||
t_holder.stacks.emplace_back(1);
|
||||
}
|
||||
|
||||
void pop_stack()
|
||||
void pop_stack(Stack_Holder &t_holder)
|
||||
{
|
||||
m_stack_holder->stacks.pop_back();
|
||||
t_holder.stacks.pop_back();
|
||||
}
|
||||
|
||||
/// Searches the current stack for an object of the given name
|
||||
/// includes a special overload for the _ place holder object to
|
||||
/// ensure that it is always in scope.
|
||||
Boxed_Value get_object(const std::string &name) const
|
||||
Boxed_Value get_object(const std::string &name, std::atomic_uint_fast32_t &t_loc) const
|
||||
{
|
||||
// Is it a placeholder object?
|
||||
if (name == "_")
|
||||
{
|
||||
return m_place_holder;
|
||||
}
|
||||
enum class Loc : uint_fast32_t {
|
||||
located = 0x80000000,
|
||||
is_local = 0x40000000,
|
||||
stack_mask = 0x0FFF0000,
|
||||
loc_mask = 0x0000FFFF
|
||||
};
|
||||
|
||||
auto &stack = get_stack_data();
|
||||
uint_fast32_t loc = t_loc.load(std::memory_order_relaxed);
|
||||
|
||||
// Is it in the stack?
|
||||
for (auto stack_elem = stack.rbegin(); stack_elem != stack.rend(); ++stack_elem)
|
||||
if (loc == 0)
|
||||
{
|
||||
const auto stackitr = stack_elem->find(name);
|
||||
if (stackitr != stack_elem->end())
|
||||
auto &stack = get_stack_data();
|
||||
|
||||
// Is it in the stack?
|
||||
for (auto stack_elem = stack.rbegin(); stack_elem != stack.rend(); ++stack_elem)
|
||||
{
|
||||
return stackitr->second;
|
||||
for (auto s = stack_elem->begin(); s != stack_elem->end(); ++s )
|
||||
{
|
||||
if (s->first == name) {
|
||||
t_loc.store( static_cast<uint_fast32_t>(std::distance(stack.rbegin(), stack_elem) << 16)
|
||||
| static_cast<uint_fast32_t>(std::distance(stack_elem->begin(), s))
|
||||
| static_cast<uint_fast32_t>(Loc::located)
|
||||
| static_cast<uint_fast32_t>(Loc::is_local),
|
||||
std::memory_order_relaxed);
|
||||
return s->second;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
t_loc.store( static_cast<uint_fast32_t>(Loc::located), std::memory_order_relaxed);
|
||||
} else if (loc & static_cast<uint_fast32_t>(Loc::is_local)) {
|
||||
auto &stack = get_stack_data();
|
||||
|
||||
return stack[stack.size() - 1 - ((loc & static_cast<uint_fast32_t>(Loc::stack_mask)) >> 16)][loc & static_cast<uint_fast32_t>(Loc::loc_mask)].second;
|
||||
}
|
||||
|
||||
// Is the value we are looking for a global?
|
||||
@ -671,13 +735,13 @@ namespace chaiscript
|
||||
// std::cout << "Getting function object: " << t_name << '\n';
|
||||
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
|
||||
|
||||
const auto &funs = get_function_objects_int();
|
||||
const auto &funs = get_boxed_functions_int();
|
||||
|
||||
auto itr = funs.find(t_name);
|
||||
|
||||
if (itr != funs.end())
|
||||
{
|
||||
return const_var(itr->second);
|
||||
return itr->second;
|
||||
} else {
|
||||
throw std::range_error("Object not found: " + t_name);
|
||||
}
|
||||
@ -699,9 +763,9 @@ namespace chaiscript
|
||||
auto &stack = get_stack_data();
|
||||
if (stack.size() > 1)
|
||||
{
|
||||
return stack[1];
|
||||
return std::map<std::string, Boxed_Value>(stack[1].begin(), stack[1].end());
|
||||
} else {
|
||||
return stack[0];
|
||||
return std::map<std::string, Boxed_Value>(stack[0].begin(), stack[0].end());
|
||||
}
|
||||
}
|
||||
|
||||
@ -710,7 +774,7 @@ namespace chaiscript
|
||||
{
|
||||
auto &stack = get_stack_data();
|
||||
auto &scope = stack.front();
|
||||
return scope;
|
||||
return std::map<std::string, Boxed_Value>(scope.begin(), scope.end());
|
||||
}
|
||||
|
||||
/// \brief Sets all of the locals for the current thread state.
|
||||
@ -722,7 +786,7 @@ namespace chaiscript
|
||||
{
|
||||
auto &stack = get_stack_data();
|
||||
auto &scope = stack.front();
|
||||
scope = t_locals;
|
||||
scope = std::vector<std::pair<std::string, Boxed_Value>>(t_locals.begin(), t_locals.end());
|
||||
}
|
||||
|
||||
|
||||
@ -843,7 +907,14 @@ namespace chaiscript
|
||||
std::vector<Boxed_Value> remaining_params{l_params.begin() + l_num_params, l_params.end()};
|
||||
Boxed_Value bv = dispatch::dispatch(l_funs, attr_params, l_conversions);
|
||||
if (!remaining_params.empty() || bv.get_type_info().bare_equal(user_type<dispatch::Proxy_Function_Base>())) {
|
||||
return (*boxed_cast<const dispatch::Proxy_Function_Base *>(bv))(remaining_params, l_conversions);
|
||||
auto func = boxed_cast<std::shared_ptr<const dispatch::Proxy_Function_Base>>(bv);
|
||||
try {
|
||||
return (*func)(remaining_params, 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(remaining_params, std::vector<Const_Proxy_Function>{func});
|
||||
} else {
|
||||
return bv;
|
||||
}
|
||||
@ -1061,55 +1132,79 @@ namespace chaiscript
|
||||
m_state = t_state;
|
||||
}
|
||||
|
||||
void save_function_params(Stack_Holder &t_s, std::initializer_list<Boxed_Value> t_params)
|
||||
{
|
||||
t_s.call_params.back().insert(t_s.call_params.back().begin(), std::move(t_params));
|
||||
}
|
||||
|
||||
void save_function_params(Stack_Holder &t_s, std::vector<Boxed_Value> &&t_params)
|
||||
{
|
||||
for (auto &¶m : t_params)
|
||||
{
|
||||
t_s.call_params.back().insert(t_s.call_params.back().begin(), std::move(param));
|
||||
}
|
||||
}
|
||||
|
||||
void save_function_params(Stack_Holder &t_s, const std::vector<Boxed_Value> &t_params)
|
||||
{
|
||||
t_s.call_params.back().insert(t_s.call_params.back().begin(), t_params.begin(), t_params.end());
|
||||
}
|
||||
|
||||
void save_function_params(std::initializer_list<Boxed_Value> t_params)
|
||||
{
|
||||
Stack_Holder &s = *m_stack_holder;
|
||||
s.call_params.back().insert(s.call_params.back().begin(), std::move(t_params));
|
||||
save_function_params(*m_stack_holder, std::move(t_params));
|
||||
}
|
||||
|
||||
void save_function_params(std::vector<Boxed_Value> &&t_params)
|
||||
{
|
||||
Stack_Holder &s = *m_stack_holder;
|
||||
|
||||
for (auto &¶m : t_params)
|
||||
{
|
||||
s.call_params.back().insert(s.call_params.back().begin(), std::move(param));
|
||||
}
|
||||
save_function_params(*m_stack_holder, std::move(t_params));
|
||||
}
|
||||
|
||||
void save_function_params(const std::vector<Boxed_Value> &t_params)
|
||||
{
|
||||
Stack_Holder &s = *m_stack_holder;
|
||||
s.call_params.back().insert(s.call_params.back().begin(), t_params.begin(), t_params.end());
|
||||
save_function_params(*m_stack_holder, t_params);
|
||||
}
|
||||
|
||||
void new_function_call()
|
||||
void new_function_call(Stack_Holder &t_s)
|
||||
{
|
||||
Stack_Holder &s = *m_stack_holder;
|
||||
if (s.call_depth == 0)
|
||||
if (t_s.call_depth == 0)
|
||||
{
|
||||
m_conversions.enable_conversion_saves(true);
|
||||
}
|
||||
|
||||
++s.call_depth;
|
||||
++t_s.call_depth;
|
||||
|
||||
save_function_params(m_conversions.take_saves());
|
||||
}
|
||||
|
||||
void pop_function_call()
|
||||
void pop_function_call(Stack_Holder &t_s)
|
||||
{
|
||||
Stack_Holder &s = *m_stack_holder;
|
||||
--s.call_depth;
|
||||
--t_s.call_depth;
|
||||
|
||||
assert(s.call_depth >= 0);
|
||||
assert(t_s.call_depth >= 0);
|
||||
|
||||
if (s.call_depth == 0)
|
||||
if (t_s.call_depth == 0)
|
||||
{
|
||||
s.call_params.back().clear();
|
||||
t_s.call_params.back().clear();
|
||||
m_conversions.enable_conversion_saves(false);
|
||||
}
|
||||
}
|
||||
|
||||
void new_function_call()
|
||||
{
|
||||
new_function_call(*m_stack_holder);
|
||||
}
|
||||
|
||||
void pop_function_call()
|
||||
{
|
||||
pop_function_call(*m_stack_holder);
|
||||
}
|
||||
|
||||
Stack_Holder &get_stack_holder()
|
||||
{
|
||||
return *m_stack_holder;
|
||||
}
|
||||
|
||||
private:
|
||||
/// Returns the current stack
|
||||
/// make const/non const versions
|
||||
@ -1118,11 +1213,26 @@ namespace chaiscript
|
||||
return m_stack_holder->stacks.back();
|
||||
}
|
||||
|
||||
StackData &get_stack_data(Stack_Holder &t_holder)
|
||||
{
|
||||
return t_holder.stacks.back();
|
||||
}
|
||||
|
||||
StackData &get_stack_data()
|
||||
{
|
||||
return m_stack_holder->stacks.back();
|
||||
}
|
||||
|
||||
const std::map<std::string, Boxed_Value> &get_boxed_functions_int() const
|
||||
{
|
||||
return m_state.m_boxed_functions;
|
||||
}
|
||||
|
||||
std::map<std::string, Boxed_Value> &get_boxed_functions_int()
|
||||
{
|
||||
return m_state.m_boxed_functions;
|
||||
}
|
||||
|
||||
const std::map<std::string, Proxy_Function> &get_function_objects_int() const
|
||||
{
|
||||
return m_state.m_function_objects;
|
||||
@ -1175,8 +1285,13 @@ namespace chaiscript
|
||||
const auto lhssize = lhsparamtypes.size();
|
||||
const auto rhssize = rhsparamtypes.size();
|
||||
|
||||
CHAISCRIPT_CONSTEXPR auto boxed_type = user_type<Boxed_Value>();
|
||||
CHAISCRIPT_CONSTEXPR auto boxed_pod_type = user_type<Boxed_Number>();
|
||||
#ifdef CHAISCRIPT_HAS_MAGIC_STATICS
|
||||
static auto boxed_type = user_type<Boxed_Value>();
|
||||
static auto boxed_pod_type = user_type<Boxed_Number>();
|
||||
#else
|
||||
auto boxed_type = user_type<Boxed_Value>();
|
||||
auto boxed_pod_type = user_type<Boxed_Number>();
|
||||
#endif
|
||||
|
||||
for (size_t i = 1; i < lhssize && i < rhssize; ++i)
|
||||
{
|
||||
@ -1258,61 +1373,76 @@ namespace chaiscript
|
||||
auto itr = funcs.find(t_name);
|
||||
|
||||
auto &func_objs = get_function_objects_int();
|
||||
auto &boxed_funcs = get_boxed_functions_int();
|
||||
|
||||
if (itr != funcs.end())
|
||||
{
|
||||
auto &vec = itr->second;
|
||||
for (const auto &func : vec)
|
||||
{
|
||||
if ((*t_f) == *(func))
|
||||
Proxy_Function new_func =
|
||||
[&]() -> Proxy_Function {
|
||||
if (itr != funcs.end())
|
||||
{
|
||||
throw chaiscript::exception::name_conflict_error(t_name);
|
||||
auto &vec = itr->second;
|
||||
for (const auto &func : vec)
|
||||
{
|
||||
if ((*t_f) == *(func))
|
||||
{
|
||||
throw chaiscript::exception::name_conflict_error(t_name);
|
||||
}
|
||||
}
|
||||
|
||||
vec.push_back(t_f);
|
||||
std::stable_sort(vec.begin(), vec.end(), &function_less_than);
|
||||
return std::make_shared<Dispatch_Function>(vec);
|
||||
} else if (t_f->has_arithmetic_param()) {
|
||||
// if the function is the only function but it also contains
|
||||
// arithmetic operators, we must wrap it in a dispatch function
|
||||
// to allow for automatic arithmetic type conversions
|
||||
std::vector<Proxy_Function> vec({t_f});
|
||||
funcs.insert(std::make_pair(t_name, vec));
|
||||
return std::make_shared<Dispatch_Function>(std::move(vec));
|
||||
} else {
|
||||
funcs.insert(std::make_pair(t_name, std::vector<Proxy_Function>{t_f}));
|
||||
return t_f;
|
||||
}
|
||||
}
|
||||
|
||||
vec.push_back(t_f);
|
||||
std::stable_sort(vec.begin(), vec.end(), &function_less_than);
|
||||
func_objs[t_name] = std::make_shared<Dispatch_Function>(vec);
|
||||
} else if (t_f->has_arithmetic_param()) {
|
||||
// if the function is the only function but it also contains
|
||||
// arithmetic operators, we must wrap it in a dispatch function
|
||||
// to allow for automatic arithmetic type conversions
|
||||
std::vector<Proxy_Function> vec({t_f});
|
||||
funcs.insert(std::make_pair(t_name, vec));
|
||||
func_objs[t_name] = std::make_shared<Dispatch_Function>(std::move(vec));
|
||||
} else {
|
||||
funcs.insert(std::make_pair(t_name, std::vector<Proxy_Function>{t_f}));
|
||||
func_objs[t_name] = t_f;
|
||||
}
|
||||
|
||||
}();
|
||||
|
||||
boxed_funcs[t_name] = const_var(new_func);
|
||||
func_objs[t_name] = std::move(new_func);
|
||||
}
|
||||
|
||||
mutable chaiscript::detail::threading::shared_mutex m_mutex;
|
||||
mutable chaiscript::detail::threading::shared_mutex m_global_object_mutex;
|
||||
|
||||
struct Stack_Holder
|
||||
{
|
||||
Stack_Holder()
|
||||
: call_depth(0)
|
||||
{
|
||||
stacks.emplace_back(1);
|
||||
call_params.emplace_back();
|
||||
}
|
||||
|
||||
std::deque<StackData> stacks;
|
||||
|
||||
std::deque<std::list<Boxed_Value>> call_params;
|
||||
int call_depth;
|
||||
};
|
||||
|
||||
Type_Conversions m_conversions;
|
||||
chaiscript::detail::threading::Thread_Storage<Stack_Holder> m_stack_holder;
|
||||
|
||||
|
||||
State m_state;
|
||||
};
|
||||
|
||||
Boxed_Value m_place_holder;
|
||||
class Dispatch_State
|
||||
{
|
||||
public:
|
||||
Dispatch_State(Dispatch_Engine &t_engine)
|
||||
: m_engine(t_engine),
|
||||
m_stack_holder(t_engine.get_stack_holder())
|
||||
{
|
||||
}
|
||||
|
||||
Dispatch_Engine *operator->() const {
|
||||
return &m_engine.get();
|
||||
}
|
||||
|
||||
Dispatch_Engine &operator*() const {
|
||||
return m_engine.get();
|
||||
}
|
||||
|
||||
Stack_Holder &stack_holder() const {
|
||||
return m_stack_holder.get();
|
||||
}
|
||||
|
||||
private:
|
||||
std::reference_wrapper<Dispatch_Engine> m_engine;
|
||||
std::reference_wrapper<Stack_Holder> m_stack_holder;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -31,9 +31,9 @@ namespace chaiscript
|
||||
struct Function_Caller_Ret
|
||||
{
|
||||
static Ret call(const std::vector<Const_Proxy_Function> &t_funcs,
|
||||
const std::vector<Boxed_Value> ¶ms, const Type_Conversions &t_conversions)
|
||||
const std::vector<Boxed_Value> ¶ms, const Type_Conversions *t_conversions)
|
||||
{
|
||||
return boxed_cast<Ret>(dispatch::dispatch(t_funcs, params, t_conversions));
|
||||
return boxed_cast<Ret>(dispatch::dispatch(t_funcs, params, t_conversions?*t_conversions:Type_Conversions()), t_conversions);
|
||||
}
|
||||
};
|
||||
|
||||
@ -44,9 +44,9 @@ namespace chaiscript
|
||||
struct Function_Caller_Ret<Ret, true>
|
||||
{
|
||||
static Ret call(const std::vector<Const_Proxy_Function> &t_funcs,
|
||||
const std::vector<Boxed_Value> ¶ms, const Type_Conversions &t_conversions)
|
||||
const std::vector<Boxed_Value> ¶ms, const Type_Conversions *t_conversions)
|
||||
{
|
||||
return Boxed_Number(dispatch::dispatch(t_funcs, params, t_conversions)).get_as<Ret>();
|
||||
return Boxed_Number(dispatch::dispatch(t_funcs, params, t_conversions?*t_conversions:Type_Conversions())).get_as<Ret>();
|
||||
}
|
||||
};
|
||||
|
||||
@ -58,9 +58,9 @@ namespace chaiscript
|
||||
struct Function_Caller_Ret<void, false>
|
||||
{
|
||||
static void call(const std::vector<Const_Proxy_Function> &t_funcs,
|
||||
const std::vector<Boxed_Value> ¶ms, const Type_Conversions &t_conversions)
|
||||
const std::vector<Boxed_Value> ¶ms, const Type_Conversions *t_conversions)
|
||||
{
|
||||
dispatch::dispatch(t_funcs, params, t_conversions);
|
||||
dispatch::dispatch(t_funcs, params, t_conversions?*t_conversions:Type_Conversions());
|
||||
}
|
||||
};
|
||||
|
||||
@ -70,31 +70,53 @@ namespace chaiscript
|
||||
template<typename Ret, typename ... Param>
|
||||
struct Build_Function_Caller_Helper
|
||||
{
|
||||
Build_Function_Caller_Helper(std::vector<Const_Proxy_Function> t_funcs, const Type_Conversions &t_conversions)
|
||||
Build_Function_Caller_Helper(std::vector<Const_Proxy_Function> t_funcs, const Type_Conversions *t_conversions)
|
||||
: m_funcs(std::move(t_funcs)),
|
||||
m_conversions(t_conversions)
|
||||
{
|
||||
}
|
||||
|
||||
Ret operator()(Param...param)
|
||||
template<typename ... P>
|
||||
Ret operator()(P&& ... param)
|
||||
{
|
||||
return Function_Caller_Ret<Ret, std::is_arithmetic<Ret>::value && !std::is_same<Ret, bool>::value>::call(m_funcs, {
|
||||
(std::is_reference<Param>::value&&!(std::is_same<chaiscript::Boxed_Value, typename std::remove_const<typename std::remove_reference<Param>::type>::type>::value))?Boxed_Value(std::ref(param)):Boxed_Value(param)...
|
||||
box<P>(std::forward<P>(param))...
|
||||
}, m_conversions
|
||||
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
template<typename P, typename Q>
|
||||
static auto box(Q&& q) -> typename std::enable_if<std::is_reference<P>::value&&!std::is_same<chaiscript::Boxed_Value, typename std::remove_const<typename std::remove_reference<P>::type>::type>::value, Boxed_Value>::type
|
||||
{
|
||||
return Boxed_Value(std::ref(std::forward<Q>(q)));
|
||||
}
|
||||
|
||||
template<typename P, typename Q>
|
||||
static auto box(Q&& q) -> typename std::enable_if<!std::is_reference<P>::value&&!std::is_same<chaiscript::Boxed_Value, typename std::remove_const<typename std::remove_reference<P>::type>::type>::value, Boxed_Value>::type
|
||||
{
|
||||
return Boxed_Value(std::forward<Q>(q));
|
||||
}
|
||||
|
||||
template<typename P>
|
||||
static Boxed_Value box(Boxed_Value bv)
|
||||
{
|
||||
return bv;
|
||||
}
|
||||
|
||||
|
||||
std::vector<Const_Proxy_Function> m_funcs;
|
||||
Type_Conversions m_conversions;
|
||||
const Type_Conversions *m_conversions;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/// \todo what happens if t_conversions is deleted out from under us?!
|
||||
template<typename Ret, typename ... Params>
|
||||
std::function<Ret (Params...)> build_function_caller_helper(Ret (Params...), const std::vector<Const_Proxy_Function> &funcs, const Type_Conversions *t_conversions)
|
||||
{
|
||||
/*
|
||||
if (funcs.size() == 1)
|
||||
{
|
||||
std::shared_ptr<const Proxy_Function_Impl<Ret (Params...)>> pfi =
|
||||
@ -108,8 +130,9 @@ namespace chaiscript
|
||||
// looks like this either wasn't a Proxy_Function_Impl or the types didn't match
|
||||
// we cannot make any other guesses or assumptions really, so continuing
|
||||
}
|
||||
*/
|
||||
|
||||
return std::function<Ret (Params...)>(Build_Function_Caller_Helper<Ret, Params...>(funcs, t_conversions?*t_conversions:Type_Conversions()));
|
||||
return std::function<Ret (Params...)>(Build_Function_Caller_Helper<Ret, Params...>(funcs, t_conversions));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,6 @@
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
|
||||
#include "boxed_number.hpp"
|
||||
@ -23,7 +22,7 @@ namespace chaiscript
|
||||
{
|
||||
namespace dispatch
|
||||
{
|
||||
template<class T> class Proxy_Function_Impl;
|
||||
template<class T, class U> class Proxy_Function_Callable_Impl;
|
||||
template<class T> class Assignable_Proxy_Function_Impl;
|
||||
|
||||
namespace detail
|
||||
@ -54,9 +53,7 @@ namespace chaiscript
|
||||
{
|
||||
static Boxed_Value handle(const std::function<Ret> &f) {
|
||||
return Boxed_Value(
|
||||
std::shared_ptr<dispatch::Proxy_Function_Base>(
|
||||
new dispatch::Proxy_Function_Impl<Ret>(f)
|
||||
)
|
||||
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Ret, std::function<Ret>>>(f)
|
||||
);
|
||||
}
|
||||
};
|
||||
@ -66,10 +63,8 @@ namespace chaiscript
|
||||
{
|
||||
static Boxed_Value handle(const std::function<Ret> &f) {
|
||||
return Boxed_Value(
|
||||
std::shared_ptr<dispatch::Proxy_Function_Base>(
|
||||
new Proxy_Function_Impl<Ret>(f)
|
||||
)
|
||||
);
|
||||
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Ret, std::function<Ret>>>(f)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
@ -78,12 +73,7 @@ namespace chaiscript
|
||||
{
|
||||
static Boxed_Value handle(const std::shared_ptr<std::function<Ret>> &f) {
|
||||
return Boxed_Value(
|
||||
std::shared_ptr<Proxy_Function_Base>(
|
||||
new Assignable_Proxy_Function_Impl<Ret>(
|
||||
std::ref(*f),
|
||||
f
|
||||
)
|
||||
)
|
||||
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Assignable_Proxy_Function_Impl<Ret>>(std::ref(*f),f)
|
||||
);
|
||||
}
|
||||
};
|
||||
@ -93,13 +83,8 @@ namespace chaiscript
|
||||
{
|
||||
static Boxed_Value handle(const std::shared_ptr<std::function<Ret>> &f) {
|
||||
return Boxed_Value(
|
||||
std::shared_ptr<Proxy_Function_Base>(
|
||||
new Assignable_Proxy_Function_Impl<Ret>(
|
||||
std::ref(*f),
|
||||
f
|
||||
)
|
||||
)
|
||||
);
|
||||
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Assignable_Proxy_Function_Impl<Ret>>(std::ref(*f),f)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
@ -108,13 +93,8 @@ namespace chaiscript
|
||||
{
|
||||
static Boxed_Value handle(const std::shared_ptr<std::function<Ret>> &f) {
|
||||
return Boxed_Value(
|
||||
std::shared_ptr<Proxy_Function_Base>(
|
||||
new Assignable_Proxy_Function_Impl<Ret>(
|
||||
std::ref(*f),
|
||||
f
|
||||
)
|
||||
)
|
||||
);
|
||||
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Assignable_Proxy_Function_Impl<Ret>>(std::ref(*f),f)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
@ -123,20 +103,14 @@ namespace chaiscript
|
||||
{
|
||||
static Boxed_Value handle(std::function<Ret> &f) {
|
||||
return Boxed_Value(
|
||||
std::shared_ptr<Proxy_Function_Base>(
|
||||
new Assignable_Proxy_Function_Impl<Ret>(
|
||||
std::ref(f),
|
||||
std::shared_ptr<std::function<Ret>>()
|
||||
)
|
||||
)
|
||||
);
|
||||
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Assignable_Proxy_Function_Impl<Ret>>(std::ref(f),
|
||||
std::shared_ptr<std::function<Ret>>())
|
||||
);
|
||||
}
|
||||
|
||||
static Boxed_Value handle(const std::function<Ret> &f) {
|
||||
return Boxed_Value(
|
||||
std::shared_ptr<dispatch::Proxy_Function_Base>(
|
||||
new dispatch::Proxy_Function_Impl<Ret>(f)
|
||||
)
|
||||
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Ret, std::function<Ret>>>(f)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
@ -16,21 +16,14 @@ namespace chaiscript
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
/**
|
||||
* A constructor function, used for creating a new object
|
||||
* of a given type with a given set of params
|
||||
*/
|
||||
template<typename Class, typename ... Params>
|
||||
std::shared_ptr<Class> constructor_(Params ... params)
|
||||
{
|
||||
return std::make_shared<Class>(params...);
|
||||
}
|
||||
|
||||
template<typename Class, typename ... Params >
|
||||
Proxy_Function build_constructor_(Class (*)(Params...))
|
||||
{
|
||||
typedef std::shared_ptr<Class> (sig)(Params...);
|
||||
return Proxy_Function(static_cast<Proxy_Function_Impl_Base *>(new Proxy_Function_Impl<sig>(std::function<sig>(&(constructor_<Class, Params...>)))));
|
||||
auto call = dispatch::detail::Constructor<Class, Params...>();
|
||||
|
||||
return Proxy_Function(
|
||||
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<std::shared_ptr<Class> (Params...), decltype(call)>>(call));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
#include <iterator>
|
||||
|
||||
#include "../chaiscript_defines.hpp"
|
||||
#include "boxed_cast.hpp"
|
||||
@ -148,7 +149,11 @@ namespace chaiscript
|
||||
|
||||
Boxed_Value operator()(const std::vector<Boxed_Value> ¶ms, const chaiscript::Type_Conversions &t_conversions) const
|
||||
{
|
||||
return do_call(params, t_conversions);
|
||||
if (m_arity < 0 || size_t(m_arity) == params.size()) {
|
||||
return do_call(params, t_conversions);
|
||||
} else {
|
||||
throw exception::arity_error(static_cast<int>(params.size()), m_arity);
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a vector containing all of the types of the parameters the function returns/takes
|
||||
@ -183,10 +188,10 @@ namespace chaiscript
|
||||
if (m_arity == 0)
|
||||
{
|
||||
return true;
|
||||
} else if (m_arity > 1 && m_types.size() > 1) {
|
||||
return compare_first_type(vals[0], t_conversions) && compare_type_to_param(m_types[2], vals[1], 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 compare_first_type(vals[0], t_conversions);
|
||||
return compare_type_to_param(m_types[1], vals[0], t_conversions);
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
@ -301,7 +306,6 @@ namespace chaiscript
|
||||
{
|
||||
public:
|
||||
Dynamic_Proxy_Function(
|
||||
std::function<Boxed_Value (const std::vector<Boxed_Value> &)> t_f,
|
||||
int t_arity=-1,
|
||||
AST_NodePtr t_parsenode = AST_NodePtr(),
|
||||
Param_Types t_param_types = Param_Types(),
|
||||
@ -309,8 +313,7 @@ namespace chaiscript
|
||||
Proxy_Function t_guard = Proxy_Function())
|
||||
: Proxy_Function_Base(build_param_type_list(t_param_types), t_arity),
|
||||
m_param_types(std::move(t_param_types)),
|
||||
m_guard(std::move(t_guard)), m_parsenode(std::move(t_parsenode)), m_description(std::move(t_description)),
|
||||
m_f(std::move(t_f))
|
||||
m_guard(std::move(t_guard)), m_parsenode(std::move(t_parsenode)), m_description(std::move(t_description))
|
||||
{
|
||||
}
|
||||
|
||||
@ -349,24 +352,8 @@ namespace chaiscript
|
||||
return m_description;
|
||||
}
|
||||
|
||||
|
||||
protected:
|
||||
virtual Boxed_Value do_call(const std::vector<Boxed_Value> ¶ms, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
|
||||
{
|
||||
if (m_arity < 0 || params.size() == size_t(m_arity))
|
||||
{
|
||||
if (call_match(params, t_conversions) && test_guard(params, t_conversions))
|
||||
{
|
||||
return m_f(params);
|
||||
} else {
|
||||
throw exception::guard_error();
|
||||
}
|
||||
|
||||
} else {
|
||||
throw exception::arity_error(static_cast<int>(params.size()), m_arity);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
bool test_guard(const std::vector<Boxed_Value> ¶ms, const Type_Conversions &t_conversions) const
|
||||
{
|
||||
if (m_guard)
|
||||
@ -383,12 +370,11 @@ namespace chaiscript
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
static std::vector<Type_Info> build_param_type_list(const Param_Types &t_types)
|
||||
{
|
||||
std::vector<Type_Info> types;
|
||||
|
||||
// For the return type
|
||||
types.push_back(chaiscript::detail::Get_Type_Info<Boxed_Value>::get());
|
||||
std::vector<Type_Info> types{chaiscript::detail::Get_Type_Info<Boxed_Value>::get()};
|
||||
|
||||
for (const auto &t : t_types.types())
|
||||
{
|
||||
@ -406,9 +392,58 @@ namespace chaiscript
|
||||
Proxy_Function m_guard;
|
||||
AST_NodePtr m_parsenode;
|
||||
std::string m_description;
|
||||
std::function<Boxed_Value (const std::vector<Boxed_Value> &)> m_f;
|
||||
};
|
||||
|
||||
|
||||
|
||||
template<typename Callable>
|
||||
class Dynamic_Proxy_Function_Impl : public Dynamic_Proxy_Function
|
||||
{
|
||||
public:
|
||||
Dynamic_Proxy_Function_Impl(
|
||||
Callable t_f,
|
||||
int t_arity=-1,
|
||||
AST_NodePtr t_parsenode = AST_NodePtr(),
|
||||
Param_Types t_param_types = Param_Types(),
|
||||
std::string t_description = "",
|
||||
Proxy_Function t_guard = Proxy_Function())
|
||||
: 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))
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~Dynamic_Proxy_Function_Impl() {}
|
||||
|
||||
|
||||
protected:
|
||||
virtual Boxed_Value do_call(const std::vector<Boxed_Value> ¶ms, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
|
||||
{
|
||||
if (call_match(params, t_conversions) && test_guard(params, t_conversions))
|
||||
{
|
||||
return m_f(params);
|
||||
} else {
|
||||
throw exception::guard_error();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
Callable m_f;
|
||||
};
|
||||
|
||||
template<typename Callable, typename ... Arg>
|
||||
Proxy_Function make_dynamic_proxy_function(Callable &&c, Arg&& ... a)
|
||||
{
|
||||
return chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Dynamic_Proxy_Function_Impl<Callable>>(
|
||||
std::forward<Callable>(c), std::forward<Arg>(a)...);
|
||||
}
|
||||
|
||||
/// An object used by Bound_Function to represent "_" parameters
|
||||
/// of a binding. This allows for unbound parameters during bind.
|
||||
struct Placeholder_Object
|
||||
@ -549,48 +584,44 @@ namespace chaiscript
|
||||
virtual bool compare_types_with_cast(const std::vector<Boxed_Value> &vals, const Type_Conversions &t_conversions) const = 0;
|
||||
};
|
||||
|
||||
/// The standard typesafe function call implementation of Proxy_Function
|
||||
/// It takes a std::function<> object and performs runtime
|
||||
/// type checking of Boxed_Value parameters, in a type safe manner
|
||||
template<typename Func>
|
||||
class Proxy_Function_Impl : public Proxy_Function_Impl_Base
|
||||
|
||||
|
||||
/// For any callable object
|
||||
template<typename Func, typename Callable>
|
||||
class Proxy_Function_Callable_Impl : public Proxy_Function_Impl_Base
|
||||
{
|
||||
public:
|
||||
Proxy_Function_Impl(std::function<Func> f)
|
||||
Proxy_Function_Callable_Impl(Callable f)
|
||||
: Proxy_Function_Impl_Base(detail::build_param_type_list(static_cast<Func *>(nullptr))),
|
||||
m_f(std::move(f)), m_dummy_func(nullptr)
|
||||
m_f(std::move(f))
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~Proxy_Function_Impl() {}
|
||||
virtual ~Proxy_Function_Callable_Impl() {}
|
||||
|
||||
virtual bool compare_types_with_cast(const std::vector<Boxed_Value> &vals, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
|
||||
{
|
||||
return detail::compare_types_cast(m_dummy_func, vals, t_conversions);
|
||||
return detail::compare_types_cast(static_cast<Func *>(nullptr), vals, t_conversions);
|
||||
}
|
||||
|
||||
virtual bool operator==(const Proxy_Function_Base &t_func) const CHAISCRIPT_OVERRIDE
|
||||
{
|
||||
return dynamic_cast<const Proxy_Function_Impl<Func> *>(&t_func) != nullptr;
|
||||
return dynamic_cast<const Proxy_Function_Callable_Impl<Func, Callable> *>(&t_func) != nullptr;
|
||||
}
|
||||
|
||||
std::function<Func> internal_function() const
|
||||
{
|
||||
return m_f;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual Boxed_Value do_call(const std::vector<Boxed_Value> ¶ms, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
|
||||
{
|
||||
return detail::Do_Call<typename std::function<Func>::result_type>::go(m_f, params, t_conversions);
|
||||
typedef typename detail::Function_Signature<Func>::Return_Type Return_Type;
|
||||
return detail::Do_Call<Return_Type>::template go<Func>(m_f, params, t_conversions);
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
std::function<Func> m_f;
|
||||
Func *m_dummy_func;
|
||||
Callable m_f;
|
||||
};
|
||||
|
||||
|
||||
class Assignable_Proxy_Function : public Proxy_Function_Impl_Base
|
||||
{
|
||||
public:
|
||||
@ -613,17 +644,16 @@ namespace chaiscript
|
||||
public:
|
||||
Assignable_Proxy_Function_Impl(std::reference_wrapper<std::function<Func>> t_f, std::shared_ptr<std::function<Func>> t_ptr)
|
||||
: Assignable_Proxy_Function(detail::build_param_type_list(static_cast<Func *>(nullptr))),
|
||||
m_f(std::move(t_f)), m_shared_ptr_holder(std::move(t_ptr)), m_dummy_func(nullptr)
|
||||
m_f(std::move(t_f)), m_shared_ptr_holder(std::move(t_ptr))
|
||||
{
|
||||
assert(!m_shared_ptr_holder || m_shared_ptr_holder.get() == &m_f.get());
|
||||
|
||||
}
|
||||
|
||||
virtual ~Assignable_Proxy_Function_Impl() {}
|
||||
|
||||
virtual bool compare_types_with_cast(const std::vector<Boxed_Value> &vals, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
|
||||
{
|
||||
return detail::compare_types_cast(m_dummy_func, vals, t_conversions);
|
||||
return detail::compare_types_cast(static_cast<Func *>(nullptr), vals, t_conversions);
|
||||
}
|
||||
|
||||
virtual bool operator==(const Proxy_Function_Base &t_func) const CHAISCRIPT_OVERRIDE
|
||||
@ -643,14 +673,13 @@ namespace chaiscript
|
||||
protected:
|
||||
virtual Boxed_Value do_call(const std::vector<Boxed_Value> ¶ms, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
|
||||
{
|
||||
return detail::Do_Call<typename std::function<Func>::result_type>::go(m_f.get(), params, t_conversions);
|
||||
return detail::Do_Call<typename std::function<Func>::result_type>::template go<Func>(m_f.get(), params, t_conversions);
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
std::reference_wrapper<std::function<Func>> m_f;
|
||||
std::shared_ptr<std::function<Func>> m_shared_ptr_holder;
|
||||
Func *m_dummy_func;
|
||||
};
|
||||
/// Attribute getter Proxy_Function implementation
|
||||
template<typename T, typename Class>
|
||||
@ -697,19 +726,14 @@ namespace chaiscript
|
||||
protected:
|
||||
virtual Boxed_Value do_call(const std::vector<Boxed_Value> ¶ms, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
|
||||
{
|
||||
if (params.size() == 1)
|
||||
const Boxed_Value &bv = params[0];
|
||||
if (bv.is_const())
|
||||
{
|
||||
const Boxed_Value &bv = params[0];
|
||||
if (bv.is_const())
|
||||
{
|
||||
const Class *o = boxed_cast<const Class *>(bv, &t_conversions);
|
||||
return detail::Handle_Return<const typename std::add_lvalue_reference<T>::type>::handle(o->*m_attr);
|
||||
} else {
|
||||
Class *o = boxed_cast<Class *>(bv, &t_conversions);
|
||||
return detail::Handle_Return<typename std::add_lvalue_reference<T>::type>::handle(o->*m_attr);
|
||||
}
|
||||
const Class *o = boxed_cast<const Class *>(bv, &t_conversions);
|
||||
return detail::Handle_Return<const typename std::add_lvalue_reference<T>::type>::handle(o->*m_attr);
|
||||
} else {
|
||||
throw exception::arity_error(static_cast<int>(params.size()), 1);
|
||||
Class *o = boxed_cast<Class *>(bv, &t_conversions);
|
||||
return detail::Handle_Return<typename std::add_lvalue_reference<T>::type>::handle(o->*m_attr);
|
||||
}
|
||||
}
|
||||
|
||||
@ -755,49 +779,38 @@ namespace chaiscript
|
||||
bool types_match_except_for_arithmetic(const FuncType &t_func, const std::vector<Boxed_Value> &plist,
|
||||
const Type_Conversions &t_conversions)
|
||||
{
|
||||
if (t_func->get_arity() != static_cast<int>(plist.size()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const std::vector<Type_Info> &types = t_func->get_param_types();
|
||||
|
||||
if (t_func->get_arity() == -1) return false;
|
||||
|
||||
assert(plist.size() == types.size() - 1);
|
||||
|
||||
for (size_t i = 0; i < plist.size(); ++i)
|
||||
{
|
||||
if (Proxy_Function_Base::compare_type_to_param(types[i+1], plist[i], t_conversions)
|
||||
|| (types[i+1].is_arithmetic() && plist[i].get_type_info().is_arithmetic()))
|
||||
{
|
||||
// types continue to match
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// all types match
|
||||
return true;
|
||||
return std::mismatch(plist.begin(), plist.end(),
|
||||
types.begin()+1,
|
||||
[&](const Boxed_Value &bv, const Type_Info &ti) {
|
||||
return Proxy_Function_Base::compare_type_to_param(ti, bv, t_conversions)
|
||||
|| (bv.get_type_info().is_arithmetic() && ti.is_arithmetic());
|
||||
}
|
||||
) == std::make_pair(plist.end(), types.end());
|
||||
}
|
||||
|
||||
template<typename InItr>
|
||||
template<typename InItr, typename Funcs>
|
||||
Boxed_Value dispatch_with_conversions(InItr begin, const InItr &end, const std::vector<Boxed_Value> &plist,
|
||||
const Type_Conversions &t_conversions)
|
||||
const Type_Conversions &t_conversions, const Funcs &t_funcs)
|
||||
{
|
||||
InItr orig(begin);
|
||||
|
||||
InItr matching_func(end);
|
||||
|
||||
while (begin != end)
|
||||
{
|
||||
if (types_match_except_for_arithmetic(*begin, plist, t_conversions))
|
||||
if (types_match_except_for_arithmetic(begin->second, plist, t_conversions))
|
||||
{
|
||||
if (matching_func == end)
|
||||
{
|
||||
matching_func = begin;
|
||||
} else {
|
||||
// handle const members vs non-const member, which is not really ambiguous
|
||||
const auto &mat_fun_param_types = (*matching_func)->get_param_types();
|
||||
const auto &next_fun_param_types = (*begin)->get_param_types();
|
||||
const auto &mat_fun_param_types = matching_func->second->get_param_types();
|
||||
const auto &next_fun_param_types = begin->second->get_param_types();
|
||||
|
||||
if (plist[0].is_const() && !mat_fun_param_types[1].is_const() && next_fun_param_types[1].is_const()) {
|
||||
matching_func = begin; // keep the new one, the const/non-const matchup is correct
|
||||
@ -805,7 +818,7 @@ namespace chaiscript
|
||||
// keep the old one, it has a better const/non-const matchup
|
||||
} else {
|
||||
// ambiguous function call
|
||||
throw exception::dispatch_error(plist, std::vector<Const_Proxy_Function>(orig, end));
|
||||
throw exception::dispatch_error(plist, std::vector<Const_Proxy_Function>(t_funcs.begin(), t_funcs.end()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -816,25 +829,30 @@ namespace chaiscript
|
||||
if (matching_func == end)
|
||||
{
|
||||
// no appropriate function to attempt arithmetic type conversion on
|
||||
throw exception::dispatch_error(plist, std::vector<Const_Proxy_Function>(orig, end));
|
||||
throw exception::dispatch_error(plist, std::vector<Const_Proxy_Function>(t_funcs.begin(), t_funcs.end()));
|
||||
}
|
||||
|
||||
|
||||
std::vector<Boxed_Value> newplist;
|
||||
const std::vector<Type_Info> &tis = (*matching_func)->get_param_types();
|
||||
newplist.reserve(plist.size());
|
||||
|
||||
const std::vector<Type_Info> &tis = matching_func->second->get_param_types();
|
||||
std::transform(tis.begin() + 1, tis.end(),
|
||||
plist.begin(),
|
||||
std::back_inserter(newplist),
|
||||
[](const Type_Info &ti, const Boxed_Value ¶m) -> Boxed_Value {
|
||||
if (ti.is_arithmetic() && param.get_type_info().is_arithmetic()) {
|
||||
return Boxed_Number(param).get_as(ti).bv;
|
||||
} else {
|
||||
return param;
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
for (size_t i = 0; i < plist.size(); ++i)
|
||||
{
|
||||
if (tis[i+1].is_arithmetic()
|
||||
&& plist[i].get_type_info().is_arithmetic()) {
|
||||
newplist.push_back(Boxed_Number(plist[i]).get_as(tis[i+1]).bv);
|
||||
} else {
|
||||
newplist.push_back(plist[i]);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
return (*(*matching_func))(newplist, t_conversions);
|
||||
return (*(matching_func->second))(newplist, t_conversions);
|
||||
} catch (const exception::bad_boxed_cast &) {
|
||||
//parameter failed to cast
|
||||
} catch (const exception::arity_error &) {
|
||||
@ -843,7 +861,7 @@ namespace chaiscript
|
||||
//guard failed to allow the function to execute
|
||||
}
|
||||
|
||||
throw exception::dispatch_error(plist, std::vector<Const_Proxy_Function>(orig, end));
|
||||
throw exception::dispatch_error(plist, std::vector<Const_Proxy_Function>(t_funcs.begin(), t_funcs.end()));
|
||||
|
||||
}
|
||||
}
|
||||
@ -857,18 +875,18 @@ namespace chaiscript
|
||||
Boxed_Value dispatch(const Funcs &funcs,
|
||||
const std::vector<Boxed_Value> &plist, const Type_Conversions &t_conversions)
|
||||
{
|
||||
//std::cout << "starting dispatch: " << funcs.size() << '\n';
|
||||
std::multimap<size_t, const Proxy_Function_Base *> ordered_funcs;
|
||||
std::vector<std::pair<size_t, const Proxy_Function_Base *>> ordered_funcs;
|
||||
ordered_funcs.reserve(funcs.size());
|
||||
|
||||
for (const auto &func : funcs)
|
||||
{
|
||||
size_t numdiffs = 0;
|
||||
const auto arity = func->get_arity();
|
||||
|
||||
if (arity == -1)
|
||||
{
|
||||
numdiffs = plist.size();
|
||||
ordered_funcs.emplace_back(plist.size(), func.get());
|
||||
} else if (arity == static_cast<int>(plist.size())) {
|
||||
size_t numdiffs = 0;
|
||||
for (size_t i = 0; i < plist.size(); ++i)
|
||||
{
|
||||
if (!func->get_param_types()[i+1].bare_equal(plist[i].get_type_info()))
|
||||
@ -876,31 +894,32 @@ namespace chaiscript
|
||||
++numdiffs;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
continue;
|
||||
ordered_funcs.emplace_back(numdiffs, func.get());
|
||||
}
|
||||
|
||||
ordered_funcs.insert(std::make_pair(numdiffs, func.get()));
|
||||
}
|
||||
|
||||
for (const auto &func : ordered_funcs )
|
||||
|
||||
for (size_t i = 0; i <= plist.size(); ++i)
|
||||
{
|
||||
try {
|
||||
if (func.first == 0 || func.second->filter(plist, t_conversions))
|
||||
{
|
||||
return (*(func.second))(plist, t_conversions);
|
||||
for (const auto &func : ordered_funcs )
|
||||
{
|
||||
try {
|
||||
if (func.first == i && func.second->filter(plist, t_conversions))
|
||||
{
|
||||
return (*(func.second))(plist, t_conversions);
|
||||
}
|
||||
} catch (const exception::bad_boxed_cast &) {
|
||||
//parameter failed to cast, try again
|
||||
} catch (const exception::arity_error &) {
|
||||
//invalid num params, try again
|
||||
} catch (const exception::guard_error &) {
|
||||
//guard failed to allow the function to execute,
|
||||
//try again
|
||||
}
|
||||
} catch (const exception::bad_boxed_cast &) {
|
||||
//parameter failed to cast, try again
|
||||
} catch (const exception::arity_error &) {
|
||||
//invalid num params, try again
|
||||
} catch (const exception::guard_error &) {
|
||||
//guard failed to allow the function to execute,
|
||||
//try again
|
||||
}
|
||||
}
|
||||
|
||||
return detail::dispatch_with_conversions(funcs.cbegin(), funcs.cend(), plist, t_conversions);
|
||||
return detail::dispatch_with_conversions(ordered_funcs.cbegin(), ordered_funcs.cend(), plist, t_conversions, funcs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include "boxed_value.hpp"
|
||||
#include "handle_return.hpp"
|
||||
#include "type_info.hpp"
|
||||
#include "callable_traits.hpp"
|
||||
|
||||
namespace chaiscript {
|
||||
class Type_Conversions;
|
||||
@ -65,6 +66,10 @@ namespace chaiscript
|
||||
}
|
||||
|
||||
|
||||
#ifdef CHAISCRIPT_GCC_4_6
|
||||
/// \todo REMOVE THIS WHEN WE DROP G++4.6
|
||||
|
||||
|
||||
// Forward declaration
|
||||
template<typename ... Rest>
|
||||
struct Try_Cast;
|
||||
@ -97,7 +102,7 @@ namespace chaiscript
|
||||
template<typename Ret, typename ... Params>
|
||||
bool compare_types_cast(Ret (*)(Params...),
|
||||
const std::vector<Boxed_Value> ¶ms, const Type_Conversions &t_conversions)
|
||||
{
|
||||
{
|
||||
try {
|
||||
Try_Cast<Params...>::do_try(params, 0, t_conversions);
|
||||
} catch (const exception::bad_boxed_cast &) {
|
||||
@ -111,8 +116,8 @@ namespace chaiscript
|
||||
struct Call_Func
|
||||
{
|
||||
|
||||
template<typename ... InnerParams>
|
||||
static Ret do_call(const std::function<Ret (Params...)> &f,
|
||||
template<typename Callable, typename ... InnerParams>
|
||||
static Ret do_call(const Callable &f,
|
||||
const std::vector<Boxed_Value> ¶ms, const Type_Conversions &t_conversions, InnerParams &&... innerparams)
|
||||
{
|
||||
return Call_Func<Ret, count - 1, Params...>::do_call(f, params, t_conversions, std::forward<InnerParams>(innerparams)..., params[sizeof...(Params) - count]);
|
||||
@ -126,8 +131,8 @@ namespace chaiscript
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4100) /// Disable unreferenced formal parameter warning, which only shows up in MSVC I don't think there's any way around it \todo evaluate this
|
||||
#endif
|
||||
template<typename ... InnerParams>
|
||||
static Ret do_call(const std::function<Ret (Params...)> &f,
|
||||
template<typename Callable, typename ... InnerParams>
|
||||
static Ret do_call(const Callable &f,
|
||||
const std::vector<Boxed_Value> &, const Type_Conversions &t_conversions, InnerParams &&... innerparams)
|
||||
{
|
||||
return f(boxed_cast<Params>(std::forward<InnerParams>(innerparams), &t_conversions)...);
|
||||
@ -143,8 +148,8 @@ namespace chaiscript
|
||||
* if any unboxing fails the execution of the function fails and
|
||||
* the bad_boxed_cast is passed up to the caller.
|
||||
*/
|
||||
template<typename Ret, typename ... Params>
|
||||
Ret call_func(const std::function<Ret (Params...)> &f,
|
||||
template<typename Callable, typename Ret, typename ... Params>
|
||||
Ret call_func(const chaiscript::dispatch::detail::Function_Signature<Ret (Params...)> &, const Callable &f,
|
||||
const std::vector<Boxed_Value> ¶ms, const Type_Conversions &t_conversions)
|
||||
{
|
||||
if (params.size() == sizeof...(Params))
|
||||
@ -155,6 +160,82 @@ namespace chaiscript
|
||||
throw exception::arity_error(static_cast<int>(params.size()), sizeof...(Params));
|
||||
}
|
||||
|
||||
|
||||
|
||||
#else
|
||||
|
||||
template<size_t ... I>
|
||||
struct Indexes
|
||||
{
|
||||
};
|
||||
|
||||
template<size_t S, size_t ... I>
|
||||
struct Make_Indexes
|
||||
{
|
||||
typedef typename Make_Indexes<S-1, I..., sizeof...(I)>::indexes indexes;
|
||||
};
|
||||
|
||||
template<size_t ... I>
|
||||
struct Make_Indexes<0, I...>
|
||||
{
|
||||
typedef Indexes<I...> indexes;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Used by Proxy_Function_Impl to determine if it is equivalent to another
|
||||
* Proxy_Function_Impl object. This function is primarily used to prevent
|
||||
* registration of two functions with the exact same signatures
|
||||
*/
|
||||
template<typename Ret, typename ... Params, size_t ... I>
|
||||
bool compare_types_cast(Indexes<I...>, Ret (*)(Params...),
|
||||
const std::vector<Boxed_Value> ¶ms, const Type_Conversions &t_conversions)
|
||||
{
|
||||
try {
|
||||
(void)params; (void)t_conversions;
|
||||
(void)std::initializer_list<int>{(boxed_cast<Params>(params[I], &t_conversions), 0)...};
|
||||
return true;
|
||||
} catch (const exception::bad_boxed_cast &) {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
template<typename Ret, typename ... Params>
|
||||
bool compare_types_cast(Ret (*f)(Params...),
|
||||
const std::vector<Boxed_Value> ¶ms, const Type_Conversions &t_conversions)
|
||||
{
|
||||
typedef typename Make_Indexes<sizeof...(Params)>::indexes indexes;
|
||||
return compare_types_cast(indexes(), f, params, t_conversions);
|
||||
}
|
||||
|
||||
|
||||
template<typename Callable, typename Ret, typename ... Params, size_t ... I>
|
||||
Ret call_func(const chaiscript::dispatch::detail::Function_Signature<Ret (Params...)> &, Indexes<I...>, const Callable &f,
|
||||
const std::vector<Boxed_Value> ¶ms, const Type_Conversions &t_conversions)
|
||||
{
|
||||
(void)params; (void)t_conversions;
|
||||
return f(boxed_cast<Params>(params[I], &t_conversions)...);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Used by Proxy_Function_Impl to perform typesafe execution of a function.
|
||||
* The function attempts to unbox each parameter to the expected type.
|
||||
* if any unboxing fails the execution of the function fails and
|
||||
* the bad_boxed_cast is passed up to the caller.
|
||||
*/
|
||||
template<typename Callable, typename Ret, typename ... Params>
|
||||
Ret call_func(const chaiscript::dispatch::detail::Function_Signature<Ret (Params...)> &sig, const Callable &f,
|
||||
const std::vector<Boxed_Value> ¶ms, const Type_Conversions &t_conversions)
|
||||
{
|
||||
typedef typename Make_Indexes<sizeof...(Params)>::indexes indexes;
|
||||
return call_func(sig, indexes(), f, params, t_conversions);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -170,20 +251,20 @@ namespace chaiscript
|
||||
template<typename Ret>
|
||||
struct Do_Call
|
||||
{
|
||||
template<typename Fun>
|
||||
static Boxed_Value go(const std::function<Fun> &fun, const std::vector<Boxed_Value> ¶ms, const Type_Conversions &t_conversions)
|
||||
template<typename Signature, typename Callable>
|
||||
static Boxed_Value go(const Callable &fun, const std::vector<Boxed_Value> ¶ms, const Type_Conversions &t_conversions)
|
||||
{
|
||||
return Handle_Return<Ret>::handle(call_func(fun, params, t_conversions));
|
||||
return Handle_Return<Ret>::handle(call_func(Function_Signature<Signature>(), fun, params, t_conversions));
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct Do_Call<void>
|
||||
{
|
||||
template<typename Fun>
|
||||
static Boxed_Value go(const std::function<Fun> &fun, const std::vector<Boxed_Value> ¶ms, const Type_Conversions &t_conversions)
|
||||
template<typename Signature, typename Callable>
|
||||
static Boxed_Value go(const Callable &fun, const std::vector<Boxed_Value> ¶ms, const Type_Conversions &t_conversions)
|
||||
{
|
||||
call_func(fun, params, t_conversions);
|
||||
call_func(Function_Signature<Signature>(), fun, params, t_conversions);
|
||||
return Handle_Return<void>::handle();
|
||||
}
|
||||
};
|
||||
|
@ -7,7 +7,6 @@
|
||||
#ifndef CHAISCRIPT_REGISTER_FUNCTION_HPP_
|
||||
#define CHAISCRIPT_REGISTER_FUNCTION_HPP_
|
||||
|
||||
#include <functional>
|
||||
#include <type_traits>
|
||||
|
||||
#include "bind_first.hpp"
|
||||
@ -15,55 +14,6 @@
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
namespace dispatch
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
template<typename T>
|
||||
struct FunctionSignature
|
||||
{
|
||||
};
|
||||
|
||||
template<typename Sig>
|
||||
struct FunctionSignature<std::function<Sig> >
|
||||
{
|
||||
typedef Sig Signature;
|
||||
};
|
||||
|
||||
template<typename Ret, typename ... Args>
|
||||
std::function<Ret (Args...) > to_function(Ret (*func)(Args...))
|
||||
{
|
||||
return std::function<Ret (Args...)>(func);
|
||||
}
|
||||
|
||||
template<typename Ret, typename Class, typename ... Args>
|
||||
std::function<Ret (Class &, Args...) > to_function(Ret (Class::*func)(Args...))
|
||||
{
|
||||
#ifdef CHAISCRIPT_MSVC
|
||||
/// \todo this std::mem_fn wrap shouldn't be necessary but type conversions for
|
||||
/// std::function for member function pointers seems to be broken in MSVC
|
||||
return std::function<Ret(Class &, Args...)>(std::mem_fn(func));
|
||||
#else
|
||||
return std::function<Ret(Class &, Args...)>(func);
|
||||
#endif
|
||||
}
|
||||
|
||||
template<typename Ret, typename Class, typename ... Args>
|
||||
std::function<Ret (const Class &, Args...) > to_function(Ret (Class::*func)(Args...) const)
|
||||
{
|
||||
#if defined(CHAISCRIPT_MSVC) || defined(CHAISCRIPT_LIBCPP)
|
||||
/// \todo this std::mem_fn wrap shouldn't be necessary but type conversions for
|
||||
/// std::function for member function pointers seems to be broken in MSVC
|
||||
return std::function<Ret (const Class &, Args...)>([func](const Class &o, Args... args)->Ret {
|
||||
return (o.*func)(std::forward<Args>(args)...);
|
||||
});
|
||||
#else
|
||||
return std::function<Ret(const Class &, Args...)>(func);
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/// \brief Creates a new Proxy_Function object from a free function, member function or data member
|
||||
/// \param[in] t Function / member to expose
|
||||
@ -88,22 +38,39 @@ namespace chaiscript
|
||||
template<typename T>
|
||||
Proxy_Function fun(const T &t)
|
||||
{
|
||||
typedef typename dispatch::detail::Callable_Traits<T>::Signature Signature;
|
||||
|
||||
return Proxy_Function(
|
||||
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Impl<typename dispatch::detail::FunctionSignature<decltype(dispatch::detail::to_function(t)) >::Signature>>(dispatch::detail::to_function(t)));
|
||||
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Signature, T>>(t));
|
||||
}
|
||||
|
||||
template<typename Ret, typename ... Param>
|
||||
Proxy_Function fun(Ret (*func)(Param...))
|
||||
{
|
||||
auto fun_call = dispatch::detail::Fun_Caller<Ret, Param...>(func);
|
||||
|
||||
return Proxy_Function(
|
||||
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Ret (Param...), decltype(fun_call)>>(fun_call));
|
||||
|
||||
}
|
||||
|
||||
template<typename Ret, typename Class, typename ... Param>
|
||||
Proxy_Function fun(Ret (Class::*func)(Param...) const)
|
||||
Proxy_Function fun(Ret (Class::*t_func)(Param...) const)
|
||||
{
|
||||
auto call = dispatch::detail::Const_Caller<Ret, Class, Param...>(t_func);
|
||||
|
||||
return Proxy_Function(
|
||||
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Impl<typename dispatch::detail::FunctionSignature<decltype(dispatch::detail::to_function(func)) >::Signature>>(dispatch::detail::to_function(func)));
|
||||
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Ret (const Class &, Param...), decltype(call)>>(call));
|
||||
}
|
||||
|
||||
template<typename Ret, typename Class, typename ... Param>
|
||||
Proxy_Function fun(Ret (Class::*func)(Param...))
|
||||
Proxy_Function fun(Ret (Class::*t_func)(Param...))
|
||||
{
|
||||
auto call = dispatch::detail::Caller<Ret, Class, Param...>(t_func);
|
||||
|
||||
return Proxy_Function(
|
||||
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Impl<typename dispatch::detail::FunctionSignature<decltype(dispatch::detail::to_function(func)) >::Signature>>(dispatch::detail::to_function(func)));
|
||||
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Ret (Class &, Param...), decltype(call)>>(call));
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -114,22 +81,6 @@ namespace chaiscript
|
||||
}
|
||||
|
||||
|
||||
/// \brief Creates a new Proxy_Function object from a std::function object
|
||||
/// \param[in] f std::function to expose to ChaiScript
|
||||
///
|
||||
/// \b Example:
|
||||
/// \code
|
||||
/// std::function<int (char, float, std::string)> f = get_some_function();
|
||||
/// chaiscript::ChaiScript chai;
|
||||
/// chai.add(fun(f), "some_function");
|
||||
/// \endcode
|
||||
///
|
||||
/// \sa \ref adding_functions
|
||||
template<typename T>
|
||||
Proxy_Function fun(const std::function<T> &f)
|
||||
{
|
||||
return Proxy_Function(chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Impl<T>>(f));
|
||||
}
|
||||
|
||||
|
||||
/// \brief Creates a new Proxy_Function object from a free function, member function or data member and binds the first parameter of it
|
||||
|
@ -92,6 +92,11 @@ namespace chaiscript
|
||||
return m_from;
|
||||
}
|
||||
|
||||
virtual bool bidir() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual ~Type_Conversion_Base() {}
|
||||
|
||||
protected:
|
||||
@ -107,6 +112,62 @@ namespace chaiscript
|
||||
|
||||
};
|
||||
|
||||
template<typename From, typename To>
|
||||
class Static_Caster
|
||||
{
|
||||
public:
|
||||
static Boxed_Value cast(const Boxed_Value &t_from)
|
||||
{
|
||||
if (t_from.get_type_info().bare_equal(chaiscript::user_type<From>()))
|
||||
{
|
||||
if (t_from.is_pointer())
|
||||
{
|
||||
// Dynamic cast out the contained boxed value, which we know is the type we want
|
||||
if (t_from.is_const())
|
||||
{
|
||||
return Boxed_Value(
|
||||
[&]()->std::shared_ptr<const To>{
|
||||
if (auto data = std::static_pointer_cast<const To>(detail::Cast_Helper<std::shared_ptr<const From> >::cast(t_from, nullptr)))
|
||||
{
|
||||
return data;
|
||||
} else {
|
||||
throw std::bad_cast();
|
||||
}
|
||||
}()
|
||||
);
|
||||
} else {
|
||||
return Boxed_Value(
|
||||
[&]()->std::shared_ptr<To>{
|
||||
if (auto data = std::static_pointer_cast<To>(detail::Cast_Helper<std::shared_ptr<From> >::cast(t_from, nullptr)))
|
||||
{
|
||||
return data;
|
||||
} else {
|
||||
throw std::bad_cast();
|
||||
}
|
||||
}()
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// Pull the reference out of the contained boxed value, which we know is the type we want
|
||||
if (t_from.is_const())
|
||||
{
|
||||
const From &d = detail::Cast_Helper<const From &>::cast(t_from, nullptr);
|
||||
const To &data = static_cast<const To &>(d);
|
||||
return Boxed_Value(std::cref(data));
|
||||
} else {
|
||||
From &d = detail::Cast_Helper<From &>::cast(t_from, nullptr);
|
||||
To &data = static_cast<To &>(d);
|
||||
return Boxed_Value(std::ref(data));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw chaiscript::exception::bad_boxed_dynamic_cast(t_from.get_type_info(), typeid(To), "Unknown dynamic_cast_conversion");
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
template<typename From, typename To>
|
||||
class Dynamic_Caster
|
||||
{
|
||||
@ -168,8 +229,10 @@ namespace chaiscript
|
||||
throw chaiscript::exception::bad_boxed_dynamic_cast(t_from.get_type_info(), typeid(To), "Unknown dynamic_cast_conversion");
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
template<typename Base, typename Derived>
|
||||
class Dynamic_Conversion_Impl : public Type_Conversion_Base
|
||||
{
|
||||
@ -186,10 +249,36 @@ namespace chaiscript
|
||||
|
||||
virtual Boxed_Value convert(const Boxed_Value &t_derived) const CHAISCRIPT_OVERRIDE
|
||||
{
|
||||
return Dynamic_Caster<Derived, Base>::cast(t_derived);
|
||||
return Static_Caster<Derived, Base>::cast(t_derived);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Base, typename Derived>
|
||||
class Static_Conversion_Impl : public Type_Conversion_Base
|
||||
{
|
||||
public:
|
||||
Static_Conversion_Impl()
|
||||
: Type_Conversion_Base(chaiscript::user_type<Base>(), chaiscript::user_type<Derived>())
|
||||
{
|
||||
}
|
||||
|
||||
virtual Boxed_Value convert_down(const Boxed_Value &t_base) const CHAISCRIPT_OVERRIDE
|
||||
{
|
||||
throw chaiscript::exception::bad_boxed_dynamic_cast(t_base.get_type_info(), typeid(Derived), "Unable to cast down inheritance hierarchy with non-polymorphic types");
|
||||
}
|
||||
|
||||
virtual bool bidir() const CHAISCRIPT_OVERRIDE
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual Boxed_Value convert(const Boxed_Value &t_derived) const CHAISCRIPT_OVERRIDE
|
||||
{
|
||||
return Static_Caster<Derived, Base>::cast(t_derived);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
template<typename Callable>
|
||||
class Type_Conversion_Impl : public Type_Conversion_Base
|
||||
@ -212,6 +301,12 @@ namespace chaiscript
|
||||
return m_func(t_from);
|
||||
}
|
||||
|
||||
virtual bool bidir() const CHAISCRIPT_OVERRIDE
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
Callable m_func;
|
||||
};
|
||||
@ -242,7 +337,7 @@ namespace chaiscript
|
||||
Type_Conversions(const Type_Conversions &t_other)
|
||||
: m_mutex(),
|
||||
m_conversions(t_other.get_conversions()),
|
||||
m_convertableTypes(),
|
||||
m_convertableTypes(t_other.m_convertableTypes),
|
||||
m_num_types(m_conversions.size()),
|
||||
m_thread_cache(this),
|
||||
m_conversion_saves(this)
|
||||
@ -288,7 +383,7 @@ namespace chaiscript
|
||||
const auto &types = thread_cache();
|
||||
if (types.count(to.bare_type_info()) != 0 && types.count(from.bare_type_info()) != 0)
|
||||
{
|
||||
return has_conversion(to, from) || has_conversion(from, to);
|
||||
return has_conversion(to, from);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
@ -338,7 +433,7 @@ namespace chaiscript
|
||||
bool has_conversion(const Type_Info &to, const Type_Info &from) const
|
||||
{
|
||||
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
|
||||
return find(to, from) != m_conversions.end();
|
||||
return find_bidir(to, from) != m_conversions.end();
|
||||
}
|
||||
|
||||
std::shared_ptr<detail::Type_Conversion_Base> get_conversion(const Type_Info &to, const Type_Info &from) const
|
||||
@ -356,6 +451,19 @@ namespace chaiscript
|
||||
}
|
||||
|
||||
private:
|
||||
std::set<std::shared_ptr<detail::Type_Conversion_Base> >::const_iterator find_bidir(
|
||||
const Type_Info &to, const Type_Info &from) const
|
||||
{
|
||||
return std::find_if(m_conversions.begin(), m_conversions.end(),
|
||||
[&to, &from](const std::shared_ptr<detail::Type_Conversion_Base> &conversion) -> bool
|
||||
{
|
||||
return (conversion->to().bare_equal(to) && conversion->from().bare_equal(from))
|
||||
|| (conversion->bidir() && conversion->from().bare_equal(to) && conversion->to().bare_equal(from));
|
||||
;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
std::set<std::shared_ptr<detail::Type_Conversion_Base> >::const_iterator find(
|
||||
const Type_Info &to, const Type_Info &from) const
|
||||
{
|
||||
@ -417,17 +525,26 @@ namespace chaiscript
|
||||
/// \endcode
|
||||
///
|
||||
template<typename Base, typename Derived>
|
||||
Type_Conversion base_class()
|
||||
Type_Conversion base_class(typename std::enable_if<std::is_polymorphic<Base>::value && std::is_polymorphic<Derived>::value>::type* = nullptr)
|
||||
{
|
||||
//Can only be used with related polymorphic types
|
||||
//may be expanded some day to support conversions other than child -> parent
|
||||
static_assert(std::is_base_of<Base,Derived>::value, "Classes are not related by inheritance");
|
||||
static_assert(std::is_polymorphic<Base>::value, "Base class must be polymorphic");
|
||||
static_assert(std::is_polymorphic<Derived>::value, "Derived class must be polymorphic");
|
||||
|
||||
return chaiscript::make_shared<detail::Type_Conversion_Base, detail::Dynamic_Conversion_Impl<Base, Derived>>();
|
||||
}
|
||||
|
||||
template<typename Base, typename Derived>
|
||||
Type_Conversion base_class(typename std::enable_if<!std::is_polymorphic<Base>::value || !std::is_polymorphic<Derived>::value>::type* = nullptr)
|
||||
{
|
||||
//Can only be used with related polymorphic types
|
||||
//may be expanded some day to support conversions other than child -> parent
|
||||
static_assert(std::is_base_of<Base,Derived>::value, "Classes are not related by inheritance");
|
||||
|
||||
return chaiscript::make_shared<detail::Type_Conversion_Base, detail::Static_Conversion_Impl<Base, Derived>>();
|
||||
}
|
||||
|
||||
|
||||
template<typename Callable>
|
||||
Type_Conversion type_conversion(const Type_Info &t_from, const Type_Info &t_to,
|
||||
const Callable &t_func)
|
||||
@ -458,6 +575,24 @@ namespace chaiscript
|
||||
return chaiscript::make_shared<detail::Type_Conversion_Base, detail::Type_Conversion_Impl<decltype(func)>>(user_type<From>(), user_type<To>(), func);
|
||||
}
|
||||
|
||||
template<typename To>
|
||||
Type_Conversion vector_conversion()
|
||||
{
|
||||
auto func = [](const Boxed_Value &t_bv) -> Boxed_Value {
|
||||
const std::vector<Boxed_Value> &from_vec = detail::Cast_Helper<const std::vector<Boxed_Value> &>::cast(t_bv, nullptr);
|
||||
|
||||
To vec;
|
||||
|
||||
for (const Boxed_Value &bv : from_vec) {
|
||||
vec.push_back(detail::Cast_Helper<typename To::value_type>::cast(bv, nullptr));
|
||||
}
|
||||
|
||||
return Boxed_Value(std::move(vec));
|
||||
};
|
||||
|
||||
return chaiscript::make_shared<detail::Type_Conversion_Base, detail::Type_Conversion_Impl<decltype(func)>>(user_type<std::vector<Boxed_Value>>(), user_type<To>(), func);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -62,7 +62,7 @@ namespace chaiscript
|
||||
|
||||
CHAISCRIPT_CONSTEXPR bool operator==(const Type_Info &ti) const CHAISCRIPT_NOEXCEPT
|
||||
{
|
||||
return ti.m_type_info == m_type_info
|
||||
return ti.m_type_info == m_type_info
|
||||
|| (ti.m_type_info && m_type_info && *ti.m_type_info == *m_type_info);
|
||||
}
|
||||
|
||||
@ -87,7 +87,7 @@ namespace chaiscript
|
||||
CHAISCRIPT_CONSTEXPR bool is_reference() const CHAISCRIPT_NOEXCEPT { return m_is_reference; }
|
||||
CHAISCRIPT_CONSTEXPR bool is_void() const CHAISCRIPT_NOEXCEPT { return m_is_void; }
|
||||
CHAISCRIPT_CONSTEXPR bool is_arithmetic() const CHAISCRIPT_NOEXCEPT { return m_is_arithmetic; }
|
||||
CHAISCRIPT_CONSTEXPR bool is_undef() const CHAISCRIPT_NOEXCEPT { return m_is_undef || m_bare_type_info == nullptr; }
|
||||
CHAISCRIPT_CONSTEXPR bool is_undef() const CHAISCRIPT_NOEXCEPT { return m_is_undef; }
|
||||
CHAISCRIPT_CONSTEXPR bool is_pointer() const CHAISCRIPT_NOEXCEPT { return m_is_pointer; }
|
||||
|
||||
std::string name() const
|
||||
@ -100,7 +100,7 @@ namespace chaiscript
|
||||
}
|
||||
}
|
||||
|
||||
std::string bare_name() const
|
||||
std::string bare_name() const
|
||||
{
|
||||
if (m_bare_type_info)
|
||||
{
|
||||
@ -134,12 +134,14 @@ namespace chaiscript
|
||||
{
|
||||
typedef T type;
|
||||
|
||||
CHAISCRIPT_CONSTEXPR static Type_Info get()
|
||||
static 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,
|
||||
return Type_Info(std::is_const<typename std::remove_pointer<typename std::remove_reference<T>::type>::type>::value,
|
||||
std::is_reference<T>::value, std::is_pointer<T>::value,
|
||||
std::is_void<T>::value,
|
||||
std::is_arithmetic<T>::value && !std::is_same<typename std::remove_const<T>::type, bool>::value,
|
||||
&typeid(T),
|
||||
(std::is_arithmetic<T>::value || std::is_arithmetic<typename std::remove_reference<T>::type>::value)
|
||||
&& !std::is_same<typename std::remove_const<typename std::remove_reference<T>::type>::type, bool>::value,
|
||||
&typeid(T),
|
||||
&typeid(typename Bare_Type<T>::type));
|
||||
}
|
||||
};
|
||||
@ -149,11 +151,11 @@ namespace chaiscript
|
||||
{
|
||||
typedef T type;
|
||||
|
||||
CHAISCRIPT_CONSTEXPR static Type_Info get()
|
||||
static 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,
|
||||
std::is_arithmetic<T>::value && !std::is_same<typename std::remove_const<T>::type, bool>::value,
|
||||
std::is_arithmetic<T>::value && !std::is_same<typename std::remove_const<typename std::remove_reference<T>::type>::type, bool>::value,
|
||||
&typeid(std::shared_ptr<T> ),
|
||||
&typeid(typename Bare_Type<T>::type));
|
||||
}
|
||||
@ -164,11 +166,11 @@ namespace chaiscript
|
||||
{
|
||||
typedef T type;
|
||||
|
||||
CHAISCRIPT_CONSTEXPR static Type_Info get()
|
||||
static 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,
|
||||
std::is_arithmetic<T>::value && !std::is_same<typename std::remove_const<T>::type, bool>::value,
|
||||
std::is_arithmetic<T>::value && !std::is_same<typename std::remove_const<typename std::remove_reference<T>::type>::type, bool>::value,
|
||||
&typeid(const std::shared_ptr<T> &),
|
||||
&typeid(typename Bare_Type<T>::type));
|
||||
}
|
||||
@ -179,11 +181,11 @@ namespace chaiscript
|
||||
{
|
||||
typedef T type;
|
||||
|
||||
CHAISCRIPT_CONSTEXPR static Type_Info get()
|
||||
static 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,
|
||||
std::is_arithmetic<T>::value && !std::is_same<typename std::remove_const<T>::type, bool>::value,
|
||||
std::is_arithmetic<T>::value && !std::is_same<typename std::remove_const<typename std::remove_reference<T>::type>::type, bool>::value,
|
||||
&typeid(std::reference_wrapper<T> ),
|
||||
&typeid(typename Bare_Type<T>::type));
|
||||
}
|
||||
@ -194,11 +196,11 @@ namespace chaiscript
|
||||
{
|
||||
typedef T type;
|
||||
|
||||
CHAISCRIPT_CONSTEXPR static Type_Info get()
|
||||
static 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,
|
||||
std::is_arithmetic<T>::value && !std::is_same<typename std::remove_const<T>::type, bool>::value,
|
||||
std::is_arithmetic<T>::value && !std::is_same<typename std::remove_const<typename std::remove_reference<T>::type>::type, bool>::value,
|
||||
&typeid(const std::reference_wrapper<T> &),
|
||||
&typeid(typename Bare_Type<T>::type));
|
||||
}
|
||||
@ -216,7 +218,7 @@ namespace chaiscript
|
||||
/// chaiscript::Type_Info ti = chaiscript::user_type(i);
|
||||
/// \endcode
|
||||
template<typename T>
|
||||
CHAISCRIPT_CONSTEXPR Type_Info user_type(const T &/*t*/)
|
||||
Type_Info user_type(const T &/*t*/)
|
||||
{
|
||||
return detail::Get_Type_Info<T>::get();
|
||||
}
|
||||
@ -231,7 +233,7 @@ namespace chaiscript
|
||||
/// chaiscript::Type_Info ti = chaiscript::user_type<int>();
|
||||
/// \endcode
|
||||
template<typename T>
|
||||
CHAISCRIPT_CONSTEXPR Type_Info user_type()
|
||||
Type_Info user_type()
|
||||
{
|
||||
return detail::Get_Type_Info<T>::get();
|
||||
}
|
||||
|
@ -276,10 +276,13 @@ namespace chaiscript
|
||||
template<typename T>
|
||||
static std::string format_location(const T &t)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << "(" << t->filename() << " " << t->start().line << ", " << t->start().column << ")";
|
||||
|
||||
return oss.str();
|
||||
if (t) {
|
||||
std::ostringstream oss;
|
||||
oss << "(" << t->filename() << " " << t->start().line << ", " << t->start().column << ")";
|
||||
return oss.str();
|
||||
} else {
|
||||
return "(internal)";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -470,13 +473,13 @@ namespace chaiscript
|
||||
oss << t_prepend << "(" << ast_node_type_to_string(this->identifier) << ") "
|
||||
<< this->text << " : " << this->location.start.line << ", " << this->location.start.column << '\n';
|
||||
|
||||
for (size_t j = 0; j < this->children.size(); ++j) {
|
||||
oss << this->children[j]->to_string(t_prepend + " ");
|
||||
for (auto & elem : this->children) {
|
||||
oss << elem->to_string(t_prepend + " ");
|
||||
}
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
Boxed_Value eval(chaiscript::detail::Dispatch_Engine &t_e) const
|
||||
Boxed_Value eval(const chaiscript::detail::Dispatch_State &t_e) const
|
||||
{
|
||||
try {
|
||||
return eval_internal(t_e);
|
||||
@ -512,7 +515,7 @@ namespace chaiscript
|
||||
{
|
||||
}
|
||||
|
||||
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &) const
|
||||
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &) const
|
||||
{
|
||||
throw std::runtime_error("Undispatched ast_node (internal error)");
|
||||
}
|
||||
@ -554,21 +557,20 @@ namespace chaiscript
|
||||
Scope_Push_Pop(const Scope_Push_Pop &) = delete;
|
||||
Scope_Push_Pop& operator=(const Scope_Push_Pop &) = delete;
|
||||
|
||||
Scope_Push_Pop(chaiscript::detail::Dispatch_Engine &t_de)
|
||||
: m_de(t_de)
|
||||
Scope_Push_Pop(const chaiscript::detail::Dispatch_State &t_ds)
|
||||
: m_ds(t_ds)
|
||||
{
|
||||
m_de.new_scope();
|
||||
m_ds.get()->new_scope(m_ds.get().stack_holder());
|
||||
}
|
||||
|
||||
~Scope_Push_Pop()
|
||||
{
|
||||
m_de.pop_scope();
|
||||
m_ds.get()->pop_scope(m_ds.get().stack_holder());
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
|
||||
chaiscript::detail::Dispatch_Engine &m_de;
|
||||
std::reference_wrapper<const chaiscript::detail::Dispatch_State> m_ds;
|
||||
};
|
||||
|
||||
/// Creates a new function call and pops it on destruction
|
||||
@ -577,31 +579,30 @@ namespace chaiscript
|
||||
Function_Push_Pop(const Function_Push_Pop &) = delete;
|
||||
Function_Push_Pop& operator=(const Function_Push_Pop &) = delete;
|
||||
|
||||
Function_Push_Pop(chaiscript::detail::Dispatch_Engine &t_de)
|
||||
: m_de(t_de)
|
||||
Function_Push_Pop(const chaiscript::detail::Dispatch_State &t_ds)
|
||||
: m_ds(t_ds)
|
||||
{
|
||||
m_de.new_function_call();
|
||||
m_ds.get()->new_function_call(m_ds.get().stack_holder());
|
||||
}
|
||||
|
||||
~Function_Push_Pop()
|
||||
{
|
||||
m_de.pop_function_call();
|
||||
m_ds.get()->pop_function_call(m_ds.get().stack_holder());
|
||||
}
|
||||
|
||||
void save_params(const std::vector<Boxed_Value> &t_params)
|
||||
{
|
||||
m_de.save_function_params(t_params);
|
||||
m_ds.get()->save_function_params(t_params);
|
||||
}
|
||||
|
||||
void save_params(std::initializer_list<Boxed_Value> t_params)
|
||||
{
|
||||
m_de.save_function_params(std::move(t_params));
|
||||
m_ds.get()->save_function_params(std::move(t_params));
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
|
||||
chaiscript::detail::Dispatch_Engine &m_de;
|
||||
std::reference_wrapper<const chaiscript::detail::Dispatch_State> m_ds;
|
||||
};
|
||||
|
||||
/// Creates a new scope then pops it on destruction
|
||||
@ -610,21 +611,20 @@ namespace chaiscript
|
||||
Stack_Push_Pop(const Stack_Push_Pop &) = delete;
|
||||
Stack_Push_Pop& operator=(const Stack_Push_Pop &) = delete;
|
||||
|
||||
Stack_Push_Pop(chaiscript::detail::Dispatch_Engine &t_de)
|
||||
: m_de(t_de)
|
||||
Stack_Push_Pop(const chaiscript::detail::Dispatch_State &t_ds)
|
||||
: m_ds(t_ds)
|
||||
{
|
||||
m_de.new_stack();
|
||||
m_ds.get()->new_stack(m_ds.get().stack_holder());
|
||||
}
|
||||
|
||||
~Stack_Push_Pop()
|
||||
{
|
||||
m_de.pop_stack();
|
||||
m_ds.get()->pop_stack(m_ds.get().stack_holder());
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
|
||||
chaiscript::detail::Dispatch_Engine &m_de;
|
||||
std::reference_wrapper<const chaiscript::detail::Dispatch_State> m_ds;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -37,14 +37,13 @@
|
||||
#ifdef CHAISCRIPT_WINDOWS
|
||||
#define VC_EXTRA_LEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <Windows.h>
|
||||
#include <windows.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#include "../dispatchkit/exception_specification.hpp"
|
||||
#include "chaiscript_parser.hpp"
|
||||
#include "chaiscript_prelude.chai"
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
@ -356,57 +355,57 @@ namespace chaiscript
|
||||
add(t_lib);
|
||||
}
|
||||
|
||||
m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::dump_system, std::ref(m_engine)), "dump_system");
|
||||
m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::dump_object, std::ref(m_engine)), "dump_object");
|
||||
m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::is_type, std::ref(m_engine)), "is_type");
|
||||
m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::type_name, std::ref(m_engine)), "type_name");
|
||||
m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::function_exists, std::ref(m_engine)), "function_exists");
|
||||
m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::get_function_objects, std::ref(m_engine)), "get_functions");
|
||||
m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::get_scripting_objects, std::ref(m_engine)), "get_objects");
|
||||
m_engine.add(chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Dynamic_Proxy_Function>(
|
||||
m_engine.add(fun([this](){ m_engine.dump_system(); }), "dump_system");
|
||||
m_engine.add(fun([this](const Boxed_Value &t_bv){ m_engine.dump_object(t_bv); }), "dump_object");
|
||||
m_engine.add(fun([this](const Boxed_Value &t_bv, const std::string &t_type){ return m_engine.is_type(t_bv, t_type); }), "is_type");
|
||||
m_engine.add(fun([this](const Boxed_Value &t_bv){ return m_engine.type_name(t_bv); }), "type_name");
|
||||
m_engine.add(fun([this](const std::string &t_f){ return m_engine.function_exists(t_f); }), "function_exists");
|
||||
m_engine.add(fun([this](){ return m_engine.get_function_objects(); }), "get_functions");
|
||||
m_engine.add(fun([this](){ return m_engine.get_scripting_objects(); }), "get_objects");
|
||||
|
||||
m_engine.add(
|
||||
dispatch::make_dynamic_proxy_function(
|
||||
[this](const std::vector<Boxed_Value> &t_params) {
|
||||
return m_engine.call_exists(t_params);
|
||||
}), "call_exists");
|
||||
})
|
||||
, "call_exists");
|
||||
|
||||
// m_engine.add(fun<Boxed_Value (const dispatch::Proxy_Function_Base *, const std::vector<Boxed_Value> &)>(std::bind(&chaiscript::dispatch::Proxy_Function_Base::operator(), std::placeholders::_1, std::placeholders::_2, std::ref(m_engine.conversions()))), "call");
|
||||
//
|
||||
m_engine.add(fun<Boxed_Value (const dispatch::Proxy_Function_Base &, const std::vector<Boxed_Value> &)>(
|
||||
m_engine.add(fun(
|
||||
[=](const dispatch::Proxy_Function_Base &t_fun, const std::vector<Boxed_Value> &t_params) {
|
||||
return t_fun(t_params, this->m_engine.conversions());
|
||||
}), "call");
|
||||
|
||||
m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::get_type_name, std::ref(m_engine)), "name");
|
||||
m_engine.add(fun([this](const Type_Info &t_ti){ return m_engine.get_type_name(t_ti); }), "name");
|
||||
|
||||
m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::get_type, std::ref(m_engine)), "type");
|
||||
m_engine.add(fun<chaiscript::Type_Info (const std::string &)>([this](const std::string &t_type_name){ return this->m_engine.get_type(t_type_name, true); }), "type");
|
||||
m_engine.add(fun([this](const std::string &t_type_name, bool t_throw){ return m_engine.get_type(t_type_name, t_throw); }), "type");
|
||||
m_engine.add(fun([this](const std::string &t_type_name){ return m_engine.get_type(t_type_name, true); }), "type");
|
||||
|
||||
m_engine.add(fun<void(const Type_Info &, const Type_Info &, const std::function<Boxed_Value(const Boxed_Value &)> &)>(
|
||||
m_engine.add(fun(
|
||||
[=](const Type_Info &t_from, const Type_Info &t_to, const std::function<Boxed_Value (const Boxed_Value &)> &t_func) {
|
||||
m_engine.add(chaiscript::type_conversion(t_from, t_to, t_func));
|
||||
}
|
||||
), "add_type_conversion");
|
||||
|
||||
|
||||
typedef std::string (ChaiScript::*load_mod_1)(const std::string&);
|
||||
typedef void (ChaiScript::*load_mod_2)(const std::string&, const std::string&);
|
||||
|
||||
m_engine.add(fun(static_cast<load_mod_1>(&ChaiScript::load_module), this), "load_module");
|
||||
m_engine.add(fun(static_cast<load_mod_2>(&ChaiScript::load_module), this), "load_module");
|
||||
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");
|
||||
|
||||
m_engine.add(fun(&ChaiScript::use, this), "use");
|
||||
m_engine.add(fun(&ChaiScript::internal_eval_file, this), "eval_file");
|
||||
m_engine.add(fun(&ChaiScript::internal_eval, this), "eval");
|
||||
m_engine.add(fun(&ChaiScript::internal_eval_ast, this), "eval");
|
||||
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 internal_eval_ast(t_ast); }), "eval");
|
||||
|
||||
m_engine.add(fun(&ChaiScript::version_major), "version_major");
|
||||
m_engine.add(fun(&ChaiScript::version_minor), "version_minor");
|
||||
m_engine.add(fun(&ChaiScript::version_patch), "version_patch");
|
||||
m_engine.add(fun(&ChaiScript::version), "version");
|
||||
|
||||
m_engine.add(fun(&ChaiScript::add_global_const, this), "add_global_const");
|
||||
m_engine.add(fun(&ChaiScript::add_global, this), "add_global");
|
||||
m_engine.add(fun([this](const Boxed_Value &t_bv, const std::string &t_name){ add_global_const(t_bv, t_name); }), "add_global_const");
|
||||
m_engine.add(fun([this](const Boxed_Value &t_bv, const std::string &t_name){ add_global(t_bv, t_name); }), "add_global");
|
||||
|
||||
do_eval(ChaiScript_Prelude::chaiscript_prelude(), "standard prelude");
|
||||
}
|
||||
|
||||
|
||||
|
@ -45,7 +45,8 @@ namespace chaiscript
|
||||
{
|
||||
/// Helper function that will set up the scope around a function call, including handling the named function parameters
|
||||
static Boxed_Value eval_function(chaiscript::detail::Dispatch_Engine &t_ss, const AST_NodePtr &t_node, const std::vector<std::string> &t_param_names, const std::vector<Boxed_Value> &t_vals, const std::map<std::string, Boxed_Value> &t_locals=std::map<std::string, Boxed_Value>()) {
|
||||
chaiscript::eval::detail::Scope_Push_Pop spp(t_ss);
|
||||
chaiscript::detail::Dispatch_State state(t_ss);
|
||||
chaiscript::eval::detail::Scope_Push_Pop spp(state);
|
||||
|
||||
for (const auto &local : t_locals) {
|
||||
t_ss.add_object(local.first, local.second);
|
||||
@ -56,7 +57,7 @@ namespace chaiscript
|
||||
}
|
||||
|
||||
try {
|
||||
return t_node->eval(t_ss);
|
||||
return t_node->eval(state);
|
||||
} catch (detail::Return_Value &rv) {
|
||||
return std::move(rv.retval);
|
||||
}
|
||||
@ -71,7 +72,7 @@ namespace chaiscript
|
||||
{ }
|
||||
|
||||
virtual ~Binary_Operator_AST_Node() {}
|
||||
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE {
|
||||
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE {
|
||||
return do_oper(t_ss, m_oper, text,
|
||||
this->children[0]->eval(t_ss),
|
||||
this->children[1]->eval(t_ss));
|
||||
@ -83,7 +84,7 @@ namespace chaiscript
|
||||
}
|
||||
|
||||
protected:
|
||||
Boxed_Value do_oper(chaiscript::detail::Dispatch_Engine &t_ss,
|
||||
Boxed_Value do_oper(const chaiscript::detail::Dispatch_State &t_ss,
|
||||
Operators::Opers t_oper, const std::string &t_oper_string, const Boxed_Value &t_lhs, const Boxed_Value &t_rhs) const
|
||||
{
|
||||
try {
|
||||
@ -101,11 +102,11 @@ namespace chaiscript
|
||||
chaiscript::eval::detail::Function_Push_Pop fpp(t_ss);
|
||||
fpp.save_params({t_lhs, t_rhs});
|
||||
chaiscript::eval::detail::Stack_Push_Pop spp(t_ss);
|
||||
return t_ss.call_function(t_oper_string, t_lhs, t_rhs);
|
||||
return t_ss->call_function(t_oper_string, t_lhs, t_rhs);
|
||||
}
|
||||
}
|
||||
catch(const exception::dispatch_error &e){
|
||||
throw exception::eval_error("Can not find appropriate '" + t_oper_string + "' operator.", e.parameters, e.functions, false, t_ss);
|
||||
throw exception::eval_error("Can not find appropriate '" + t_oper_string + "' operator.", e.parameters, e.functions, false, *t_ss);
|
||||
}
|
||||
}
|
||||
|
||||
@ -119,7 +120,7 @@ namespace chaiscript
|
||||
AST_Node(std::move(t_ast_node_text), AST_Node_Type::Int, std::move(t_loc)),
|
||||
m_value(std::move(t_bv)) { }
|
||||
virtual ~Int_AST_Node() {}
|
||||
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &) const CHAISCRIPT_OVERRIDE{
|
||||
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &) const CHAISCRIPT_OVERRIDE{
|
||||
return m_value;
|
||||
}
|
||||
|
||||
@ -134,7 +135,7 @@ namespace chaiscript
|
||||
AST_Node(std::move(t_ast_node_text), AST_Node_Type::Float, std::move(t_loc)),
|
||||
m_value(std::move(t_bv)) { }
|
||||
virtual ~Float_AST_Node() {}
|
||||
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &) const CHAISCRIPT_OVERRIDE{
|
||||
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &) const CHAISCRIPT_OVERRIDE{
|
||||
return m_value;
|
||||
}
|
||||
|
||||
@ -147,17 +148,17 @@ namespace chaiscript
|
||||
public:
|
||||
Id_AST_Node(const std::string &t_ast_node_text, Parse_Location t_loc) :
|
||||
AST_Node(t_ast_node_text, AST_Node_Type::Id, std::move(t_loc)),
|
||||
m_value(get_value(t_ast_node_text))
|
||||
m_value(get_value(t_ast_node_text)), m_loc(0)
|
||||
{ }
|
||||
|
||||
virtual ~Id_AST_Node() {}
|
||||
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE {
|
||||
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE {
|
||||
if (!m_value.is_undef())
|
||||
{
|
||||
return m_value;
|
||||
} else {
|
||||
try {
|
||||
return t_ss.get_object(this->text);
|
||||
return t_ss->get_object(this->text, m_loc);
|
||||
}
|
||||
catch (std::exception &) {
|
||||
throw exception::eval_error("Can not find object: " + this->text);
|
||||
@ -170,21 +171,22 @@ namespace chaiscript
|
||||
{
|
||||
if (t_text == "true") {
|
||||
return const_var(true);
|
||||
}
|
||||
else if (t_text == "false") {
|
||||
} else if (t_text == "false") {
|
||||
return const_var(false);
|
||||
}
|
||||
else if (t_text == "Infinity") {
|
||||
} else if (t_text == "Infinity") {
|
||||
return const_var(std::numeric_limits<double>::infinity());
|
||||
}
|
||||
else if (t_text == "NaN") {
|
||||
} else if (t_text == "NaN") {
|
||||
return const_var(std::numeric_limits<double>::quiet_NaN());
|
||||
} else if (t_text == "_") {
|
||||
return Boxed_Value(std::make_shared<dispatch::Placeholder_Object>());
|
||||
} else {
|
||||
return Boxed_Value();
|
||||
}
|
||||
}
|
||||
|
||||
Boxed_Value m_value;
|
||||
|
||||
mutable std::atomic_uint_fast32_t m_loc;
|
||||
};
|
||||
|
||||
struct Char_AST_Node : public AST_Node {
|
||||
@ -219,7 +221,7 @@ namespace chaiscript
|
||||
Fun_Call_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_NodePtr> t_children) :
|
||||
AST_Node(std::move(t_ast_node_text), AST_Node_Type::Fun_Call, std::move(t_loc), std::move(t_children)) { }
|
||||
virtual ~Fun_Call_AST_Node() {}
|
||||
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE{
|
||||
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE{
|
||||
chaiscript::eval::detail::Function_Push_Pop fpp(t_ss);
|
||||
|
||||
std::vector<Boxed_Value> params;
|
||||
@ -235,16 +237,16 @@ namespace chaiscript
|
||||
|
||||
try {
|
||||
chaiscript::eval::detail::Stack_Push_Pop spp(t_ss);
|
||||
return (*t_ss.boxed_cast<const Const_Proxy_Function &>(fn))(params, t_ss.conversions());
|
||||
return (*t_ss->boxed_cast<const Const_Proxy_Function &>(fn))(params, t_ss->conversions());
|
||||
}
|
||||
catch(const exception::dispatch_error &e){
|
||||
throw exception::eval_error(std::string(e.what()) + " with function '" + this->children[0]->text + "'", e.parameters, e.functions, false, t_ss);
|
||||
throw exception::eval_error(std::string(e.what()) + " with function '" + this->children[0]->text + "'", e.parameters, e.functions, false, *t_ss);
|
||||
}
|
||||
catch(const exception::bad_boxed_cast &){
|
||||
try {
|
||||
Const_Proxy_Function f = t_ss.boxed_cast<const Const_Proxy_Function &>(fn);
|
||||
Const_Proxy_Function f = t_ss->boxed_cast<const Const_Proxy_Function &>(fn);
|
||||
// handle the case where there is only 1 function to try to call and dispatch fails on it
|
||||
throw exception::eval_error("Error calling function '" + this->children[0]->text + "'", params, {f}, false, t_ss);
|
||||
throw exception::eval_error("Error calling function '" + this->children[0]->text + "'", params, {f}, false, *t_ss);
|
||||
} catch (const exception::bad_boxed_cast &) {
|
||||
throw exception::eval_error("'" + this->children[0]->pretty_print() + "' does not evaluate to a function.");
|
||||
}
|
||||
@ -282,29 +284,6 @@ namespace chaiscript
|
||||
|
||||
};
|
||||
|
||||
struct Fun_Lookup_AST_Node : public AST_Node {
|
||||
public:
|
||||
Fun_Lookup_AST_Node(const std::string &t_fun_name)
|
||||
: AST_Node(t_fun_name, 0, Parse_Location("<EVAL>"))
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~Fun_Lookup_AST_Node() {}
|
||||
|
||||
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE {
|
||||
try {
|
||||
Boxed_Value bv = t_ss.get_object(text);
|
||||
t_ss.add_object(text, bv);
|
||||
std::cout << " Saved fun lookup: " << text << '\n';
|
||||
return bv;
|
||||
} catch (...) {
|
||||
return Boxed_Value();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/// Used in the context of in-string ${} evals, so that no new scope is created
|
||||
@ -315,10 +294,11 @@ namespace chaiscript
|
||||
{ assert(children.size() == 2); }
|
||||
|
||||
virtual ~Inplace_Fun_Call_AST_Node() {}
|
||||
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE{
|
||||
std::vector<Boxed_Value> params;
|
||||
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE{
|
||||
chaiscript::eval::detail::Function_Push_Pop fpp(t_ss);
|
||||
|
||||
std::vector<Boxed_Value> params;
|
||||
params.reserve(this->children[1]->children.size());
|
||||
for (const auto &child : this->children[1]->children) {
|
||||
params.push_back(child->eval(t_ss));
|
||||
}
|
||||
@ -328,18 +308,18 @@ namespace chaiscript
|
||||
try {
|
||||
Boxed_Value bv = this->children[0]->eval(t_ss);
|
||||
try {
|
||||
fn = t_ss.boxed_cast<const Const_Proxy_Function &>(bv);
|
||||
fn = t_ss->boxed_cast<const Const_Proxy_Function &>(bv);
|
||||
} catch (const exception::bad_boxed_cast &) {
|
||||
throw exception::eval_error("'" + this->children[0]->pretty_print() + "' does not evaluate to a function.");
|
||||
}
|
||||
return (*fn)(params, t_ss.conversions());
|
||||
return (*fn)(params, t_ss->conversions());
|
||||
}
|
||||
catch(const exception::dispatch_error &e){
|
||||
throw exception::eval_error(std::string(e.what()) + " with function '" + this->children[0]->text + "'", e.parameters, e.functions, false, t_ss);
|
||||
throw exception::eval_error(std::string(e.what()) + " with function '" + this->children[0]->text + "'", e.parameters, e.functions, false, *t_ss);
|
||||
}
|
||||
catch(const exception::bad_boxed_cast &){
|
||||
// handle the case where there is only 1 function to try to call and dispatch fails on it
|
||||
throw exception::eval_error("Error calling function '" + this->children[0]->text + "'", params, {fn}, false, t_ss);
|
||||
throw exception::eval_error("Error calling function '" + this->children[0]->text + "'", params, {fn}, false, *t_ss);
|
||||
}
|
||||
catch(const exception::arity_error &e){
|
||||
throw exception::eval_error(std::string(e.what()) + " with function '" + this->children[0]->text + "'");
|
||||
@ -438,17 +418,17 @@ namespace chaiscript
|
||||
return retval;
|
||||
}
|
||||
|
||||
static std::pair<std::string, Type_Info> get_arg_type(const AST_NodePtr &t_node, chaiscript::detail::Dispatch_Engine &t_ss)
|
||||
static std::pair<std::string, Type_Info> get_arg_type(const AST_NodePtr &t_node, const chaiscript::detail::Dispatch_State &t_ss)
|
||||
{
|
||||
if (t_node->children.size() < 2)
|
||||
{
|
||||
return std::pair<std::string, Type_Info>();
|
||||
} else {
|
||||
return std::pair<std::string, Type_Info>(t_node->children[0]->text, t_ss.get_type(t_node->children[0]->text, false));
|
||||
return std::pair<std::string, Type_Info>(t_node->children[0]->text, t_ss->get_type(t_node->children[0]->text, false));
|
||||
}
|
||||
}
|
||||
|
||||
static dispatch::Param_Types get_arg_types(const AST_NodePtr &t_node, chaiscript::detail::Dispatch_Engine &t_ss) {
|
||||
static dispatch::Param_Types get_arg_types(const AST_NodePtr &t_node, const chaiscript::detail::Dispatch_State &t_ss) {
|
||||
std::vector<std::pair<std::string, Type_Info>> retval;
|
||||
|
||||
for (const auto &child : t_node->children)
|
||||
@ -470,7 +450,7 @@ namespace chaiscript
|
||||
Operators::Opers m_oper;
|
||||
|
||||
virtual ~Equation_AST_Node() {}
|
||||
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE {
|
||||
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE {
|
||||
chaiscript::eval::detail::Function_Push_Pop fpp(t_ss);
|
||||
Boxed_Value rhs = this->children[2]->eval(t_ss);
|
||||
Boxed_Value lhs = this->children[0]->eval(t_ss);
|
||||
@ -503,21 +483,21 @@ namespace chaiscript
|
||||
} else {
|
||||
if (!rhs.is_return_value())
|
||||
{
|
||||
rhs = t_ss.call_function("clone", rhs);
|
||||
rhs = t_ss->call_function("clone", rhs);
|
||||
}
|
||||
rhs.reset_return_value();
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
return t_ss.call_function(this->children[1]->text, std::move(lhs), rhs);
|
||||
return t_ss->call_function(this->children[1]->text, std::move(lhs), rhs);
|
||||
}
|
||||
catch(const exception::dispatch_error &e){
|
||||
throw exception::eval_error("Unable to find appropriate'" + this->children[1]->text + "' operator.", e.parameters, e.functions, false, t_ss);
|
||||
throw exception::eval_error("Unable to find appropriate'" + this->children[1]->text + "' operator.", e.parameters, e.functions, false, *t_ss);
|
||||
}
|
||||
}
|
||||
catch(const exception::dispatch_error &e){
|
||||
throw exception::eval_error("Missing clone or copy constructor for right hand side of equation", e.parameters, e.functions, false, t_ss);
|
||||
throw exception::eval_error("Missing clone or copy constructor for right hand side of equation", e.parameters, e.functions, false, *t_ss);
|
||||
}
|
||||
}
|
||||
else if (this->children[1]->text == ":=") {
|
||||
@ -529,9 +509,9 @@ namespace chaiscript
|
||||
}
|
||||
else {
|
||||
try {
|
||||
return t_ss.call_function(this->children[1]->text, std::move(lhs), rhs);
|
||||
return t_ss->call_function(this->children[1]->text, std::move(lhs), rhs);
|
||||
} catch(const exception::dispatch_error &e){
|
||||
throw exception::eval_error("Unable to find appropriate'" + this->children[1]->text + "' operator.", e.parameters, e.functions, false, t_ss);
|
||||
throw exception::eval_error("Unable to find appropriate'" + this->children[1]->text + "' operator.", e.parameters, e.functions, false, *t_ss);
|
||||
}
|
||||
}
|
||||
|
||||
@ -544,7 +524,7 @@ namespace chaiscript
|
||||
Global_Decl_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_NodePtr> t_children) :
|
||||
AST_Node(std::move(t_ast_node_text), AST_Node_Type::Global_Decl, std::move(t_loc), std::move(t_children)) { }
|
||||
virtual ~Global_Decl_AST_Node() {}
|
||||
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE {
|
||||
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE {
|
||||
|
||||
const std::string &idname =
|
||||
[&]()->const std::string &{
|
||||
@ -556,7 +536,7 @@ namespace chaiscript
|
||||
}();
|
||||
|
||||
try {
|
||||
return t_ss.add_global_no_throw(Boxed_Value(), idname);
|
||||
return t_ss->add_global_no_throw(Boxed_Value(), idname);
|
||||
}
|
||||
catch (const exception::reserved_word_error &) {
|
||||
throw exception::eval_error("Reserved word used as global '" + idname + "'");
|
||||
@ -571,7 +551,7 @@ namespace chaiscript
|
||||
Var_Decl_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_NodePtr> t_children) :
|
||||
AST_Node(std::move(t_ast_node_text), AST_Node_Type::Var_Decl, std::move(t_loc), std::move(t_children)) { }
|
||||
virtual ~Var_Decl_AST_Node() {}
|
||||
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE {
|
||||
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE {
|
||||
if (this->children[0]->identifier == AST_Node_Type::Reference)
|
||||
{
|
||||
return this->children[0]->eval(t_ss);
|
||||
@ -580,7 +560,7 @@ namespace chaiscript
|
||||
|
||||
try {
|
||||
Boxed_Value bv;
|
||||
t_ss.add_object(idname, bv);
|
||||
t_ss->add_object(idname, bv);
|
||||
return bv;
|
||||
}
|
||||
catch (const exception::reserved_word_error &) {
|
||||
@ -605,7 +585,7 @@ namespace chaiscript
|
||||
Array_Call_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_NodePtr> t_children) :
|
||||
AST_Node(std::move(t_ast_node_text), AST_Node_Type::Array_Call, std::move(t_loc), std::move(t_children)) { }
|
||||
virtual ~Array_Call_AST_Node() {}
|
||||
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE{
|
||||
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE{
|
||||
chaiscript::eval::detail::Function_Push_Pop fpp(t_ss);
|
||||
|
||||
std::vector<Boxed_Value> params{children[0]->eval(t_ss), children[1]->eval(t_ss)};
|
||||
@ -613,10 +593,10 @@ namespace chaiscript
|
||||
try {
|
||||
chaiscript::eval::detail::Stack_Push_Pop spp(t_ss);
|
||||
fpp.save_params(params);
|
||||
return t_ss.call_function("[]", params);
|
||||
return t_ss->call_function("[]", params);
|
||||
}
|
||||
catch(const exception::dispatch_error &e){
|
||||
throw exception::eval_error("Can not find appropriate array lookup operator '[]'.", e.parameters, e.functions, false, t_ss );
|
||||
throw exception::eval_error("Can not find appropriate array lookup operator '[]'.", e.parameters, e.functions, false, *t_ss );
|
||||
}
|
||||
|
||||
}
|
||||
@ -646,7 +626,7 @@ namespace chaiscript
|
||||
children[2]->children[0]->text:children[2]->text) { }
|
||||
|
||||
virtual ~Dot_Access_AST_Node() {}
|
||||
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE{
|
||||
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE{
|
||||
chaiscript::eval::detail::Function_Push_Pop fpp(t_ss);
|
||||
|
||||
Boxed_Value retval = children[0]->eval(t_ss);
|
||||
@ -664,15 +644,15 @@ namespace chaiscript
|
||||
|
||||
try {
|
||||
chaiscript::eval::detail::Stack_Push_Pop spp(t_ss);
|
||||
t_ss.add_object("this", retval);
|
||||
retval = t_ss.call_member(m_fun_name, std::move(params), has_function_params);
|
||||
t_ss->add_object("this", retval);
|
||||
retval = t_ss->call_member(m_fun_name, std::move(params), has_function_params);
|
||||
}
|
||||
catch(const exception::dispatch_error &e){
|
||||
if (e.functions.empty())
|
||||
{
|
||||
throw exception::eval_error("'" + m_fun_name + "' is not a function.");
|
||||
} else {
|
||||
throw exception::eval_error(std::string(e.what()) + " for function '" + m_fun_name + "'", e.parameters, e.functions, true, t_ss);
|
||||
throw exception::eval_error(std::string(e.what()) + " for function '" + m_fun_name + "'", e.parameters, e.functions, true, *t_ss);
|
||||
}
|
||||
}
|
||||
catch(detail::Return_Value &rv) {
|
||||
@ -681,10 +661,10 @@ namespace chaiscript
|
||||
|
||||
if (this->children[2]->identifier == AST_Node_Type::Array_Call) {
|
||||
try {
|
||||
retval = t_ss.call_function("[]", retval, this->children[2]->children[1]->eval(t_ss));
|
||||
retval = t_ss->call_function("[]", retval, this->children[2]->children[1]->eval(t_ss));
|
||||
}
|
||||
catch(const exception::dispatch_error &e){
|
||||
throw exception::eval_error("Can not find appropriate array lookup operator '[]'.", e.parameters, e.functions, true, t_ss);
|
||||
throw exception::eval_error("Can not find appropriate array lookup operator '[]'.", e.parameters, e.functions, true, *t_ss);
|
||||
}
|
||||
}
|
||||
|
||||
@ -702,7 +682,7 @@ namespace chaiscript
|
||||
m_value(const_var(text)) { }
|
||||
virtual ~Quoted_String_AST_Node() {}
|
||||
|
||||
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &) const CHAISCRIPT_OVERRIDE {
|
||||
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &) const CHAISCRIPT_OVERRIDE {
|
||||
return m_value;
|
||||
}
|
||||
|
||||
@ -723,7 +703,7 @@ namespace chaiscript
|
||||
m_value(const_var(char(text.at(0)))) { }
|
||||
|
||||
virtual ~Single_Quoted_String_AST_Node() {}
|
||||
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &) const CHAISCRIPT_OVERRIDE{
|
||||
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &) const CHAISCRIPT_OVERRIDE{
|
||||
return m_value;
|
||||
}
|
||||
|
||||
@ -744,7 +724,7 @@ namespace chaiscript
|
||||
|
||||
virtual ~Lambda_AST_Node() {}
|
||||
|
||||
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE{
|
||||
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE{
|
||||
|
||||
const auto captures = [&]()->std::map<std::string, Boxed_Value>{
|
||||
std::map<std::string, Boxed_Value> named_captures;
|
||||
@ -759,13 +739,17 @@ namespace chaiscript
|
||||
const auto param_types = Arg_List_AST_Node::get_arg_types(this->children[1], t_ss);
|
||||
|
||||
const auto &lambda_node = this->children.back();
|
||||
std::reference_wrapper<chaiscript::detail::Dispatch_Engine> engine(*t_ss);
|
||||
|
||||
return Boxed_Value(chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Dynamic_Proxy_Function>(
|
||||
[&t_ss, lambda_node, param_names, captures](const std::vector<Boxed_Value> &t_params)
|
||||
{
|
||||
return detail::eval_function(t_ss, lambda_node, param_names, t_params, captures);
|
||||
},
|
||||
static_cast<int>(numparams), lambda_node, param_types));
|
||||
return Boxed_Value(
|
||||
dispatch::make_dynamic_proxy_function(
|
||||
[engine, lambda_node, param_names, captures](const std::vector<Boxed_Value> &t_params)
|
||||
{
|
||||
return detail::eval_function(engine, lambda_node, param_names, t_params, captures);
|
||||
},
|
||||
static_cast<int>(numparams), lambda_node, param_types
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
private:
|
||||
@ -779,7 +763,7 @@ namespace chaiscript
|
||||
AST_Node(std::move(t_ast_node_text), AST_Node_Type::Block, std::move(t_loc), std::move(t_children)) { }
|
||||
virtual ~Block_AST_Node() {}
|
||||
|
||||
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE{
|
||||
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE{
|
||||
chaiscript::eval::detail::Scope_Push_Pop spp(t_ss);
|
||||
|
||||
const auto num_children = children.size();
|
||||
@ -797,7 +781,7 @@ namespace chaiscript
|
||||
AST_Node(std::move(t_ast_node_text), AST_Node_Type::Def, std::move(t_loc), std::move(t_children)) { }
|
||||
|
||||
virtual ~Def_AST_Node() {}
|
||||
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE{
|
||||
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE{
|
||||
std::vector<std::string> t_param_names;
|
||||
size_t numparams = 0;
|
||||
AST_NodePtr guardnode;
|
||||
@ -822,25 +806,29 @@ namespace chaiscript
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<dispatch::Dynamic_Proxy_Function> guard;
|
||||
std::reference_wrapper<chaiscript::detail::Dispatch_Engine> engine(*t_ss);
|
||||
std::shared_ptr<dispatch::Proxy_Function_Base> guard;
|
||||
if (guardnode) {
|
||||
guard = std::make_shared<dispatch::Dynamic_Proxy_Function>
|
||||
([&t_ss, guardnode, t_param_names](const std::vector<Boxed_Value> &t_params)
|
||||
{
|
||||
return detail::eval_function(t_ss, guardnode, t_param_names, t_params);
|
||||
}, static_cast<int>(numparams), guardnode);
|
||||
guard = dispatch::make_dynamic_proxy_function(
|
||||
[engine, guardnode, t_param_names](const std::vector<Boxed_Value> &t_params)
|
||||
{
|
||||
return detail::eval_function(engine, guardnode, t_param_names, t_params);
|
||||
},
|
||||
static_cast<int>(numparams), guardnode);
|
||||
}
|
||||
|
||||
try {
|
||||
const std::string & l_function_name = this->children[0]->text;
|
||||
const std::string & l_annotation = this->annotation?this->annotation->text:"";
|
||||
const auto & func_node = this->children.back();
|
||||
t_ss.add(chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Dynamic_Proxy_Function>
|
||||
([&t_ss, guardnode, func_node, t_param_names](const std::vector<Boxed_Value> &t_params)
|
||||
{
|
||||
return detail::eval_function(t_ss, func_node, t_param_names, t_params);
|
||||
}, static_cast<int>(numparams), this->children.back(),
|
||||
param_types, l_annotation, guard), l_function_name);
|
||||
t_ss->add(
|
||||
dispatch::make_dynamic_proxy_function(
|
||||
[engine, guardnode, func_node, t_param_names](const std::vector<Boxed_Value> &t_params)
|
||||
{
|
||||
return detail::eval_function(engine, func_node, t_param_names, t_params);
|
||||
},
|
||||
static_cast<int>(numparams), this->children.back(),
|
||||
param_types, l_annotation, guard), l_function_name);
|
||||
}
|
||||
catch (const exception::reserved_word_error &e) {
|
||||
throw exception::eval_error("Reserved word used as function name '" + e.word() + "'");
|
||||
@ -857,7 +845,7 @@ namespace chaiscript
|
||||
While_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_NodePtr> t_children) :
|
||||
AST_Node(std::move(t_ast_node_text), AST_Node_Type::While, std::move(t_loc), std::move(t_children)) { }
|
||||
virtual ~While_AST_Node() {}
|
||||
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE {
|
||||
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE {
|
||||
chaiscript::eval::detail::Scope_Push_Pop spp(t_ss);
|
||||
|
||||
try {
|
||||
@ -883,12 +871,12 @@ namespace chaiscript
|
||||
Class_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_NodePtr> t_children) :
|
||||
AST_Node(std::move(t_ast_node_text), AST_Node_Type::Class, std::move(t_loc), std::move(t_children)) { }
|
||||
virtual ~Class_AST_Node() {}
|
||||
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE {
|
||||
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE {
|
||||
chaiscript::eval::detail::Scope_Push_Pop spp(t_ss);
|
||||
|
||||
/// \todo do this better
|
||||
// put class name in current scope so it can be looked up by the attrs and methods
|
||||
t_ss.add_object("_current_class_name", const_var(children[0]->text));
|
||||
t_ss->add_object("_current_class_name", const_var(children[0]->text));
|
||||
|
||||
children[1]->eval(t_ss);
|
||||
|
||||
@ -902,7 +890,7 @@ namespace chaiscript
|
||||
AST_Node(std::move(t_ast_node_text), AST_Node_Type::If, std::move(t_loc), std::move(t_children))
|
||||
{ assert(children.size() == 3); }
|
||||
virtual ~Ternary_Cond_AST_Node() {}
|
||||
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE {
|
||||
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE {
|
||||
if (get_bool_condition(children[0]->eval(t_ss))) {
|
||||
return children[1]->eval(t_ss);
|
||||
}
|
||||
@ -918,7 +906,7 @@ namespace chaiscript
|
||||
If_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_NodePtr> t_children) :
|
||||
AST_Node(std::move(t_ast_node_text), AST_Node_Type::If, std::move(t_loc), std::move(t_children)) { }
|
||||
virtual ~If_AST_Node() {}
|
||||
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE{
|
||||
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE{
|
||||
|
||||
if (get_bool_condition(children[0]->eval(t_ss))) {
|
||||
return children[1]->eval(t_ss);
|
||||
@ -951,7 +939,7 @@ namespace chaiscript
|
||||
{ assert(children.size() == 4); }
|
||||
virtual ~For_AST_Node() {}
|
||||
|
||||
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE{
|
||||
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE{
|
||||
chaiscript::eval::detail::Scope_Push_Pop spp(t_ss);
|
||||
|
||||
try {
|
||||
@ -983,7 +971,7 @@ namespace chaiscript
|
||||
Switch_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_NodePtr> t_children) :
|
||||
AST_Node(std::move(t_ast_node_text), AST_Node_Type::Switch, std::move(t_loc), std::move(t_children)) { }
|
||||
virtual ~Switch_AST_Node() {}
|
||||
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE {
|
||||
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE {
|
||||
bool breaking = false;
|
||||
size_t currentCase = 1;
|
||||
bool hasMatched = false;
|
||||
@ -997,7 +985,7 @@ namespace chaiscript
|
||||
if (this->children[currentCase]->identifier == AST_Node_Type::Case) {
|
||||
//This is a little odd, but because want to see both the switch and the case simultaneously, I do a downcast here.
|
||||
try {
|
||||
if (hasMatched || boxed_cast<bool>(t_ss.call_function("==", match_value, this->children[currentCase]->children[0]->eval(t_ss)))) {
|
||||
if (hasMatched || boxed_cast<bool>(t_ss->call_function("==", match_value, this->children[currentCase]->children[0]->eval(t_ss)))) {
|
||||
this->children[currentCase]->eval(t_ss);
|
||||
hasMatched = true;
|
||||
}
|
||||
@ -1027,7 +1015,7 @@ namespace chaiscript
|
||||
{ assert(children.size() == 2); /* how many children does it have? */ }
|
||||
|
||||
virtual ~Case_AST_Node() {}
|
||||
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE {
|
||||
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE {
|
||||
chaiscript::eval::detail::Scope_Push_Pop spp(t_ss);
|
||||
|
||||
children[1]->eval(t_ss);
|
||||
@ -1042,7 +1030,7 @@ namespace chaiscript
|
||||
AST_Node(std::move(t_ast_node_text), AST_Node_Type::Default, std::move(t_loc), std::move(t_children))
|
||||
{ assert(children.size() == 1); }
|
||||
virtual ~Default_AST_Node() {}
|
||||
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE {
|
||||
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE {
|
||||
chaiscript::eval::detail::Scope_Push_Pop spp(t_ss);
|
||||
|
||||
children[0]->eval(t_ss);
|
||||
@ -1057,12 +1045,17 @@ namespace chaiscript
|
||||
Inline_Array_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_NodePtr> t_children) :
|
||||
AST_Node(std::move(t_ast_node_text), AST_Node_Type::Inline_Array, std::move(t_loc), std::move(t_children)) { }
|
||||
virtual ~Inline_Array_AST_Node() {}
|
||||
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE {
|
||||
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE {
|
||||
try {
|
||||
std::vector<Boxed_Value> vec;
|
||||
if (!children.empty()) {
|
||||
for (const auto &child : children[0]->children) {
|
||||
vec.push_back(t_ss.call_function("clone", child->eval(t_ss)));
|
||||
auto obj = child->eval(t_ss);
|
||||
if (!obj.is_return_value()) {
|
||||
vec.push_back(t_ss->call_function("clone", obj));
|
||||
} else {
|
||||
vec.push_back(std::move(obj));
|
||||
}
|
||||
}
|
||||
}
|
||||
return const_var(std::move(vec));
|
||||
@ -1083,19 +1076,23 @@ namespace chaiscript
|
||||
Inline_Map_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_NodePtr> t_children) :
|
||||
AST_Node(std::move(t_ast_node_text), AST_Node_Type::Inline_Map, std::move(t_loc), std::move(t_children)) { }
|
||||
virtual ~Inline_Map_AST_Node() {}
|
||||
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE{
|
||||
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE{
|
||||
try {
|
||||
std::map<std::string, Boxed_Value> retval;
|
||||
|
||||
for (const auto &child : children[0]->children) {
|
||||
Boxed_Value bv = t_ss.call_function("clone", child->children[1]->eval(t_ss));
|
||||
retval[t_ss.boxed_cast<std::string>(child->children[0]->eval(t_ss))] = std::move(bv);
|
||||
auto obj = child->children[1]->eval(t_ss);
|
||||
if (!obj.is_return_value()) {
|
||||
obj = t_ss->call_function("clone", obj);
|
||||
}
|
||||
|
||||
retval[t_ss->boxed_cast<std::string>(child->children[0]->eval(t_ss))] = std::move(obj);
|
||||
}
|
||||
|
||||
return const_var(std::move(retval));
|
||||
}
|
||||
catch (const exception::dispatch_error &e) {
|
||||
throw exception::eval_error("Can not find appropriate copy constructor or 'clone' while inserting into Map.", e.parameters, e.functions, false, t_ss);
|
||||
throw exception::eval_error("Can not find appropriate copy constructor or 'clone' while inserting into Map.", e.parameters, e.functions, false, *t_ss);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1106,7 +1103,7 @@ namespace chaiscript
|
||||
Return_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_NodePtr> t_children) :
|
||||
AST_Node(std::move(t_ast_node_text), AST_Node_Type::Return, std::move(t_loc), std::move(t_children)) { }
|
||||
virtual ~Return_AST_Node() {}
|
||||
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE{
|
||||
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE{
|
||||
if (!this->children.empty()) {
|
||||
throw detail::Return_Value(children[0]->eval(t_ss));
|
||||
}
|
||||
@ -1122,12 +1119,23 @@ namespace chaiscript
|
||||
File_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_NodePtr> t_children) :
|
||||
AST_Node(std::move(t_ast_node_text), AST_Node_Type::File, std::move(t_loc), std::move(t_children)) { }
|
||||
virtual ~File_AST_Node() {}
|
||||
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE {
|
||||
const auto num_children = children.size();
|
||||
for (size_t i = 0; i < num_children-1; ++i) {
|
||||
children[i]->eval(t_ss);
|
||||
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE {
|
||||
try {
|
||||
const auto num_children = children.size();
|
||||
|
||||
if (num_children > 0) {
|
||||
for (size_t i = 0; i < num_children-1; ++i) {
|
||||
children[i]->eval(t_ss);
|
||||
}
|
||||
return children.back()->eval(t_ss);
|
||||
} else {
|
||||
return Boxed_Value();
|
||||
}
|
||||
} catch (const detail::Continue_Loop &) {
|
||||
throw exception::eval_error("Unexpected `continue` statement outside of a loop");
|
||||
} catch (const detail::Break_Loop &) {
|
||||
throw exception::eval_error("Unexpected `break` statement outside of a loop");
|
||||
}
|
||||
return children.back()->eval(t_ss);
|
||||
}
|
||||
};
|
||||
|
||||
@ -1137,10 +1145,10 @@ namespace chaiscript
|
||||
AST_Node(std::move(t_ast_node_text), AST_Node_Type::Reference, std::move(t_loc), std::move(t_children))
|
||||
{ assert(children.size() == 1); }
|
||||
|
||||
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE{
|
||||
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE{
|
||||
try {
|
||||
Boxed_Value bv;
|
||||
t_ss.add_object(this->children[0]->text, bv);
|
||||
t_ss->add_object(this->children[0]->text, bv);
|
||||
return bv;
|
||||
}
|
||||
catch (const exception::reserved_word_error &) {
|
||||
@ -1159,22 +1167,22 @@ namespace chaiscript
|
||||
{ }
|
||||
|
||||
virtual ~Prefix_AST_Node() {}
|
||||
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE{
|
||||
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE{
|
||||
Boxed_Value bv(children[1]->eval(t_ss));
|
||||
|
||||
try {
|
||||
// short circuit arithmetic operations
|
||||
if (m_oper != Operators::invalid && bv.get_type_info().is_arithmetic())
|
||||
if (m_oper != Operators::invalid && m_oper != Operators::bitwise_and && bv.get_type_info().is_arithmetic())
|
||||
{
|
||||
return Boxed_Number::do_oper(m_oper, std::move(bv));
|
||||
return Boxed_Number::do_oper(m_oper, bv);
|
||||
} else {
|
||||
chaiscript::eval::detail::Function_Push_Pop fpp(t_ss);
|
||||
chaiscript::eval::detail::Stack_Push_Pop spp(t_ss);
|
||||
fpp.save_params({bv});
|
||||
return t_ss.call_function(children[0]->text, std::move(bv));
|
||||
return t_ss->call_function(children[0]->text, std::move(bv));
|
||||
}
|
||||
} catch (const exception::dispatch_error &e) {
|
||||
throw exception::eval_error("Error with prefix operator evaluation: '" + children[0]->text + "'", e.parameters, e.functions, false, t_ss);
|
||||
throw exception::eval_error("Error with prefix operator evaluation: '" + children[0]->text + "'", e.parameters, e.functions, false, *t_ss);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1187,7 +1195,7 @@ namespace chaiscript
|
||||
Break_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_NodePtr> t_children) :
|
||||
AST_Node(std::move(t_ast_node_text), AST_Node_Type::Break, std::move(t_loc), std::move(t_children)) { }
|
||||
virtual ~Break_AST_Node() {}
|
||||
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &) const CHAISCRIPT_OVERRIDE{
|
||||
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &) const CHAISCRIPT_OVERRIDE{
|
||||
throw detail::Break_Loop();
|
||||
}
|
||||
};
|
||||
@ -1197,7 +1205,7 @@ namespace chaiscript
|
||||
Continue_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_NodePtr> t_children) :
|
||||
AST_Node(std::move(t_ast_node_text), AST_Node_Type::Continue, std::move(t_loc), std::move(t_children)) { }
|
||||
virtual ~Continue_AST_Node() {}
|
||||
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &) const CHAISCRIPT_OVERRIDE{
|
||||
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &) const CHAISCRIPT_OVERRIDE{
|
||||
throw detail::Continue_Loop();
|
||||
}
|
||||
};
|
||||
@ -1210,7 +1218,7 @@ namespace chaiscript
|
||||
{ }
|
||||
|
||||
virtual ~Noop_AST_Node() {}
|
||||
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &) const CHAISCRIPT_OVERRIDE{
|
||||
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &) const CHAISCRIPT_OVERRIDE{
|
||||
// It's a no-op, that evaluates to "true"
|
||||
return m_value;
|
||||
}
|
||||
@ -1238,14 +1246,14 @@ namespace chaiscript
|
||||
Inline_Range_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_NodePtr> t_children) :
|
||||
AST_Node(std::move(t_ast_node_text), AST_Node_Type::Inline_Range, std::move(t_loc), std::move(t_children)) { }
|
||||
virtual ~Inline_Range_AST_Node() {}
|
||||
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE{
|
||||
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE{
|
||||
try {
|
||||
return t_ss.call_function("generate_range",
|
||||
return t_ss->call_function("generate_range",
|
||||
children[0]->children[0]->children[0]->eval(t_ss),
|
||||
children[0]->children[0]->children[1]->eval(t_ss));
|
||||
}
|
||||
catch (const exception::dispatch_error &e) {
|
||||
throw exception::eval_error("Unable to generate range vector, while calling 'generate_range'", e.parameters, e.functions, false, t_ss);
|
||||
throw exception::eval_error("Unable to generate range vector, while calling 'generate_range'", e.parameters, e.functions, false, *t_ss);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1264,7 +1272,7 @@ namespace chaiscript
|
||||
AST_Node(std::move(t_ast_node_text), AST_Node_Type::Try, std::move(t_loc), std::move(t_children)) { }
|
||||
virtual ~Try_AST_Node() {}
|
||||
|
||||
Boxed_Value handle_exception(chaiscript::detail::Dispatch_Engine &t_ss, const Boxed_Value &t_except) const
|
||||
Boxed_Value handle_exception(const chaiscript::detail::Dispatch_State &t_ss, const Boxed_Value &t_except) const
|
||||
{
|
||||
Boxed_Value retval;
|
||||
|
||||
@ -1286,9 +1294,9 @@ namespace chaiscript
|
||||
|
||||
if (dispatch::Param_Types(
|
||||
std::vector<std::pair<std::string, Type_Info>>{Arg_List_AST_Node::get_arg_type(catch_block->children[0], t_ss)}
|
||||
).match(std::vector<Boxed_Value>{t_except}, t_ss.conversions()))
|
||||
).match(std::vector<Boxed_Value>{t_except}, t_ss->conversions()))
|
||||
{
|
||||
t_ss.add_object(name, t_except);
|
||||
t_ss->add_object(name, t_except);
|
||||
|
||||
if (catch_block->children.size() == 2) {
|
||||
//Variable capture, no guards
|
||||
@ -1325,7 +1333,7 @@ namespace chaiscript
|
||||
return retval;
|
||||
}
|
||||
|
||||
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE{
|
||||
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE{
|
||||
Boxed_Value retval;
|
||||
|
||||
chaiscript::eval::detail::Scope_Push_Pop spp(t_ss);
|
||||
@ -1340,9 +1348,14 @@ namespace chaiscript
|
||||
}
|
||||
throw;
|
||||
}
|
||||
catch (const std::runtime_error &e) {
|
||||
retval = handle_exception(t_ss, Boxed_Value(std::ref(e)));
|
||||
}
|
||||
catch (const std::out_of_range &e) {
|
||||
retval = handle_exception(t_ss, Boxed_Value(std::ref(e)));
|
||||
}
|
||||
catch (const std::exception &e) {
|
||||
retval = handle_exception(t_ss, Boxed_Value(std::ref(e)));
|
||||
|
||||
}
|
||||
catch (Boxed_Value &e) {
|
||||
retval = handle_exception(t_ss, e);
|
||||
@ -1383,11 +1396,11 @@ namespace chaiscript
|
||||
Method_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_NodePtr> t_children) :
|
||||
AST_Node(std::move(t_ast_node_text), AST_Node_Type::Method, std::move(t_loc), std::move(t_children)) { }
|
||||
virtual ~Method_AST_Node() {}
|
||||
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE{
|
||||
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE{
|
||||
|
||||
AST_NodePtr guardnode;
|
||||
|
||||
const auto d = t_ss.get_parent_locals();
|
||||
const auto d = t_ss->get_parent_locals();
|
||||
const auto itr = d.find("_current_class_name");
|
||||
const auto class_offset = (itr != d.end())?-1:0;
|
||||
const std::string & class_name = (itr != d.end())?std::string(boxed_cast<std::string>(itr->second)):this->children[0]->text;
|
||||
@ -1415,39 +1428,48 @@ namespace chaiscript
|
||||
|
||||
const size_t numparams = t_param_names.size();
|
||||
|
||||
std::shared_ptr<dispatch::Dynamic_Proxy_Function> guard;
|
||||
std::shared_ptr<dispatch::Proxy_Function_Base> guard;
|
||||
std::reference_wrapper<chaiscript::detail::Dispatch_Engine> engine(*t_ss);
|
||||
if (guardnode) {
|
||||
guard = std::make_shared<dispatch::Dynamic_Proxy_Function>
|
||||
(std::bind(chaiscript::eval::detail::eval_function,
|
||||
std::ref(t_ss), guardnode,
|
||||
t_param_names, std::placeholders::_1, std::map<std::string, Boxed_Value>()), static_cast<int>(numparams), guardnode);
|
||||
guard = dispatch::make_dynamic_proxy_function(
|
||||
[engine, t_param_names, guardnode](const std::vector<Boxed_Value> &t_params) {
|
||||
return chaiscript::eval::detail::eval_function(engine, guardnode, t_param_names, t_params, std::map<std::string, Boxed_Value>());
|
||||
},
|
||||
static_cast<int>(numparams), guardnode);
|
||||
}
|
||||
|
||||
try {
|
||||
const std::string & l_annotation = annotation?annotation->text:"";
|
||||
|
||||
const std::string & function_name = children[static_cast<size_t>(1 + class_offset)]->text;
|
||||
auto node = children.back();
|
||||
|
||||
if (function_name == class_name) {
|
||||
param_types.push_front(class_name, Type_Info());
|
||||
t_ss.add(std::make_shared<dispatch::detail::Dynamic_Object_Constructor>(class_name, std::make_shared<dispatch::Dynamic_Proxy_Function>(std::bind(chaiscript::eval::detail::eval_function,
|
||||
std::ref(t_ss), children.back(), t_param_names, std::placeholders::_1, std::map<std::string, Boxed_Value>()),
|
||||
static_cast<int>(numparams), children.back(), param_types, l_annotation, guard)),
|
||||
|
||||
t_ss->add(
|
||||
std::make_shared<dispatch::detail::Dynamic_Object_Constructor>(class_name,
|
||||
dispatch::make_dynamic_proxy_function(
|
||||
[engine, t_param_names, node](const std::vector<Boxed_Value> &t_params) {
|
||||
return chaiscript::eval::detail::eval_function(engine, node, t_param_names, t_params, std::map<std::string, Boxed_Value>());
|
||||
},
|
||||
static_cast<int>(numparams), node, param_types, l_annotation, guard
|
||||
)
|
||||
),
|
||||
function_name);
|
||||
|
||||
} else {
|
||||
|
||||
// if the type is unknown, then this generates a function that looks up the type
|
||||
// at runtime. Defining the type first before this is called is better
|
||||
auto type = t_ss.get_type(class_name, false);
|
||||
auto type = t_ss->get_type(class_name, false);
|
||||
param_types.push_front(class_name, type);
|
||||
|
||||
t_ss.add(
|
||||
std::make_shared<dispatch::detail::Dynamic_Object_Function>(class_name,
|
||||
std::make_shared<dispatch::Dynamic_Proxy_Function>(std::bind(chaiscript::eval::detail::eval_function,
|
||||
std::ref(t_ss), children.back(),
|
||||
t_param_names, std::placeholders::_1, std::map<std::string, Boxed_Value>()), static_cast<int>(numparams), children.back(),
|
||||
param_types, l_annotation, guard), type), function_name);
|
||||
t_ss->add(std::make_shared<dispatch::detail::Dynamic_Object_Function>(class_name,
|
||||
dispatch::make_dynamic_proxy_function(
|
||||
[engine, t_param_names, node](const std::vector<Boxed_Value> &t_params) {
|
||||
return chaiscript::eval::detail::eval_function(engine, node, t_param_names, t_params, std::map<std::string, Boxed_Value>());
|
||||
},
|
||||
static_cast<int>(numparams), node, param_types, l_annotation, guard), type),
|
||||
function_name);
|
||||
}
|
||||
}
|
||||
catch (const exception::reserved_word_error &e) {
|
||||
@ -1465,23 +1487,22 @@ namespace chaiscript
|
||||
Attr_Decl_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_NodePtr> t_children) :
|
||||
AST_Node(std::move(t_ast_node_text), AST_Node_Type::Attr_Decl, std::move(t_loc), std::move(t_children)) { }
|
||||
virtual ~Attr_Decl_AST_Node() {}
|
||||
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE
|
||||
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE
|
||||
{
|
||||
const auto &d = t_ss.get_parent_locals();
|
||||
const auto &d = t_ss->get_parent_locals();
|
||||
const auto itr = d.find("_current_class_name");
|
||||
const auto class_offset = (itr != d.end())?-1:0;
|
||||
std::string class_name = (itr != d.end())?std::string(boxed_cast<std::string>(itr->second)):this->children[0]->text;
|
||||
|
||||
try {
|
||||
t_ss.add(
|
||||
std::string attr_name = this->children[static_cast<size_t>(1 + class_offset)]->text;
|
||||
|
||||
t_ss->add(
|
||||
std::make_shared<dispatch::detail::Dynamic_Object_Function>(
|
||||
std::move(class_name),
|
||||
fun(std::function<Boxed_Value (dispatch::Dynamic_Object &)>(
|
||||
std::bind(static_cast<Boxed_Value &(dispatch::Dynamic_Object::*)(const std::string &)>(&dispatch::Dynamic_Object::get_attr),
|
||||
std::placeholders::_1,
|
||||
this->children[static_cast<size_t>(1 + class_offset)]->text
|
||||
))
|
||||
),
|
||||
fun([attr_name](dispatch::Dynamic_Object &t_obj) {
|
||||
return t_obj.get_attr(attr_name);
|
||||
}),
|
||||
true
|
||||
|
||||
), this->children[static_cast<size_t>(1 + class_offset)]->text);
|
||||
@ -1505,7 +1526,7 @@ namespace chaiscript
|
||||
{ assert(children.size() == 3); }
|
||||
|
||||
virtual ~Logical_And_AST_Node() {}
|
||||
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE{
|
||||
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE{
|
||||
return const_var(get_bool_condition(children[0]->eval(t_ss))
|
||||
&& get_bool_condition(children[2]->eval(t_ss)));
|
||||
}
|
||||
@ -1522,7 +1543,7 @@ namespace chaiscript
|
||||
AST_Node(std::move(t_ast_node_text), AST_Node_Type::Logical_Or, std::move(t_loc), std::move(t_children))
|
||||
{ assert(children.size() == 3); }
|
||||
virtual ~Logical_Or_AST_Node() {}
|
||||
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE{
|
||||
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE{
|
||||
return const_var(get_bool_condition(children[0]->eval(t_ss))
|
||||
|| get_bool_condition(children[2]->eval(t_ss)));
|
||||
}
|
||||
|
@ -7,8 +7,6 @@
|
||||
#ifndef CHAISCRIPT_PARSER_HPP_
|
||||
#define CHAISCRIPT_PARSER_HPP_
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <exception>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
@ -16,6 +14,8 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <cctype>
|
||||
#include <cstring>
|
||||
|
||||
|
||||
#include "../dispatchkit/boxed_value.hpp"
|
||||
#include "chaiscript_common.hpp"
|
||||
@ -67,6 +67,7 @@ namespace chaiscript
|
||||
m_multiline_comment_end("*/"),
|
||||
m_singleline_comment("//")
|
||||
{
|
||||
m_match_stack.reserve(2);
|
||||
setup_operators();
|
||||
}
|
||||
|
||||
@ -193,6 +194,7 @@ namespace chaiscript
|
||||
|
||||
/// Returns the front-most AST node
|
||||
AST_NodePtr ast() const {
|
||||
if (m_match_stack.empty()) throw exception::eval_error("Attempted to access AST of failed parse.");
|
||||
return m_match_stack.front();
|
||||
}
|
||||
|
||||
@ -215,28 +217,6 @@ namespace chaiscript
|
||||
|
||||
}
|
||||
|
||||
static void optimize_fun_lookups(AST_NodePtr &p)
|
||||
{
|
||||
for (auto &c : p->children)
|
||||
{
|
||||
|
||||
if (c->identifier == AST_Node_Type::Def
|
||||
|| c->identifier == AST_Node_Type::Method
|
||||
|| c->identifier == AST_Node_Type::Lambda) {
|
||||
std::vector<AST_NodePtr> children_to_add;
|
||||
auto counts = count_fun_calls(c, false);
|
||||
for (const auto &count : counts) {
|
||||
// std::cout << " Fun Call Count: " << count.first << " " << count.second << '\n';
|
||||
if (count.second > 1) {
|
||||
children_to_add.push_back(chaiscript::make_shared<AST_Node, eval::Fun_Lookup_AST_Node>(count.first));
|
||||
}
|
||||
}
|
||||
c->children.back()->children.insert(c->children.back()->children.begin(), children_to_add.begin(), children_to_add.end());
|
||||
}
|
||||
optimize_fun_lookups(c);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void optimize_blocks(AST_NodePtr &p)
|
||||
{
|
||||
@ -281,12 +261,11 @@ namespace chaiscript
|
||||
return count;
|
||||
}
|
||||
|
||||
AST_NodePtr optimized_ast(bool t_optimize_blocks = false, bool t_optimize_returns = true, bool t_optimize_fun_lookups = false) {
|
||||
AST_NodePtr p = m_match_stack.front();
|
||||
AST_NodePtr optimized_ast(bool t_optimize_blocks = false, bool t_optimize_returns = true) {
|
||||
AST_NodePtr p = ast();
|
||||
//Note, optimize_blocks is currently broken; it breaks stack management
|
||||
if (t_optimize_blocks) { optimize_blocks(p); }
|
||||
if (t_optimize_returns) { optimize_returns(p); }
|
||||
if (t_optimize_fun_lookups) { optimize_fun_lookups(p); }
|
||||
return p;
|
||||
}
|
||||
|
||||
@ -1230,37 +1209,32 @@ namespace chaiscript
|
||||
}
|
||||
|
||||
/// Reads an end-of-line group from input, without skipping initial whitespace
|
||||
bool Eol_() {
|
||||
bool Eol_(const bool t_eos = false) {
|
||||
bool retval = false;
|
||||
|
||||
if (has_more_input() && (Symbol_("\r\n") || Char_('\n'))) {
|
||||
retval = true;
|
||||
++m_line;
|
||||
m_col = 1;
|
||||
} else if (has_more_input() && Char_(';')) {
|
||||
} else if (has_more_input() && !t_eos && Char_(';')) {
|
||||
retval = true;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/// Reads (and potentially captures) an end-of-line group from input
|
||||
bool Eol(const bool t_capture = false) {
|
||||
/// Reads until the end of the current statement
|
||||
bool Eos() {
|
||||
SkipWS();
|
||||
|
||||
if (!t_capture) {
|
||||
return Eol_();
|
||||
} else {
|
||||
const auto start = m_input_pos;
|
||||
const auto prev_col = m_col;
|
||||
const auto prev_line = m_line;
|
||||
if (Eol_()) {
|
||||
m_match_stack.push_back(make_node<eval::Eol_AST_Node>(std::string(start, m_input_pos), prev_line, prev_col));
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return Eol_(true);
|
||||
}
|
||||
|
||||
/// Reads (and potentially captures) an end-of-line group from input
|
||||
bool Eol() {
|
||||
SkipWS();
|
||||
|
||||
return Eol_();
|
||||
}
|
||||
|
||||
/// Reads a comma-separated list of values from input. Id's only, no types allowed
|
||||
@ -1463,7 +1437,7 @@ namespace chaiscript
|
||||
}
|
||||
}
|
||||
|
||||
while (Eol()) {}
|
||||
while (Eos()) {}
|
||||
|
||||
if (Char(':')) {
|
||||
if (!Operator()) {
|
||||
|
@ -127,18 +127,6 @@ def even(x)
|
||||
}
|
||||
|
||||
|
||||
# Pushes the second value onto the container first value while making a clone of the value
|
||||
def push_back(container, x) : call_exists(push_back_ref, container, x)
|
||||
{
|
||||
container.push_back_ref(clone(x))
|
||||
}
|
||||
|
||||
# Pushes the second value onto the front of the container first value while making a clone of the value
|
||||
def push_front(container, x) : call_exists(push_front_ref, container, x)
|
||||
{
|
||||
container.push_front_ref(clone(x))
|
||||
}
|
||||
|
||||
# Inserts the third value at the position of the second value into the container of the first
|
||||
# while making a clone.
|
||||
def insert_at(container, pos, x)
|
||||
|
@ -718,14 +718,14 @@ Object drop_while(Range c, Function f);
|
||||
Object reduce(Range c, Function f);
|
||||
|
||||
|
||||
/// \brief Takes elements from Range c that match function f, return them.
|
||||
/// \brief Takes elements from Container c that match function f, return them.
|
||||
///
|
||||
/// Example:
|
||||
/// \code
|
||||
/// eval> filter([1, 2, 3, 4], odd)
|
||||
/// [1, 3]
|
||||
/// \endcode
|
||||
Object filter(Range c, Function f);
|
||||
Object filter(Container c, Function f);
|
||||
|
||||
|
||||
/// \brief Joins the elements of the Range c into a string, delimiting each with the delim string.
|
||||
|
@ -1,7 +1,11 @@
|
||||
Master Status: [](https://travis-ci.org/ChaiScript/ChaiScript) [](https://coveralls.io/r/ChaiScript/ChaiScript?branch=master)
|
||||
Master Status: [](https://travis-ci.org/ChaiScript/ChaiScript) [](https://ci.appveyor.com/project/lefticus/chaiscript) [](http://codecov.io/github/ChaiScript/ChaiScript?branch=master)
|
||||
|
||||
Develop Status: [](https://travis-ci.org/ChaiScript/ChaiScript) [](https://coveralls.io/r/ChaiScript/ChaiScript?branch=develop)
|
||||
Develop Status: [](https://travis-ci.org/ChaiScript/ChaiScript) [](https://ci.appveyor.com/project/lefticus/chaiscript/branch/develop) [](http://codecov.io/github/ChaiScript/ChaiScript?branch=develop)
|
||||
|
||||
<a href="https://scan.coverity.com/projects/5297">
|
||||
<img alt="Coverity Scan Build Status"
|
||||
src="https://img.shields.io/coverity/scan/5297.svg"/>
|
||||
</a>
|
||||
|
||||
ChaiScript
|
||||
|
||||
|
@ -1,6 +1,33 @@
|
||||
Notes:
|
||||
=======
|
||||
Current Version: 5.7.0
|
||||
Current Version: 5.7.1
|
||||
|
||||
### Changes since 5.7.0
|
||||
* Build time reduction
|
||||
* Build size reduction
|
||||
* Performance increases
|
||||
* Fixed ~20 crash-bugs found with fuzzy testing #194
|
||||
* Let unhandled exceptions propogate to user
|
||||
* Report eval_error when break statement is not in loop
|
||||
* Fix handling of 0 length scripts closes #193
|
||||
* Don't crash on arity mismatch - Specifically affects the case where no overloads exist for a given function
|
||||
* Fix error printing for `bind` calls
|
||||
* Handle unexpected continue statement
|
||||
* Check arity during bind
|
||||
* Don't allow arith conversion on variadic function
|
||||
* Correct `bind` parameter match count
|
||||
* Add in expected Boxed_Value exception cases
|
||||
* Check access to AST, don't allow `;` in func def
|
||||
* Don't attempt arithmetic unary & call
|
||||
* Don't crash on 0 param call to `bind`
|
||||
* Catch errors during member function dispatch
|
||||
* Properly handle type of const bool &
|
||||
* Automatic deduction of lambda type signatures
|
||||
* Work with non-polymorphic parent/child conversions
|
||||
* Move to codecov for coverage reporting
|
||||
* Add `.at` method for Map objects
|
||||
* Various corrections for support of move-only objects
|
||||
|
||||
|
||||
### Changes since 5.6.0
|
||||
|
||||
|
29
src/main.cpp
29
src/main.cpp
@ -297,6 +297,8 @@ int main(int argc, char *argv[])
|
||||
chai.add(chaiscript::fun(&get_eval_error), "get_eval_error");
|
||||
chai.add(chaiscript::fun(&now), "now");
|
||||
|
||||
bool eval_error_ok = false;
|
||||
bool boxed_exception_ok = false;
|
||||
|
||||
for (int i = 0; i < argc; ++i) {
|
||||
if ( i == 0 && argc > 1 ) {
|
||||
@ -324,9 +326,15 @@ int main(int argc, char *argv[])
|
||||
arg += line + '\n' ;
|
||||
}
|
||||
} else if ( arg == "-v" || arg == "--version" ) {
|
||||
arg = "version()" ;
|
||||
arg = "print(version())" ;
|
||||
} else if ( arg == "-h" || arg == "--help" ) {
|
||||
arg = "help(-1)";
|
||||
} else if ( arg == "-e" || arg == "--evalerrorok" ) {
|
||||
eval_error_ok = true;
|
||||
continue;
|
||||
} else if ( arg == "--exception" ) {
|
||||
boxed_exception_ok = true;
|
||||
continue;
|
||||
} else if ( arg == "-i" || arg == "--interactive" ) {
|
||||
mode = eInteractive ;
|
||||
} else if ( arg.find('-') == 0 ) {
|
||||
@ -352,12 +360,23 @@ int main(int argc, char *argv[])
|
||||
catch (const chaiscript::exception::eval_error &ee) {
|
||||
std::cout << ee.pretty_print();
|
||||
std::cout << '\n';
|
||||
return EXIT_FAILURE;
|
||||
|
||||
if (!eval_error_ok) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
catch (std::exception &e) {
|
||||
std::cout << e.what() << '\n';
|
||||
return EXIT_FAILURE;
|
||||
catch (const chaiscript::Boxed_Value &e) {
|
||||
std::cout << "Unhandled exception thrown of type " << e.get_type_info().name() << '\n';
|
||||
|
||||
if (!boxed_exception_ok) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
// catch (std::exception &e) {
|
||||
// std::cout << e.what() << '\n';
|
||||
// return EXIT_FAILURE;
|
||||
// }
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
|
@ -23,7 +23,11 @@
|
||||
|
||||
CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_stl_extra()
|
||||
{
|
||||
return chaiscript::bootstrap::standard_library::list_type<std::list<chaiscript::Boxed_Value> >("List");
|
||||
|
||||
auto module = chaiscript::bootstrap::standard_library::list_type<std::list<chaiscript::Boxed_Value> >("List");
|
||||
module->add(chaiscript::bootstrap::standard_library::vector_type<std::vector<uint16_t> >("u16vector"));
|
||||
module->add(chaiscript::vector_conversion<std::vector<uint16_t>>());
|
||||
return module;
|
||||
}
|
||||
|
||||
#ifdef __llvm__
|
||||
|
@ -34,6 +34,11 @@ class TestBaseType
|
||||
int mdarray[2][3][5];
|
||||
std::function<int (int)> func_member;
|
||||
|
||||
void set_string_val(std::string &t_str)
|
||||
{
|
||||
t_str = "42";
|
||||
}
|
||||
|
||||
private:
|
||||
TestBaseType &operator=(const TestBaseType &) = delete;
|
||||
};
|
||||
@ -52,6 +57,7 @@ class Type2
|
||||
return m_bt.val;
|
||||
}
|
||||
|
||||
|
||||
const char *get_str() const
|
||||
{
|
||||
return m_str.c_str();
|
||||
@ -171,6 +177,7 @@ CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_test_mo
|
||||
m->add(chaiscript::fun(&TestBaseType::val), "val");
|
||||
m->add(chaiscript::fun(&TestBaseType::const_val), "const_val");
|
||||
m->add(chaiscript::fun(&TestBaseType::base_only_func), "base_only_func");
|
||||
m->add(chaiscript::fun(&TestBaseType::set_string_val), "set_string_val");
|
||||
|
||||
#ifndef CHAISCRIPT_MSVC_12
|
||||
// we cannot support these in MSVC_12 because of a bug in the implementation of
|
||||
|
@ -37,8 +37,7 @@ TEST_CASE("C++11 Lambdas Can Be Registered")
|
||||
// in an std::function or provide the signature
|
||||
chaiscript::ChaiScript chai;
|
||||
|
||||
// provide the signature
|
||||
chai.add(chaiscript::fun<std::string ()>([] { return "hello"; } ), "f1");
|
||||
chai.add(chaiscript::fun([]()->std::string { return "hello"; } ), "f1");
|
||||
|
||||
// wrap
|
||||
chai.add(chaiscript::fun(std::function<std::string ()>([] { return "world"; } )), "f2");
|
||||
@ -723,3 +722,24 @@ TEST_CASE("Object lifetime test 2")
|
||||
CHECK(_script.eval<std::string>("to_string(test2.x)") == "10");
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
///// Non-polymorphic base class conversions
|
||||
class Non_Poly_Base {};
|
||||
class Non_Poly_Derived : public Non_Poly_Base {};
|
||||
int myfunction(Non_Poly_Base *)
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
||||
TEST_CASE("Test Derived->Base with non-polymorphic classes")
|
||||
{
|
||||
chaiscript::ChaiScript chai;
|
||||
chai.add(chaiscript::base_class<Non_Poly_Base, Non_Poly_Derived>());
|
||||
Non_Poly_Derived d;
|
||||
chai.add(chaiscript::var(&d), "d");
|
||||
chai.add(chaiscript::fun(&myfunction), "myfunction");
|
||||
CHECK(chai.eval<int>("myfunction(d)") == 2);
|
||||
}
|
||||
|
BIN
unittests/fuzzy_tests-2015-07-16.tar.bz2
Normal file
BIN
unittests/fuzzy_tests-2015-07-16.tar.bz2
Normal file
Binary file not shown.
@ -1,2 +1,19 @@
|
||||
auto x = ["bob":2, "fred":3]
|
||||
assert_equal(3, x["fred"])
|
||||
|
||||
|
||||
try {
|
||||
auto m = ["bob":2, "fred":3];
|
||||
m.at("tom");
|
||||
assert_true(false);
|
||||
} catch (out_of_range e) {
|
||||
print("out_of_range")
|
||||
assert_true(true);
|
||||
} catch (e) {
|
||||
print("other")
|
||||
dump_object(e);
|
||||
assert_true(false);
|
||||
}
|
||||
|
||||
|
||||
assert_equal(["bob":2, "fred":3].at("fred"), 3);
|
||||
|
8
unittests/non_const_param.chai
Normal file
8
unittests/non_const_param.chai
Normal file
@ -0,0 +1,8 @@
|
||||
load_module("test_module")
|
||||
|
||||
var t2 = TestBaseType();
|
||||
|
||||
var s = "5";
|
||||
t2.set_string_val(s);
|
||||
assert_equal(s, "42")
|
||||
|
@ -5,33 +5,58 @@
|
||||
#include <iostream>
|
||||
#include <cstdlib>
|
||||
|
||||
void test_type(const chaiscript::Type_Info &ti, bool t_is_const, bool t_is_pointer, bool t_is_reference, bool t_is_void,
|
||||
bool t_is_undef)
|
||||
#ifdef CHAISCRIPT_MSVC
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4190 4640 28251 4702 6330)
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wshadow"
|
||||
#pragma GCC diagnostic ignored "-Wold-style-cast"
|
||||
#endif
|
||||
|
||||
#ifdef __llvm__
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wreturn-type-c-linkage"
|
||||
#pragma clang diagnostic ignored "-Wold-style-cast"
|
||||
#pragma clang diagnostic ignored "-Wexit-time-destructors"
|
||||
#pragma clang diagnostic ignored "-Wfloat-equal"
|
||||
#pragma clang diagnostic ignored "-Wunreachable-code"
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
#define CATCH_CONFIG_MAIN
|
||||
|
||||
#include "catch.hpp"
|
||||
|
||||
|
||||
TEST_CASE("Type_Info objects generate expected results")
|
||||
{
|
||||
if (ti.is_const() == t_is_const
|
||||
&& ti.is_pointer() == t_is_pointer
|
||||
&& ti.is_reference() == t_is_reference
|
||||
&& ti.is_void() == t_is_void
|
||||
&& ti.is_undef() == t_is_undef)
|
||||
const auto test_type = [](const chaiscript::Type_Info &ti, bool t_is_const, bool t_is_pointer, bool t_is_reference, bool t_is_void,
|
||||
bool t_is_undef, bool t_is_arithmetic)
|
||||
{
|
||||
return;
|
||||
} else {
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
CHECK(ti.is_const() == t_is_const);
|
||||
CHECK(ti.is_pointer() == t_is_pointer);
|
||||
CHECK(ti.is_reference() == t_is_reference);
|
||||
CHECK(ti.is_void() == t_is_void);
|
||||
CHECK(ti.is_undef() == t_is_undef);
|
||||
CHECK(ti.is_arithmetic() == t_is_arithmetic);
|
||||
};
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
test_type(chaiscript::user_type<void>(), false, false, false, true, false);
|
||||
test_type(chaiscript::user_type<const int>(), true, false, false, false, false);
|
||||
test_type(chaiscript::user_type<const int &>(), true, false, true, false, false);
|
||||
test_type(chaiscript::user_type<int>(), false, false, false, false, false);
|
||||
test_type(chaiscript::user_type<int *>(), false, true, false, false, false);
|
||||
test_type(chaiscript::user_type<const int *>(), true, true, false, false, false);
|
||||
test_type(chaiscript::Type_Info(), false, false, false, false, true);
|
||||
SECTION("void") { test_type(chaiscript::user_type<void>(), false, false, false, true, false, false); }
|
||||
SECTION("const int") { test_type(chaiscript::user_type<const int>(), true, false, false, false, false, true); }
|
||||
SECTION("const int &") { test_type(chaiscript::user_type<const int &>(), true, false, true, false, false, true); }
|
||||
SECTION("int") { test_type(chaiscript::user_type<int>(), false, false, false, false, false, true); }
|
||||
SECTION("int *") { test_type(chaiscript::user_type<int *>(), false, true, false, false, false, false); }
|
||||
SECTION("const int *") { test_type(chaiscript::user_type<const int *>(), true, true, false, false, false, false); }
|
||||
SECTION("const bool &") { test_type(chaiscript::user_type<const bool &>(), true, false, true, false, false, false); }
|
||||
SECTION("default") { test_type(chaiscript::Type_Info(), false, false, false, false, true, false); }
|
||||
|
||||
std::cout << "Size of Type_Info " << sizeof(chaiscript::Type_Info) << '\n';
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -3,3 +3,11 @@ x.push_back(3)
|
||||
assert_equal(3, x.size())
|
||||
assert_equal(3, x.back())
|
||||
assert_equal(1, x.front())
|
||||
|
||||
|
||||
load_module("stl_extra")
|
||||
|
||||
auto uint16v = u16vector();
|
||||
uint16v.push_back(1u);
|
||||
assert_equal(1, uint16v.front());
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user