Compare commits
111 Commits
v5.7.1
...
Workaround
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5852412d2c | ||
|
|
452f71b51f | ||
|
|
a97cb1530d | ||
|
|
21048b9e65 | ||
|
|
d73e715997 | ||
|
|
353a077c6b | ||
|
|
373a3688c9 | ||
|
|
208107fd7e | ||
|
|
e19a8e31ea | ||
|
|
b55eff95cf | ||
|
|
b6287a194c | ||
|
|
888d897a3e | ||
|
|
e32714c456 | ||
|
|
e1c40f3e8f | ||
|
|
d7489358f3 | ||
|
|
316ba45e3c | ||
|
|
f0796b51c8 | ||
|
|
e638d450ed | ||
|
|
e60eabbeb2 | ||
|
|
c249bef27d | ||
|
|
4e69e5a3d2 | ||
|
|
49c89a3b88 | ||
|
|
7507223c8b | ||
|
|
681b7db727 | ||
|
|
4826bddb5b | ||
|
|
21c3853537 | ||
|
|
49436e5740 | ||
|
|
202204a82a | ||
|
|
34c6b17215 | ||
|
|
6fe7f5ce98 | ||
|
|
d9f86a96f0 | ||
|
|
40b1549b3b | ||
|
|
c9a5bf6f83 | ||
|
|
8496a86043 | ||
|
|
bc388e59da | ||
|
|
09748275db | ||
|
|
eec0299cbc | ||
|
|
19ecfdfec5 | ||
|
|
7ba7b81a5c | ||
|
|
882cbf2dfb | ||
|
|
38b98c55cc | ||
|
|
3a675bf379 | ||
|
|
985b62705f | ||
|
|
5aecb7f17b | ||
|
|
ad69bf7d38 | ||
|
|
84554ed0a5 | ||
|
|
36765df3c0 | ||
|
|
b11ebf9e8f | ||
|
|
84e2d449b9 | ||
|
|
3e62a99f82 | ||
|
|
64dd349e32 | ||
|
|
1add4c4b0f | ||
|
|
14b3870efb | ||
|
|
d2cf12f948 | ||
|
|
e221ceaa4c | ||
|
|
beedf13d01 | ||
|
|
9d18360333 | ||
|
|
18e5ee0ba2 | ||
|
|
41e9027d9a | ||
|
|
8d9dc2b0a3 | ||
|
|
6a4647af43 | ||
|
|
5a651e2b8a | ||
|
|
d9fa5605ac | ||
|
|
3a8cb581cc | ||
|
|
b434d26a5d | ||
|
|
ba30d4f483 | ||
|
|
b4ffcd594d | ||
|
|
ca35128503 | ||
|
|
681f18ee62 | ||
|
|
e62a38b39f | ||
|
|
85ac1052dd | ||
|
|
8024edeadf | ||
|
|
f9f1d5807a | ||
|
|
14227475b2 | ||
|
|
e1a80fb5ce | ||
|
|
aabe53c934 | ||
|
|
f3dbb7ed87 | ||
|
|
52e11bf001 | ||
|
|
f06e5cdcd6 | ||
|
|
15eb78bd8f | ||
|
|
9f362608b7 | ||
|
|
e21c8f87b4 | ||
|
|
0a143d1cd3 | ||
|
|
08935beaf3 | ||
|
|
c9625b09b0 | ||
|
|
800c7fb37b | ||
|
|
179eaefafe | ||
|
|
28f5a74e98 | ||
|
|
781d62d3a5 | ||
|
|
8ed2158709 | ||
|
|
8f98e16e5e | ||
|
|
3a595ef912 | ||
|
|
5aa0bfcea4 | ||
|
|
04e2256c92 | ||
|
|
38ba00e55c | ||
|
|
8931346230 | ||
|
|
8bdd2deb19 | ||
|
|
535055eff8 | ||
|
|
913d2fd20f | ||
|
|
0c4951d742 | ||
|
|
9d17b18f26 | ||
|
|
31b3195c17 | ||
|
|
0d4e4090a0 | ||
|
|
b946af42cc | ||
|
|
22339d10db | ||
|
|
b3d2350f33 | ||
|
|
3cae2aed1d | ||
|
|
c6f262c675 | ||
|
|
8239206ec5 | ||
|
|
a2ff672b34 | ||
|
|
9a0a12d230 |
@@ -12,7 +12,7 @@ compilers:
|
|||||||
build_tag: AddressSanitizer
|
build_tag: AddressSanitizer
|
||||||
version: "3.6"
|
version: "3.6"
|
||||||
skip_packaging: true
|
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
|
cmake_extra_flags: -DRUN_FUZZY_TESTS:BOOL=TRUE -DUSE_LIBCXX:BOOL=OFF -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DENABLE_ADDRESS_SANITIZER:BOOL=ON
|
||||||
- name: "clang"
|
- name: "clang"
|
||||||
build_tag: ThreadSanitizer
|
build_tag: ThreadSanitizer
|
||||||
version: "3.6"
|
version: "3.6"
|
||||||
|
|||||||
@@ -68,6 +68,13 @@ if(CMAKE_COMPILER_IS_GNUCC OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
|
|||||||
set(LINKER_FLAGS "${LINKER_FLAGS} -flto")
|
set(LINKER_FLAGS "${LINKER_FLAGS} -flto")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
option(GPROF_OUTPUT "Generate profile data" FALSE)
|
||||||
|
if (GPROF_OUTPUT)
|
||||||
|
add_definitions(-pg)
|
||||||
|
set(LINKER_FLAGS "${LINKER_FLAGS} -pg")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
|
||||||
option(PROFILE_GENERATE "Generate profile data" FALSE)
|
option(PROFILE_GENERATE "Generate profile data" FALSE)
|
||||||
if (PROFILE_GENERATE)
|
if (PROFILE_GENERATE)
|
||||||
add_definitions(-fprofile-generate)
|
add_definitions(-fprofile-generate)
|
||||||
@@ -95,7 +102,7 @@ set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/description.txt"
|
|||||||
|
|
||||||
set(CPACK_PACKAGE_VERSION_MAJOR 5)
|
set(CPACK_PACKAGE_VERSION_MAJOR 5)
|
||||||
set(CPACK_PACKAGE_VERSION_MINOR 7)
|
set(CPACK_PACKAGE_VERSION_MINOR 7)
|
||||||
set(CPACK_PACKAGE_VERSION_PATCH 1)
|
set(CPACK_PACKAGE_VERSION_PATCH 2)
|
||||||
|
|
||||||
set(CPACK_PACKAGE_EXECUTABLES "chai;ChaiScript Eval")
|
set(CPACK_PACKAGE_EXECUTABLES "chai;ChaiScript Eval")
|
||||||
set(CPACK_PACKAGE_VENDOR "ChaiScript.com")
|
set(CPACK_PACKAGE_VENDOR "ChaiScript.com")
|
||||||
@@ -174,7 +181,7 @@ else()
|
|||||||
add_definitions(-Wall -Wextra -Wshadow -Wnon-virtual-dtor -Wold-style-cast -Wcast-align -Wcast-qual -Wunused -Woverloaded-virtual -pedantic ${CPP11_FLAG})
|
add_definitions(-Wall -Wextra -Wshadow -Wnon-virtual-dtor -Wold-style-cast -Wcast-align -Wcast-qual -Wunused -Woverloaded-virtual -pedantic ${CPP11_FLAG})
|
||||||
|
|
||||||
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
|
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
|
||||||
add_definitions(-Weverything -Wno-c++98-compat -Wno-documentation -Wno-switch-enum -Wno-weak-vtables -Wno-sign-conversion -Wno-missing-prototypes -Wno-padded -Wno-missing-noreturn -Wno-exit-time-destructors)
|
add_definitions(-Weverything -Wno-c++98-compat-pedantic -Wno-c++98-compat -Wno-documentation -Wno-switch-enum -Wno-weak-vtables -Wno-sign-conversion -Wno-missing-prototypes -Wno-padded -Wno-missing-noreturn -Wno-exit-time-destructors)
|
||||||
else()
|
else()
|
||||||
add_definitions(-Wnoexcept)
|
add_definitions(-Wnoexcept)
|
||||||
endif()
|
endif()
|
||||||
@@ -253,10 +260,14 @@ add_dependencies(chai chaiscript_stdlib-${CHAI_VERSION})
|
|||||||
if(BUILD_SAMPLES)
|
if(BUILD_SAMPLES)
|
||||||
add_executable(example samples/example.cpp)
|
add_executable(example samples/example.cpp)
|
||||||
target_link_libraries(example ${LIBS})
|
target_link_libraries(example ${LIBS})
|
||||||
|
add_executable(test_num_exceptions samples/test_num_exceptions.cpp)
|
||||||
|
target_link_libraries(test_num_exceptions ${LIBS})
|
||||||
add_executable(memory_leak_test samples/memory_leak_test.cpp)
|
add_executable(memory_leak_test samples/memory_leak_test.cpp)
|
||||||
target_link_libraries(memory_leak_test ${LIBS})
|
target_link_libraries(memory_leak_test ${LIBS})
|
||||||
add_executable(inheritance samples/inheritance.cpp)
|
add_executable(inheritance samples/inheritance.cpp)
|
||||||
target_link_libraries(inheritance ${LIBS})
|
target_link_libraries(inheritance ${LIBS})
|
||||||
|
add_executable(factory samples/factory.cpp)
|
||||||
|
target_link_libraries(factory ${LIBS})
|
||||||
add_executable(fun_call_performance samples/fun_call_performance.cpp)
|
add_executable(fun_call_performance samples/fun_call_performance.cpp)
|
||||||
target_link_libraries(fun_call_performance ${LIBS})
|
target_link_libraries(fun_call_performance ${LIBS})
|
||||||
endif()
|
endif()
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ chai.add(chaiscript::constructor<MyType (const MyType &)>(), "MyType");
|
|||||||
It's not strictly necessary to add types, but it helps with many things. Cloning, better errors, etc.
|
It's not strictly necessary to add types, but it helps with many things. Cloning, better errors, etc.
|
||||||
|
|
||||||
```
|
```
|
||||||
chai.add(chaiscript::user_type<MyClass>, "MyClass");
|
chai.add(chaiscript::user_type<MyClass>(), "MyClass");
|
||||||
```
|
```
|
||||||
|
|
||||||
## Adding Type Conversions
|
## Adding Type Conversions
|
||||||
@@ -354,6 +354,19 @@ o.f = fun(y) { print(this.x + y); }
|
|||||||
o.f(10); // prints 13
|
o.f(10); // prints 13
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Option Explicit
|
||||||
|
|
||||||
|
If you want to disable dynamic parameter definitions, you can `set_explicit`.
|
||||||
|
|
||||||
|
```
|
||||||
|
class My_Class {
|
||||||
|
def My_Class() {
|
||||||
|
this.set_explicit(true);
|
||||||
|
this.x = 2; // this would fail with explicit set to true
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
## method_missing
|
## method_missing
|
||||||
|
|
||||||
A function of the signature `method_missing(object, name, param1, param2, param3)` will be called if an appropriate
|
A function of the signature `method_missing(object, name, param1, param2, param3)` will be called if an appropriate
|
||||||
|
|||||||
26
contrib/codeanalysis/profile_cpp_calls.chai
Normal file
26
contrib/codeanalysis/profile_cpp_calls.chai
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
|
||||||
|
var test_str = "bob was a string";
|
||||||
|
|
||||||
|
for( var i = 0; i < 200000; ++i)
|
||||||
|
{
|
||||||
|
test_str.size();
|
||||||
|
// test_str.find("a", i);
|
||||||
|
test_str.c_str();
|
||||||
|
test_str.erase_at(1);
|
||||||
|
test_str.erase_at(1);
|
||||||
|
test_str.erase_at(1);
|
||||||
|
test_str.erase_at(1);
|
||||||
|
test_str.erase_at(1);
|
||||||
|
test_str.erase_at(1);
|
||||||
|
|
||||||
|
size(test_str);
|
||||||
|
// test_str.find("a", i);
|
||||||
|
c_str(test_str);
|
||||||
|
erase_at(test_str, 1);
|
||||||
|
erase_at(test_str, 1);
|
||||||
|
erase_at(test_str, 1);
|
||||||
|
erase_at(test_str, 1);
|
||||||
|
erase_at(test_str, 1);
|
||||||
|
erase_at(test_str, 1);
|
||||||
|
test_str = "bob was a string";
|
||||||
|
}
|
||||||
@@ -29,8 +29,9 @@
|
|||||||
#define CHAISCRIPT_WINDOWS
|
#define CHAISCRIPT_WINDOWS
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if (defined(__GNUC__) && __GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8) || (defined(__llvm__) && !defined(CHAISCRIPT_LIBCPP))
|
#if ( ( (defined(__GNUC__) && __GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8) ) && !defined(WIN32)) || (defined(__llvm__) && !defined(CHAISCRIPT_LIBCPP))
|
||||||
/// Currently only g++>=4.8 supports this natively
|
/// Currently only g++>=4.8 supports this natively
|
||||||
|
/// MinGW pretends to, but causes a crash on exit when thread_local objects are destructed
|
||||||
/// \todo Make this support other compilers when possible
|
/// \todo Make this support other compilers when possible
|
||||||
#define CHAISCRIPT_HAS_THREAD_LOCAL
|
#define CHAISCRIPT_HAS_THREAD_LOCAL
|
||||||
#endif
|
#endif
|
||||||
@@ -39,7 +40,11 @@
|
|||||||
#define CHAISCRIPT_GCC_4_6
|
#define CHAISCRIPT_GCC_4_6
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if (defined(__GNUC__) && __GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7) || defined(CHAISCRIPT_MSVC) || defined(__llvm__)
|
#if defined(__llvm__)
|
||||||
|
#define CHAISCRIPT_CLANG
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (defined(__GNUC__) && __GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7) || defined(CHAISCRIPT_MSVC) || defined(CHAISCRIPT_CLANG)
|
||||||
#define CHAISCRIPT_OVERRIDE override
|
#define CHAISCRIPT_OVERRIDE override
|
||||||
#else
|
#else
|
||||||
#define CHAISCRIPT_OVERRIDE
|
#define CHAISCRIPT_OVERRIDE
|
||||||
@@ -52,7 +57,7 @@
|
|||||||
#define CHAISCRIPT_MODULE_EXPORT extern "C"
|
#define CHAISCRIPT_MODULE_EXPORT extern "C"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef CHAISCRIPT_MSVC
|
#ifdef CHAISCRIPT_MSVC_12
|
||||||
#define CHAISCRIPT_NOEXCEPT throw()
|
#define CHAISCRIPT_NOEXCEPT throw()
|
||||||
#define CHAISCRIPT_CONSTEXPR
|
#define CHAISCRIPT_CONSTEXPR
|
||||||
#else
|
#else
|
||||||
@@ -65,7 +70,7 @@
|
|||||||
namespace chaiscript {
|
namespace chaiscript {
|
||||||
static const int version_major = 5;
|
static const int version_major = 5;
|
||||||
static const int version_minor = 7;
|
static const int version_minor = 7;
|
||||||
static const int version_patch = 1;
|
static const int version_patch = 2;
|
||||||
|
|
||||||
template<typename B, typename D, typename ...Arg>
|
template<typename B, typename D, typename ...Arg>
|
||||||
inline std::shared_ptr<B> make_shared(Arg && ... arg)
|
inline std::shared_ptr<B> make_shared(Arg && ... arg)
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
#include "dispatchkit/bootstrap_stl.hpp"
|
#include "dispatchkit/bootstrap_stl.hpp"
|
||||||
#include "dispatchkit/boxed_value.hpp"
|
#include "dispatchkit/boxed_value.hpp"
|
||||||
#include "language/chaiscript_prelude.chai"
|
#include "language/chaiscript_prelude.chai"
|
||||||
|
#include "utility/json_wrap.hpp"
|
||||||
|
|
||||||
#ifndef CHAISCRIPT_NO_THREADS
|
#ifndef CHAISCRIPT_NO_THREADS
|
||||||
#include <future>
|
#include <future>
|
||||||
@@ -51,6 +52,8 @@ namespace chaiscript
|
|||||||
lib->add(chaiscript::fun([](const std::function<chaiscript::Boxed_Value ()> &t_func){ return std::async(std::launch::async, t_func);}), "async");
|
lib->add(chaiscript::fun([](const std::function<chaiscript::Boxed_Value ()> &t_func){ return std::async(std::launch::async, t_func);}), "async");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
lib->add(json_wrap::library());
|
||||||
|
|
||||||
lib->eval(ChaiScript_Prelude::chaiscript_prelude() /*, "standard prelude"*/ );
|
lib->eval(ChaiScript_Prelude::chaiscript_prelude() /*, "standard prelude"*/ );
|
||||||
|
|
||||||
return lib;
|
return lib;
|
||||||
|
|||||||
@@ -440,6 +440,8 @@ namespace chaiscript
|
|||||||
m->add(constructor<dispatch::Dynamic_Object ()>(), "Dynamic_Object");
|
m->add(constructor<dispatch::Dynamic_Object ()>(), "Dynamic_Object");
|
||||||
m->add(fun(&dispatch::Dynamic_Object::get_type_name), "get_type_name");
|
m->add(fun(&dispatch::Dynamic_Object::get_type_name), "get_type_name");
|
||||||
m->add(fun(&dispatch::Dynamic_Object::get_attrs), "get_attrs");
|
m->add(fun(&dispatch::Dynamic_Object::get_attrs), "get_attrs");
|
||||||
|
m->add(fun(&dispatch::Dynamic_Object::set_explicit), "set_explicit");
|
||||||
|
m->add(fun(&dispatch::Dynamic_Object::is_explicit), "is_explicit");
|
||||||
|
|
||||||
m->add(fun(static_cast<Boxed_Value & (dispatch::Dynamic_Object::*)(const std::string &)>(&dispatch::Dynamic_Object::get_attr)), "get_attr");
|
m->add(fun(static_cast<Boxed_Value & (dispatch::Dynamic_Object::*)(const std::string &)>(&dispatch::Dynamic_Object::get_attr)), "get_attr");
|
||||||
m->add(fun(static_cast<const Boxed_Value & (dispatch::Dynamic_Object::*)(const std::string &) const>(&dispatch::Dynamic_Object::get_attr)), "get_attr");
|
m->add(fun(static_cast<const Boxed_Value & (dispatch::Dynamic_Object::*)(const std::string &) const>(&dispatch::Dynamic_Object::get_attr)), "get_attr");
|
||||||
@@ -450,7 +452,13 @@ namespace chaiscript
|
|||||||
m->add(fun(static_cast<Boxed_Value & (dispatch::Dynamic_Object::*)(const std::string &)>(&dispatch::Dynamic_Object::get_attr)), "[]");
|
m->add(fun(static_cast<Boxed_Value & (dispatch::Dynamic_Object::*)(const std::string &)>(&dispatch::Dynamic_Object::get_attr)), "[]");
|
||||||
m->add(fun(static_cast<const Boxed_Value & (dispatch::Dynamic_Object::*)(const std::string &) const>(&dispatch::Dynamic_Object::get_attr)), "[]");
|
m->add(fun(static_cast<const Boxed_Value & (dispatch::Dynamic_Object::*)(const std::string &) const>(&dispatch::Dynamic_Object::get_attr)), "[]");
|
||||||
|
|
||||||
m->eval("def Dynamic_Object::clone() { auto &new_o = Dynamic_Object(this.get_type_name()); for_each(this.get_attrs(), bind(fun(new_o, x) { new_o.get_attr(x.first) = x.second; }, new_o, _) ); return new_o; }");
|
m->eval(R""(
|
||||||
|
def Dynamic_Object::clone() {
|
||||||
|
auto &new_o = Dynamic_Object(this.get_type_name());
|
||||||
|
for_each(this.get_attrs(), fun[new_o](x) { new_o.get_attr(x.first) = x.second; } );
|
||||||
|
new_o;
|
||||||
|
}
|
||||||
|
)"");
|
||||||
|
|
||||||
m->add(fun(&has_guard), "has_guard");
|
m->add(fun(&has_guard), "has_guard");
|
||||||
m->add(fun(&get_guard), "get_guard");
|
m->add(fun(&get_guard), "get_guard");
|
||||||
@@ -460,9 +468,12 @@ namespace chaiscript
|
|||||||
m->add(fun(&Boxed_Value::is_const), "is_var_const");
|
m->add(fun(&Boxed_Value::is_const), "is_var_const");
|
||||||
m->add(fun(&Boxed_Value::is_ref), "is_var_reference");
|
m->add(fun(&Boxed_Value::is_ref), "is_var_reference");
|
||||||
m->add(fun(&Boxed_Value::is_pointer), "is_var_pointer");
|
m->add(fun(&Boxed_Value::is_pointer), "is_var_pointer");
|
||||||
|
m->add(fun(&Boxed_Value::is_return_value), "is_var_return_value");
|
||||||
|
m->add(fun(&Boxed_Value::reset_return_value), "reset_var_return_value");
|
||||||
m->add(fun(&Boxed_Value::is_type), "is_type");
|
m->add(fun(&Boxed_Value::is_type), "is_type");
|
||||||
m->add(fun(&Boxed_Value::get_attr), "get_var_attr");
|
m->add(fun(&Boxed_Value::get_attr), "get_var_attr");
|
||||||
m->add(fun(&Boxed_Value::copy_attrs), "copy_var_attrs");
|
m->add(fun(&Boxed_Value::copy_attrs), "copy_var_attrs");
|
||||||
|
m->add(fun(&Boxed_Value::clone_attrs), "clone_var_attrs");
|
||||||
|
|
||||||
m->add(fun(&Boxed_Value::get_type_info), "get_type_info");
|
m->add(fun(&Boxed_Value::get_type_info), "get_type_info");
|
||||||
m->add(user_type<Type_Info>(), "Type_Info");
|
m->add(user_type<Type_Info>(), "Type_Info");
|
||||||
@@ -485,6 +496,7 @@ namespace chaiscript
|
|||||||
basic_constructors<bool>("bool", m);
|
basic_constructors<bool>("bool", m);
|
||||||
operators::assign<bool>(m);
|
operators::assign<bool>(m);
|
||||||
operators::equal<bool>(m);
|
operators::equal<bool>(m);
|
||||||
|
operators::not_equal<bool>(m);
|
||||||
|
|
||||||
m->add(fun([](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(&Bootstrap::bool_to_string), "to_string");
|
||||||
@@ -502,6 +514,8 @@ namespace chaiscript
|
|||||||
bootstrap_pod_type<long>("long", m);
|
bootstrap_pod_type<long>("long", m);
|
||||||
bootstrap_pod_type<unsigned int>("unsigned_int", m);
|
bootstrap_pod_type<unsigned int>("unsigned_int", m);
|
||||||
bootstrap_pod_type<unsigned long>("unsigned_long", m);
|
bootstrap_pod_type<unsigned long>("unsigned_long", m);
|
||||||
|
bootstrap_pod_type<long long>("long_long", m);
|
||||||
|
bootstrap_pod_type<unsigned long long>("unsigned_long_long", m);
|
||||||
bootstrap_pod_type<size_t>("size_t", m);
|
bootstrap_pod_type<size_t>("size_t", m);
|
||||||
bootstrap_pod_type<char>("char", m);
|
bootstrap_pod_type<char>("char", m);
|
||||||
bootstrap_pod_type<wchar_t>("wchar_t", m);
|
bootstrap_pod_type<wchar_t>("wchar_t", m);
|
||||||
@@ -556,13 +570,14 @@ namespace chaiscript
|
|||||||
"eval_error",
|
"eval_error",
|
||||||
{ },
|
{ },
|
||||||
{ {fun(&chaiscript::exception::eval_error::reason), "reason"},
|
{ {fun(&chaiscript::exception::eval_error::reason), "reason"},
|
||||||
{fun(std::function<std::vector<Boxed_Value> (const chaiscript::exception::eval_error &t_eval_error)>([](const chaiscript::exception::eval_error &t_eval_error) -> std::vector<Boxed_Value> {
|
{fun(&chaiscript::exception::eval_error::pretty_print), "pretty_print"},
|
||||||
std::vector<Boxed_Value> retval;
|
{fun(std::function<std::vector<Boxed_Value> (const chaiscript::exception::eval_error &t_eval_error)>([](const chaiscript::exception::eval_error &t_eval_error) -> std::vector<Boxed_Value> {
|
||||||
std::transform(t_eval_error.call_stack.begin(), t_eval_error.call_stack.end(),
|
std::vector<Boxed_Value> retval;
|
||||||
std::back_inserter(retval),
|
std::transform(t_eval_error.call_stack.begin(), t_eval_error.call_stack.end(),
|
||||||
&chaiscript::var<std::shared_ptr<const chaiscript::AST_Node>>);
|
std::back_inserter(retval),
|
||||||
return retval;
|
&chaiscript::var<const std::shared_ptr<const chaiscript::AST_Node> &>);
|
||||||
})), "call_stack"} }
|
return retval;
|
||||||
|
})), "call_stack"} }
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
@@ -588,7 +603,7 @@ namespace chaiscript
|
|||||||
std::vector<Boxed_Value> retval;
|
std::vector<Boxed_Value> retval;
|
||||||
std::transform(t_node.children.begin(), t_node.children.end(),
|
std::transform(t_node.children.begin(), t_node.children.end(),
|
||||||
std::back_inserter(retval),
|
std::back_inserter(retval),
|
||||||
&chaiscript::var<std::shared_ptr<chaiscript::AST_Node>>);
|
&chaiscript::var<const std::shared_ptr<chaiscript::AST_Node> &>);
|
||||||
return retval;
|
return retval;
|
||||||
})), "children"},
|
})), "children"},
|
||||||
{fun(&AST_Node::replace_child), "replace_child"}
|
{fun(&AST_Node::replace_child), "replace_child"}
|
||||||
|
|||||||
@@ -334,7 +334,12 @@ namespace chaiscript
|
|||||||
"# Pushes the second value onto the container while making a clone of the value\n"
|
"# Pushes the second value onto the container while making a clone of the value\n"
|
||||||
"def push_back(" + type + " container, x)\n"
|
"def push_back(" + type + " container, x)\n"
|
||||||
"{ \n"
|
"{ \n"
|
||||||
" container.push_back_ref(clone(x)) \n"
|
" if (x.is_var_return_value()) {\n"
|
||||||
|
" x.reset_var_return_value() \n"
|
||||||
|
" container.push_back_ref(x) \n"
|
||||||
|
" } else { \n"
|
||||||
|
" container.push_back_ref(clone(x)); \n"
|
||||||
|
" }\n"
|
||||||
"} \n"
|
"} \n"
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -370,7 +375,12 @@ namespace chaiscript
|
|||||||
"# Pushes the second value onto the front of container while making a clone of the value\n"
|
"# Pushes the second value onto the front of container while making a clone of the value\n"
|
||||||
"def push_front(" + type + " container, x)\n"
|
"def push_front(" + type + " container, x)\n"
|
||||||
"{ \n"
|
"{ \n"
|
||||||
" container.push_front_ref(clone(x)) \n"
|
" if (x.is_var_return_value()) {\n"
|
||||||
|
" x.reset_var_return_value() \n"
|
||||||
|
" container.push_front_ref(x) \n"
|
||||||
|
" } else { \n"
|
||||||
|
" container.push_front_ref(clone(x)); \n"
|
||||||
|
" }\n"
|
||||||
"} \n"
|
"} \n"
|
||||||
);
|
);
|
||||||
return "push_front_ref";
|
return "push_front_ref";
|
||||||
@@ -460,6 +470,30 @@ namespace chaiscript
|
|||||||
m->add(fun(static_cast<elem_access>(&MapType::at)), "at");
|
m->add(fun(static_cast<elem_access>(&MapType::at)), "at");
|
||||||
m->add(fun(static_cast<const_elem_access>(&MapType::at)), "at");
|
m->add(fun(static_cast<const_elem_access>(&MapType::at)), "at");
|
||||||
|
|
||||||
|
if (typeid(MapType) == typeid(std::map<std::string, Boxed_Value>))
|
||||||
|
{
|
||||||
|
m->eval(R"(
|
||||||
|
def Map::`==`(Map rhs) {
|
||||||
|
if ( rhs.size() != this.size() ) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
auto r1 = range(this);
|
||||||
|
auto r2 = range(rhs);
|
||||||
|
while (!r1.empty())
|
||||||
|
{
|
||||||
|
if (!eq(r1.front().first, r2.front().first) || !eq(r1.front().second, r2.front().second))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
r1.pop_front();
|
||||||
|
r2.pop_front();
|
||||||
|
}
|
||||||
|
true;
|
||||||
|
}
|
||||||
|
} )"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
container_type<MapType>(type, m);
|
container_type<MapType>(type, m);
|
||||||
default_constructible_type<MapType>(type, m);
|
default_constructible_type<MapType>(type, m);
|
||||||
assignable_type<MapType>(type, m);
|
assignable_type<MapType>(type, m);
|
||||||
@@ -515,7 +549,7 @@ namespace chaiscript
|
|||||||
if (typeid(VectorType) == typeid(std::vector<Boxed_Value>))
|
if (typeid(VectorType) == typeid(std::vector<Boxed_Value>))
|
||||||
{
|
{
|
||||||
m->eval(R"(
|
m->eval(R"(
|
||||||
def Vector::`==`(rhs) : type_match(rhs, this) {
|
def Vector::`==`(Vector rhs) {
|
||||||
if ( rhs.size() != this.size() ) {
|
if ( rhs.size() != this.size() ) {
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -33,14 +33,14 @@ namespace chaiscript
|
|||||||
template<typename Result>
|
template<typename Result>
|
||||||
struct Cast_Helper_Inner
|
struct Cast_Helper_Inner
|
||||||
{
|
{
|
||||||
typedef std::reference_wrapper<typename std::add_const<Result>::type > Result_Type;
|
typedef typename std::add_const<Result>::type Result_Type;
|
||||||
|
|
||||||
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *)
|
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *)
|
||||||
{
|
{
|
||||||
if (ob.get_type_info().bare_equal_type_info(typeid(Result)))
|
if (ob.get_type_info().bare_equal_type_info(typeid(Result)))
|
||||||
{
|
{
|
||||||
auto p = throw_if_null(ob.get_const_ptr());
|
auto p = throw_if_null(ob.get_const_ptr());
|
||||||
return std::cref(*static_cast<const Result *>(p));
|
return *static_cast<const Result *>(p);
|
||||||
} else {
|
} else {
|
||||||
throw chaiscript::detail::exception::bad_any_cast();
|
throw chaiscript::detail::exception::bad_any_cast();
|
||||||
}
|
}
|
||||||
@@ -52,12 +52,6 @@ namespace chaiscript
|
|||||||
{
|
{
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Cast_Helper_Inner for casting to a const & type
|
|
||||||
template<typename Result>
|
|
||||||
struct Cast_Helper_Inner<const Result &> : Cast_Helper_Inner<Result>
|
|
||||||
{
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/// Cast_Helper_Inner for casting to a const * type
|
/// Cast_Helper_Inner for casting to a const * type
|
||||||
template<typename Result>
|
template<typename Result>
|
||||||
@@ -68,7 +62,7 @@ namespace chaiscript
|
|||||||
{
|
{
|
||||||
if (ob.get_type_info().bare_equal_type_info(typeid(Result)))
|
if (ob.get_type_info().bare_equal_type_info(typeid(Result)))
|
||||||
{
|
{
|
||||||
return static_cast<const Result *>(throw_if_null(ob.get_const_ptr()));
|
return static_cast<const Result *>(ob.get_const_ptr());
|
||||||
} else {
|
} else {
|
||||||
throw chaiscript::detail::exception::bad_any_cast();
|
throw chaiscript::detail::exception::bad_any_cast();
|
||||||
}
|
}
|
||||||
@@ -84,7 +78,36 @@ namespace chaiscript
|
|||||||
{
|
{
|
||||||
if (!ob.get_type_info().is_const() && ob.get_type_info() == typeid(Result))
|
if (!ob.get_type_info().is_const() && ob.get_type_info() == typeid(Result))
|
||||||
{
|
{
|
||||||
return static_cast<Result *>(throw_if_null(ob.get_ptr()));
|
return static_cast<Result *>(ob.get_ptr());
|
||||||
|
} else {
|
||||||
|
throw chaiscript::detail::exception::bad_any_cast();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename Result>
|
||||||
|
struct Cast_Helper_Inner<Result * const &> : public Cast_Helper_Inner<Result *>
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename Result>
|
||||||
|
struct Cast_Helper_Inner<const Result * const &> : public Cast_Helper_Inner<const Result *>
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/// Cast_Helper_Inner for casting to a & type
|
||||||
|
template<typename Result>
|
||||||
|
struct Cast_Helper_Inner<const Result &>
|
||||||
|
{
|
||||||
|
typedef const Result& Result_Type;
|
||||||
|
|
||||||
|
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *)
|
||||||
|
{
|
||||||
|
if (ob.get_type_info().bare_equal_type_info(typeid(Result)))
|
||||||
|
{
|
||||||
|
auto p = throw_if_null(ob.get_const_ptr());
|
||||||
|
return *static_cast<const Result *>(p);
|
||||||
} else {
|
} else {
|
||||||
throw chaiscript::detail::exception::bad_any_cast();
|
throw chaiscript::detail::exception::bad_any_cast();
|
||||||
}
|
}
|
||||||
@@ -166,7 +189,7 @@ namespace chaiscript
|
|||||||
template<>
|
template<>
|
||||||
struct Cast_Helper_Inner<Boxed_Value>
|
struct Cast_Helper_Inner<Boxed_Value>
|
||||||
{
|
{
|
||||||
typedef const Boxed_Value & Result_Type;
|
typedef Boxed_Value Result_Type;
|
||||||
|
|
||||||
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *)
|
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *)
|
||||||
{
|
{
|
||||||
@@ -178,11 +201,11 @@ namespace chaiscript
|
|||||||
template<>
|
template<>
|
||||||
struct Cast_Helper_Inner<Boxed_Value &>
|
struct Cast_Helper_Inner<Boxed_Value &>
|
||||||
{
|
{
|
||||||
typedef Boxed_Value& Result_Type;
|
typedef std::reference_wrapper<Boxed_Value> Result_Type;
|
||||||
|
|
||||||
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *)
|
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *)
|
||||||
{
|
{
|
||||||
return const_cast<Boxed_Value &>(ob);
|
return std::ref(const_cast<Boxed_Value &>(ob));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -100,6 +100,7 @@ namespace chaiscript
|
|||||||
:(Common_Types::t_uint64);
|
:(Common_Types::t_uint64);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static Common_Types get_common_type(const Boxed_Value &t_bv)
|
static Common_Types get_common_type(const Boxed_Value &t_bv)
|
||||||
{
|
{
|
||||||
const Type_Info &inp_ = t_bv.get_type_info();
|
const Type_Info &inp_ = t_bv.get_type_info();
|
||||||
@@ -120,8 +121,12 @@ namespace chaiscript
|
|||||||
return get_common_type(sizeof(unsigned int), false);
|
return get_common_type(sizeof(unsigned int), false);
|
||||||
} else if (inp_ == typeid(long)) {
|
} else if (inp_ == typeid(long)) {
|
||||||
return get_common_type(sizeof(long), true);
|
return get_common_type(sizeof(long), true);
|
||||||
|
} else if (inp_ == typeid(long long)) {
|
||||||
|
return get_common_type(sizeof(long long), true);
|
||||||
} else if (inp_ == typeid(unsigned long)) {
|
} else if (inp_ == typeid(unsigned long)) {
|
||||||
return get_common_type(sizeof(unsigned long), false);
|
return get_common_type(sizeof(unsigned long), false);
|
||||||
|
} else if (inp_ == typeid(unsigned long long)) {
|
||||||
|
return get_common_type(sizeof(unsigned long long), false);
|
||||||
} else if (inp_ == typeid(std::int8_t)) {
|
} else if (inp_ == typeid(std::int8_t)) {
|
||||||
return Common_Types::t_int8;
|
return Common_Types::t_int8;
|
||||||
} else if (inp_ == typeid(std::int16_t)) {
|
} else if (inp_ == typeid(std::int16_t)) {
|
||||||
@@ -513,6 +518,21 @@ namespace chaiscript
|
|||||||
validate_boxed_number(bv);
|
validate_boxed_number(bv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool is_floating_point(const Boxed_Value &t_bv)
|
||||||
|
{
|
||||||
|
const Type_Info &inp_ = t_bv.get_type_info();
|
||||||
|
|
||||||
|
if (inp_ == typeid(double)) {
|
||||||
|
return true;
|
||||||
|
} else if (inp_ == typeid(long double)) {
|
||||||
|
return true;
|
||||||
|
} else if (inp_ == typeid(float)) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Boxed_Number get_as(const Type_Info &inp_) const
|
Boxed_Number get_as(const Type_Info &inp_) const
|
||||||
{
|
{
|
||||||
if (inp_.bare_equal_type_info(typeid(int))) {
|
if (inp_.bare_equal_type_info(typeid(int))) {
|
||||||
@@ -537,8 +557,12 @@ namespace chaiscript
|
|||||||
return Boxed_Number(get_as<unsigned int>());
|
return Boxed_Number(get_as<unsigned int>());
|
||||||
} else if (inp_.bare_equal_type_info(typeid(long))) {
|
} else if (inp_.bare_equal_type_info(typeid(long))) {
|
||||||
return Boxed_Number(get_as<long>());
|
return Boxed_Number(get_as<long>());
|
||||||
|
} else if (inp_.bare_equal_type_info(typeid(long long))) {
|
||||||
|
return Boxed_Number(get_as<long long>());
|
||||||
} else if (inp_.bare_equal_type_info(typeid(unsigned long))) {
|
} else if (inp_.bare_equal_type_info(typeid(unsigned long))) {
|
||||||
return Boxed_Number(get_as<unsigned long>());
|
return Boxed_Number(get_as<unsigned long>());
|
||||||
|
} else if (inp_.bare_equal_type_info(typeid(unsigned long long))) {
|
||||||
|
return Boxed_Number(get_as<unsigned long long>());
|
||||||
} else if (inp_.bare_equal_type_info(typeid(int8_t))) {
|
} else if (inp_.bare_equal_type_info(typeid(int8_t))) {
|
||||||
return Boxed_Number(get_as<int8_t>());
|
return Boxed_Number(get_as<int8_t>());
|
||||||
} else if (inp_.bare_equal_type_info(typeid(int16_t))) {
|
} else if (inp_.bare_equal_type_info(typeid(int16_t))) {
|
||||||
|
|||||||
@@ -297,6 +297,13 @@ namespace chaiscript
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Boxed_Value &clone_attrs(const Boxed_Value &t_obj)
|
||||||
|
{
|
||||||
|
copy_attrs(t_obj);
|
||||||
|
reset_return_value();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/// \returns true if the two Boxed_Values share the same internal type
|
/// \returns true if the two Boxed_Values share the same internal type
|
||||||
static bool type_match(const Boxed_Value &l, const Boxed_Value &r) CHAISCRIPT_NOEXCEPT
|
static bool type_match(const Boxed_Value &l, const Boxed_Value &r) CHAISCRIPT_NOEXCEPT
|
||||||
@@ -330,9 +337,9 @@ namespace chaiscript
|
|||||||
///
|
///
|
||||||
/// @sa @ref adding_objects
|
/// @sa @ref adding_objects
|
||||||
template<typename T>
|
template<typename T>
|
||||||
Boxed_Value var(T t)
|
Boxed_Value var(T &&t)
|
||||||
{
|
{
|
||||||
return Boxed_Value(t);
|
return Boxed_Value(std::forward<T>(t));
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|||||||
@@ -61,6 +61,17 @@ namespace chaiscript {
|
|||||||
Ret (Class::*m_func)(Param...);
|
Ret (Class::*m_func)(Param...);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct Arity
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename Ret, typename ... Params>
|
||||||
|
struct Arity<Ret (Params...)>
|
||||||
|
{
|
||||||
|
static const size_t arity = sizeof...(Params);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct Function_Signature
|
struct Function_Signature
|
||||||
|
|||||||
@@ -417,9 +417,9 @@ namespace chaiscript
|
|||||||
|
|
||||||
struct State
|
struct State
|
||||||
{
|
{
|
||||||
std::map<std::string, std::vector<Proxy_Function> > m_functions;
|
std::vector<std::pair<std::string, std::shared_ptr<std::vector<Proxy_Function>>>> m_functions;
|
||||||
std::map<std::string, Proxy_Function> m_function_objects;
|
std::vector<std::pair<std::string, Proxy_Function>> m_function_objects;
|
||||||
std::map<std::string, Boxed_Value> m_boxed_functions;
|
std::vector<std::pair<std::string, Boxed_Value>> m_boxed_functions;
|
||||||
std::map<std::string, Boxed_Value> m_global_objects;
|
std::map<std::string, Boxed_Value> m_global_objects;
|
||||||
Type_Name_Map m_types;
|
Type_Name_Map m_types;
|
||||||
std::set<std::string> m_reserved_words;
|
std::set<std::string> m_reserved_words;
|
||||||
@@ -482,24 +482,31 @@ namespace chaiscript
|
|||||||
add_object(name, std::move(obj));
|
add_object(name, std::move(obj));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Adds a named object to the current scope
|
||||||
|
/// \warning This version does not check the validity of the name
|
||||||
|
/// it is meant for internal use only
|
||||||
|
void add_object(const std::string &t_name, Boxed_Value obj, Stack_Holder &t_holder)
|
||||||
|
{
|
||||||
|
auto &stack_elem = get_stack_data(t_holder).back();
|
||||||
|
|
||||||
|
if (std::any_of(stack_elem.begin(), stack_elem.end(),
|
||||||
|
[&](const std::pair<std::string, Boxed_Value> &o) {
|
||||||
|
return o.first == t_name;
|
||||||
|
}))
|
||||||
|
{
|
||||||
|
throw chaiscript::exception::name_conflict_error(t_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
get_stack_data(t_holder).back().emplace_back(t_name, std::move(obj));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Adds a named object to the current scope
|
/// Adds a named object to the current scope
|
||||||
/// \warning This version does not check the validity of the name
|
/// \warning This version does not check the validity of the name
|
||||||
/// it is meant for internal use only
|
/// it is meant for internal use only
|
||||||
void add_object(const std::string &name, Boxed_Value obj)
|
void add_object(const std::string &name, Boxed_Value obj)
|
||||||
{
|
{
|
||||||
auto &stack_elem = get_stack_data().back();
|
add_object(name, std::move(obj), get_stack_holder());
|
||||||
|
|
||||||
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
|
/// Adds a new global shared object, between all the threads
|
||||||
@@ -511,7 +518,7 @@ namespace chaiscript
|
|||||||
throw chaiscript::exception::global_non_const();
|
throw chaiscript::exception::global_non_const();
|
||||||
}
|
}
|
||||||
|
|
||||||
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l(m_global_object_mutex);
|
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
|
||||||
|
|
||||||
if (m_state.m_global_objects.find(name) != m_state.m_global_objects.end())
|
if (m_state.m_global_objects.find(name) != m_state.m_global_objects.end())
|
||||||
{
|
{
|
||||||
@@ -526,7 +533,7 @@ namespace chaiscript
|
|||||||
{
|
{
|
||||||
validate_object_name(name);
|
validate_object_name(name);
|
||||||
|
|
||||||
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l(m_global_object_mutex);
|
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
|
||||||
|
|
||||||
const auto itr = m_state.m_global_objects.find(name);
|
const auto itr = m_state.m_global_objects.find(name);
|
||||||
if (itr == m_state.m_global_objects.end())
|
if (itr == m_state.m_global_objects.end())
|
||||||
@@ -544,7 +551,7 @@ namespace chaiscript
|
|||||||
{
|
{
|
||||||
validate_object_name(name);
|
validate_object_name(name);
|
||||||
|
|
||||||
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l(m_global_object_mutex);
|
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
|
||||||
|
|
||||||
if (m_state.m_global_objects.find(name) != m_state.m_global_objects.end())
|
if (m_state.m_global_objects.find(name) != m_state.m_global_objects.end())
|
||||||
{
|
{
|
||||||
@@ -641,19 +648,21 @@ namespace chaiscript
|
|||||||
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;
|
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?
|
// Is the value we are looking for a global or function?
|
||||||
{
|
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
|
||||||
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_global_object_mutex);
|
|
||||||
|
|
||||||
const auto itr = m_state.m_global_objects.find(name);
|
const auto itr = m_state.m_global_objects.find(name);
|
||||||
if (itr != m_state.m_global_objects.end())
|
if (itr != m_state.m_global_objects.end())
|
||||||
{
|
{
|
||||||
return itr->second;
|
return itr->second;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If all that failed, then check to see if it's a function
|
// no? is it a function object?
|
||||||
return get_function_object(name);
|
auto obj = get_function_object_int(name, loc);
|
||||||
|
if (obj.first != loc) t_loc.store(uint_fast32_t(obj.first), std::memory_order_relaxed);
|
||||||
|
return obj.second;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Registers a new named type
|
/// Registers a new named type
|
||||||
@@ -711,20 +720,29 @@ namespace chaiscript
|
|||||||
return std::vector<std::pair<std::string, Type_Info> >(m_state.m_types.begin(), m_state.m_types.end());
|
return std::vector<std::pair<std::string, Type_Info> >(m_state.m_types.begin(), m_state.m_types.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<std::vector<Proxy_Function>> get_method_missing_functions() const
|
||||||
|
{
|
||||||
|
uint_fast32_t method_missing_loc = m_method_missing_loc.load(std::memory_order_relaxed);
|
||||||
|
auto method_missing_funs = get_function("method_missing", method_missing_loc);
|
||||||
|
if (method_missing_funs.first != method_missing_loc) m_method_missing_loc.store(uint_fast32_t(method_missing_funs.first), std::memory_order_relaxed);
|
||||||
|
return std::move(method_missing_funs.second);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Return a function by name
|
/// Return a function by name
|
||||||
std::vector< Proxy_Function > get_function(const std::string &t_name) const
|
std::pair<size_t, std::shared_ptr<std::vector< Proxy_Function>>> get_function(const std::string &t_name, const size_t t_hint) const
|
||||||
{
|
{
|
||||||
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
|
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
|
||||||
|
|
||||||
const auto &funs = get_functions_int();
|
const auto &funs = get_functions_int();
|
||||||
|
|
||||||
auto itr = funs.find(t_name);
|
auto itr = find_keyed_value(funs, t_name, t_hint);
|
||||||
|
|
||||||
if (itr != funs.end())
|
if (itr != funs.end())
|
||||||
{
|
{
|
||||||
return itr->second;
|
return std::make_pair(std::distance(funs.begin(), itr), itr->second);
|
||||||
} else {
|
} else {
|
||||||
return std::vector<Proxy_Function>();
|
return std::make_pair(size_t(0), std::make_shared<std::vector<Proxy_Function>>());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -732,28 +750,36 @@ namespace chaiscript
|
|||||||
/// \throws std::range_error if it does not
|
/// \throws std::range_error if it does not
|
||||||
Boxed_Value get_function_object(const std::string &t_name) const
|
Boxed_Value get_function_object(const std::string &t_name) const
|
||||||
{
|
{
|
||||||
// std::cout << "Getting function object: " << t_name << '\n';
|
|
||||||
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
|
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
|
||||||
|
|
||||||
|
return get_function_object_int(t_name, 0).second;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \returns a function object (Boxed_Value wrapper) if it exists
|
||||||
|
/// \throws std::range_error if it does not
|
||||||
|
/// \warn does not obtain a mutex lock. \sa get_function_object for public version
|
||||||
|
std::pair<size_t, Boxed_Value> get_function_object_int(const std::string &t_name, const size_t t_hint) const
|
||||||
|
{
|
||||||
const auto &funs = get_boxed_functions_int();
|
const auto &funs = get_boxed_functions_int();
|
||||||
|
|
||||||
auto itr = funs.find(t_name);
|
auto itr = find_keyed_value(funs, t_name, t_hint);
|
||||||
|
|
||||||
if (itr != funs.end())
|
if (itr != funs.end())
|
||||||
{
|
{
|
||||||
return itr->second;
|
return std::make_pair(std::distance(funs.begin(), itr), itr->second);
|
||||||
} else {
|
} else {
|
||||||
throw std::range_error("Object not found: " + t_name);
|
throw std::range_error("Object not found: " + t_name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Return true if a function exists
|
/// Return true if a function exists
|
||||||
bool function_exists(const std::string &name) const
|
bool function_exists(const std::string &name) const
|
||||||
{
|
{
|
||||||
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
|
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
|
||||||
|
|
||||||
const auto &functions = get_functions_int();
|
const auto &functions = get_functions_int();
|
||||||
return functions.find(name) != functions.end();
|
return find_keyed_value(functions, name) != functions.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \returns All values in the local thread state in the parent scope, or if it doesn't exist,
|
/// \returns All values in the local thread state in the parent scope, or if it doesn't exist,
|
||||||
@@ -810,11 +836,8 @@ namespace chaiscript
|
|||||||
}
|
}
|
||||||
|
|
||||||
// add the global values
|
// add the global values
|
||||||
{
|
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
|
||||||
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_global_object_mutex);
|
retval.insert(m_state.m_global_objects.begin(), m_state.m_global_objects.end());
|
||||||
|
|
||||||
retval.insert(m_state.m_global_objects.begin(), m_state.m_global_objects.end());
|
|
||||||
}
|
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
@@ -851,7 +874,7 @@ namespace chaiscript
|
|||||||
|
|
||||||
for (const auto & function : functions)
|
for (const auto & function : functions)
|
||||||
{
|
{
|
||||||
for (const auto & internal_func : function.second)
|
for (const auto & internal_func : *function.second)
|
||||||
{
|
{
|
||||||
rets.emplace_back(function.first, internal_func);
|
rets.emplace_back(function.first, internal_func);
|
||||||
}
|
}
|
||||||
@@ -896,38 +919,54 @@ namespace chaiscript
|
|||||||
#pragma warning(push)
|
#pragma warning(push)
|
||||||
#pragma warning(disable : 4715)
|
#pragma warning(disable : 4715)
|
||||||
#endif
|
#endif
|
||||||
Boxed_Value call_member(const std::string &t_name, const std::vector<Boxed_Value> ¶ms, bool t_has_params) const
|
Boxed_Value call_member(const std::string &t_name, std::atomic_uint_fast32_t &t_loc, const std::vector<Boxed_Value> ¶ms, bool t_has_params)
|
||||||
{
|
{
|
||||||
const auto funs = get_function(t_name);
|
uint_fast32_t loc = t_loc.load(std::memory_order_relaxed);
|
||||||
|
const auto funs = get_function(t_name, loc);
|
||||||
|
if (funs.first != loc) t_loc.store(uint_fast32_t(funs.first), std::memory_order_relaxed);
|
||||||
|
|
||||||
const auto do_attribute_call =
|
const auto do_attribute_call =
|
||||||
[this](int l_num_params, const std::vector<Boxed_Value> &l_params, const std::vector<Proxy_Function> &l_funs, const Type_Conversions &l_conversions)->Boxed_Value
|
[this](int l_num_params, const std::vector<Boxed_Value> &l_params, const std::vector<Proxy_Function> &l_funs, const Type_Conversions &l_conversions)->Boxed_Value
|
||||||
{
|
{
|
||||||
std::vector<Boxed_Value> attr_params{l_params.begin(), l_params.begin() + l_num_params};
|
std::vector<Boxed_Value> attr_params{l_params.begin(), l_params.begin() + l_num_params};
|
||||||
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);
|
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>())) {
|
if (l_num_params < int(l_params.size()) || bv.get_type_info().bare_equal(user_type<dispatch::Proxy_Function_Base>())) {
|
||||||
|
struct This_Foist {
|
||||||
|
This_Foist(Dispatch_Engine &e, const Boxed_Value &t_bv) : m_e(e) {
|
||||||
|
m_e.get().new_scope();
|
||||||
|
m_e.get().add_object("__this", t_bv);
|
||||||
|
}
|
||||||
|
|
||||||
|
~This_Foist() {
|
||||||
|
m_e.get().pop_scope();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::reference_wrapper<Dispatch_Engine> m_e;
|
||||||
|
};
|
||||||
|
|
||||||
|
This_Foist fi(*this, l_params.front());
|
||||||
|
|
||||||
auto func = boxed_cast<std::shared_ptr<const dispatch::Proxy_Function_Base>>(bv);
|
auto func = boxed_cast<std::shared_ptr<const dispatch::Proxy_Function_Base>>(bv);
|
||||||
try {
|
try {
|
||||||
return (*func)(remaining_params, l_conversions);
|
return (*func)({l_params.begin() + l_num_params, l_params.end()}, l_conversions);
|
||||||
} catch (const chaiscript::exception::bad_boxed_cast &) {
|
} catch (const chaiscript::exception::bad_boxed_cast &) {
|
||||||
} catch (const chaiscript::exception::arity_error &) {
|
} catch (const chaiscript::exception::arity_error &) {
|
||||||
} catch (const chaiscript::exception::guard_error &) {
|
} catch (const chaiscript::exception::guard_error &) {
|
||||||
}
|
}
|
||||||
throw chaiscript::exception::dispatch_error(remaining_params, std::vector<Const_Proxy_Function>{func});
|
throw chaiscript::exception::dispatch_error({l_params.begin() + l_num_params, l_params.end()}, std::vector<Const_Proxy_Function>{func});
|
||||||
} else {
|
} else {
|
||||||
return bv;
|
return bv;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if (is_attribute_call(funs, params, t_has_params)) {
|
if (is_attribute_call(*funs.second, params, t_has_params)) {
|
||||||
return do_attribute_call(1, params, funs, m_conversions);
|
return do_attribute_call(1, params, *funs.second, m_conversions);
|
||||||
} else {
|
} else {
|
||||||
std::exception_ptr except;
|
std::exception_ptr except;
|
||||||
|
|
||||||
if (!funs.empty()) {
|
if (!funs.second->empty()) {
|
||||||
try {
|
try {
|
||||||
return dispatch::dispatch(funs, params, m_conversions);
|
return dispatch::dispatch(*funs.second, params, m_conversions);
|
||||||
} catch(chaiscript::exception::dispatch_error&) {
|
} catch(chaiscript::exception::dispatch_error&) {
|
||||||
except = std::current_exception();
|
except = std::current_exception();
|
||||||
}
|
}
|
||||||
@@ -939,7 +978,9 @@ namespace chaiscript
|
|||||||
const auto functions = [&]()->std::vector<Proxy_Function> {
|
const auto functions = [&]()->std::vector<Proxy_Function> {
|
||||||
std::vector<Proxy_Function> fs;
|
std::vector<Proxy_Function> fs;
|
||||||
|
|
||||||
for (const auto &f : get_function("method_missing"))
|
const auto method_missing_funs = get_method_missing_functions();
|
||||||
|
|
||||||
|
for (const auto &f : *method_missing_funs)
|
||||||
{
|
{
|
||||||
if(f->compare_first_type(params[0], m_conversions)) {
|
if(f->compare_first_type(params[0], m_conversions)) {
|
||||||
fs.push_back(f);
|
fs.push_back(f);
|
||||||
@@ -961,12 +1002,17 @@ namespace chaiscript
|
|||||||
}();
|
}();
|
||||||
|
|
||||||
if (!functions.empty()) {
|
if (!functions.empty()) {
|
||||||
if (is_no_param) {
|
try {
|
||||||
std::vector<Boxed_Value> tmp_params(params);
|
if (is_no_param) {
|
||||||
tmp_params.insert(tmp_params.begin() + 1, var(t_name));
|
std::vector<Boxed_Value> tmp_params(params);
|
||||||
return do_attribute_call(2, tmp_params, functions, m_conversions);
|
tmp_params.insert(tmp_params.begin() + 1, var(t_name));
|
||||||
} else {
|
return do_attribute_call(2, tmp_params, functions, m_conversions);
|
||||||
return dispatch::dispatch(functions, {params[0], var(t_name), var(std::vector<Boxed_Value>(params.begin()+1, params.end()))}, m_conversions);
|
} else {
|
||||||
|
return dispatch::dispatch(functions, {params[0], var(t_name), var(std::vector<Boxed_Value>(params.begin()+1, params.end()))}, m_conversions);
|
||||||
|
}
|
||||||
|
} catch (const dispatch::option_explicit_set &e) {
|
||||||
|
throw chaiscript::exception::dispatch_error(params, std::vector<Const_Proxy_Function>(funs.second->begin(), funs.second->end()),
|
||||||
|
e.what());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -975,7 +1021,7 @@ namespace chaiscript
|
|||||||
if (except) {
|
if (except) {
|
||||||
std::rethrow_exception(except);
|
std::rethrow_exception(except);
|
||||||
} else {
|
} else {
|
||||||
throw chaiscript::exception::dispatch_error(params, std::vector<Const_Proxy_Function>(funs.begin(), funs.end()));
|
throw chaiscript::exception::dispatch_error(params, std::vector<Const_Proxy_Function>(funs.second->begin(), funs.second->end()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -985,30 +1031,14 @@ namespace chaiscript
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
Boxed_Value call_function(const std::string &t_name, const std::vector<Boxed_Value> ¶ms) const
|
Boxed_Value call_function(const std::string &t_name, std::atomic_uint_fast32_t &t_loc, const std::vector<Boxed_Value> ¶ms) const
|
||||||
{
|
{
|
||||||
Boxed_Value bv = dispatch::dispatch(get_function(t_name), params, m_conversions);
|
uint_fast32_t loc = t_loc.load(std::memory_order_relaxed);
|
||||||
// the result of a clone is never to be marked as a return_value
|
const auto funs = get_function(t_name, loc);
|
||||||
if (t_name == "clone") {
|
if (funs.first != loc) t_loc.store(uint_fast32_t(funs.first), std::memory_order_relaxed);
|
||||||
bv.reset_return_value();
|
return dispatch::dispatch(*funs.second, params, m_conversions);
|
||||||
}
|
|
||||||
return bv;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Boxed_Value call_function(const std::string &t_name) const
|
|
||||||
{
|
|
||||||
return call_function(t_name, std::vector<Boxed_Value>());
|
|
||||||
}
|
|
||||||
|
|
||||||
Boxed_Value call_function(const std::string &t_name, Boxed_Value p1) const
|
|
||||||
{
|
|
||||||
return call_function(t_name, std::vector<Boxed_Value>({std::move(p1)}));
|
|
||||||
}
|
|
||||||
|
|
||||||
Boxed_Value call_function(const std::string &t_name, Boxed_Value p1, Boxed_Value p2) const
|
|
||||||
{
|
|
||||||
return call_function(t_name, std::vector<Boxed_Value>({std::move(p1), std::move(p2)}));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Dump object info to stdout
|
/// Dump object info to stdout
|
||||||
void dump_object(const Boxed_Value &o) const
|
void dump_object(const Boxed_Value &o) const
|
||||||
@@ -1119,7 +1149,6 @@ namespace chaiscript
|
|||||||
State get_state() const
|
State get_state() const
|
||||||
{
|
{
|
||||||
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
|
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
|
||||||
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l2(m_global_object_mutex);
|
|
||||||
|
|
||||||
return m_state;
|
return m_state;
|
||||||
}
|
}
|
||||||
@@ -1127,7 +1156,6 @@ namespace chaiscript
|
|||||||
void set_state(const State &t_state)
|
void set_state(const State &t_state)
|
||||||
{
|
{
|
||||||
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
|
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
|
||||||
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l2(m_global_object_mutex);
|
|
||||||
|
|
||||||
m_state = t_state;
|
m_state = t_state;
|
||||||
}
|
}
|
||||||
@@ -1205,7 +1233,6 @@ namespace chaiscript
|
|||||||
return *m_stack_holder;
|
return *m_stack_holder;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
|
||||||
/// Returns the current stack
|
/// Returns the current stack
|
||||||
/// make const/non const versions
|
/// make const/non const versions
|
||||||
const StackData &get_stack_data() const
|
const StackData &get_stack_data() const
|
||||||
@@ -1223,32 +1250,34 @@ namespace chaiscript
|
|||||||
return m_stack_holder->stacks.back();
|
return m_stack_holder->stacks.back();
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::map<std::string, Boxed_Value> &get_boxed_functions_int() const
|
private:
|
||||||
|
|
||||||
|
const std::vector<std::pair<std::string, Boxed_Value>> &get_boxed_functions_int() const
|
||||||
{
|
{
|
||||||
return m_state.m_boxed_functions;
|
return m_state.m_boxed_functions;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::map<std::string, Boxed_Value> &get_boxed_functions_int()
|
std::vector<std::pair<std::string, Boxed_Value>> &get_boxed_functions_int()
|
||||||
{
|
{
|
||||||
return m_state.m_boxed_functions;
|
return m_state.m_boxed_functions;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::map<std::string, Proxy_Function> &get_function_objects_int() const
|
const std::vector<std::pair<std::string, Proxy_Function>> &get_function_objects_int() const
|
||||||
{
|
{
|
||||||
return m_state.m_function_objects;
|
return m_state.m_function_objects;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::map<std::string, Proxy_Function> &get_function_objects_int()
|
std::vector<std::pair<std::string, Proxy_Function>> &get_function_objects_int()
|
||||||
{
|
{
|
||||||
return m_state.m_function_objects;
|
return m_state.m_function_objects;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::map<std::string, std::vector<Proxy_Function> > &get_functions_int() const
|
const std::vector<std::pair<std::string, std::shared_ptr<std::vector<Proxy_Function>>>> &get_functions_int() const
|
||||||
{
|
{
|
||||||
return m_state.m_functions;
|
return m_state.m_functions;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::map<std::string, std::vector<Proxy_Function> > &get_functions_int()
|
std::vector<std::pair<std::string, std::shared_ptr<std::vector<Proxy_Function>>>> &get_functions_int()
|
||||||
{
|
{
|
||||||
return m_state.m_functions;
|
return m_state.m_functions;
|
||||||
}
|
}
|
||||||
@@ -1362,6 +1391,49 @@ namespace chaiscript
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename Container, typename Key, typename Value>
|
||||||
|
static void add_keyed_value(Container &t_c, const Key &t_key, Value &&t_value)
|
||||||
|
{
|
||||||
|
auto itr = find_keyed_value(t_c, t_key);
|
||||||
|
|
||||||
|
if (itr == t_c.end()) {
|
||||||
|
t_c.reserve(t_c.size() + 1); // tightly control growth of memory usage here
|
||||||
|
t_c.emplace_back(t_key, std::forward<Value>(t_value));
|
||||||
|
} else {
|
||||||
|
typedef typename Container::value_type value_type;
|
||||||
|
*itr = value_type(t_key, std::forward<Value>(t_value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Container, typename Key>
|
||||||
|
static typename Container::iterator find_keyed_value(Container &t_c, const Key &t_key)
|
||||||
|
{
|
||||||
|
return std::find_if(t_c.begin(), t_c.end(),
|
||||||
|
[&t_key](const typename Container::value_type &o) {
|
||||||
|
return o.first == t_key;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Container, typename Key>
|
||||||
|
static typename Container::const_iterator find_keyed_value(const Container &t_c, const Key &t_key)
|
||||||
|
{
|
||||||
|
return std::find_if(t_c.begin(), t_c.end(),
|
||||||
|
[&t_key](const typename Container::value_type &o) {
|
||||||
|
return o.first == t_key;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Container, typename Key>
|
||||||
|
static typename Container::const_iterator find_keyed_value(const Container &t_c, const Key &t_key, const size_t t_hint)
|
||||||
|
{
|
||||||
|
if (t_c.size() > t_hint && t_c[t_hint].first == t_key) {
|
||||||
|
return t_c.begin() + t_hint;
|
||||||
|
} else {
|
||||||
|
return find_keyed_value(t_c, t_key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Implementation detail for adding a function.
|
/// Implementation detail for adding a function.
|
||||||
/// \throws exception::name_conflict_error if there's a function matching the given one being added
|
/// \throws exception::name_conflict_error if there's a function matching the given one being added
|
||||||
void add_function(const Proxy_Function &t_f, const std::string &t_name)
|
void add_function(const Proxy_Function &t_f, const std::string &t_name)
|
||||||
@@ -1370,16 +1442,13 @@ namespace chaiscript
|
|||||||
|
|
||||||
auto &funcs = get_functions_int();
|
auto &funcs = get_functions_int();
|
||||||
|
|
||||||
auto itr = funcs.find(t_name);
|
auto itr = find_keyed_value(funcs, t_name);
|
||||||
|
|
||||||
auto &func_objs = get_function_objects_int();
|
|
||||||
auto &boxed_funcs = get_boxed_functions_int();
|
|
||||||
|
|
||||||
Proxy_Function new_func =
|
Proxy_Function new_func =
|
||||||
[&]() -> Proxy_Function {
|
[&]() -> Proxy_Function {
|
||||||
if (itr != funcs.end())
|
if (itr != funcs.end())
|
||||||
{
|
{
|
||||||
auto &vec = itr->second;
|
auto vec = *itr->second;
|
||||||
for (const auto &func : vec)
|
for (const auto &func : vec)
|
||||||
{
|
{
|
||||||
if ((*t_f) == *(func))
|
if ((*t_f) == *(func))
|
||||||
@@ -1388,33 +1457,35 @@ namespace chaiscript
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vec.reserve(vec.size() + 1); // tightly control vec growth
|
||||||
vec.push_back(t_f);
|
vec.push_back(t_f);
|
||||||
std::stable_sort(vec.begin(), vec.end(), &function_less_than);
|
std::stable_sort(vec.begin(), vec.end(), &function_less_than);
|
||||||
return std::make_shared<Dispatch_Function>(vec);
|
itr->second = std::make_shared<std::vector<Proxy_Function>>(vec);
|
||||||
|
return std::make_shared<Dispatch_Function>(std::move(vec));
|
||||||
} else if (t_f->has_arithmetic_param()) {
|
} else if (t_f->has_arithmetic_param()) {
|
||||||
// if the function is the only function but it also contains
|
// if the function is the only function but it also contains
|
||||||
// arithmetic operators, we must wrap it in a dispatch function
|
// arithmetic operators, we must wrap it in a dispatch function
|
||||||
// to allow for automatic arithmetic type conversions
|
// to allow for automatic arithmetic type conversions
|
||||||
std::vector<Proxy_Function> vec({t_f});
|
std::vector<Proxy_Function> vec({t_f});
|
||||||
funcs.insert(std::make_pair(t_name, vec));
|
funcs.emplace_back(t_name, std::make_shared<std::vector<Proxy_Function>>(vec));
|
||||||
return std::make_shared<Dispatch_Function>(std::move(vec));
|
return std::make_shared<Dispatch_Function>(std::move(vec));
|
||||||
} else {
|
} else {
|
||||||
funcs.insert(std::make_pair(t_name, std::vector<Proxy_Function>{t_f}));
|
funcs.emplace_back(t_name, std::make_shared<std::vector<Proxy_Function>>(std::initializer_list<Proxy_Function>({t_f})));
|
||||||
return t_f;
|
return t_f;
|
||||||
}
|
}
|
||||||
}();
|
}();
|
||||||
|
|
||||||
boxed_funcs[t_name] = const_var(new_func);
|
add_keyed_value(get_boxed_functions_int(), t_name, const_var(new_func));
|
||||||
func_objs[t_name] = std::move(new_func);
|
add_keyed_value(get_function_objects_int(), t_name, std::move(new_func));
|
||||||
}
|
}
|
||||||
|
|
||||||
mutable chaiscript::detail::threading::shared_mutex m_mutex;
|
mutable chaiscript::detail::threading::shared_mutex m_mutex;
|
||||||
mutable chaiscript::detail::threading::shared_mutex m_global_object_mutex;
|
|
||||||
|
|
||||||
|
|
||||||
Type_Conversions m_conversions;
|
Type_Conversions m_conversions;
|
||||||
chaiscript::detail::threading::Thread_Storage<Stack_Holder> m_stack_holder;
|
chaiscript::detail::threading::Thread_Storage<Stack_Holder> m_stack_holder;
|
||||||
|
|
||||||
|
mutable std::atomic_uint_fast32_t m_method_missing_loc;
|
||||||
|
|
||||||
State m_state;
|
State m_state;
|
||||||
};
|
};
|
||||||
@@ -1440,6 +1511,10 @@ namespace chaiscript
|
|||||||
return m_stack_holder.get();
|
return m_stack_holder.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void add_object(const std::string &t_name, Boxed_Value obj) const {
|
||||||
|
m_engine.get().add_object(t_name, std::move(obj), m_stack_holder.get());
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::reference_wrapper<Dispatch_Engine> m_engine;
|
std::reference_wrapper<Dispatch_Engine> m_engine;
|
||||||
std::reference_wrapper<Stack_Holder> m_stack_holder;
|
std::reference_wrapper<Stack_Holder> m_stack_holder;
|
||||||
|
|||||||
@@ -24,23 +24,55 @@ namespace chaiscript
|
|||||||
{
|
{
|
||||||
namespace dispatch
|
namespace dispatch
|
||||||
{
|
{
|
||||||
|
struct option_explicit_set : std::runtime_error {
|
||||||
|
option_explicit_set(const std::string &t_param_name)
|
||||||
|
: std::runtime_error("option explicit set and parameter '" + t_param_name + "' does not exist")
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
option_explicit_set(const option_explicit_set &) = default;
|
||||||
|
|
||||||
|
virtual ~option_explicit_set() CHAISCRIPT_NOEXCEPT {}
|
||||||
|
};
|
||||||
|
|
||||||
class Dynamic_Object
|
class Dynamic_Object
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Dynamic_Object(std::string t_type_name)
|
Dynamic_Object(std::string t_type_name)
|
||||||
: m_type_name(std::move(t_type_name))
|
: m_type_name(std::move(t_type_name)), m_option_explicit(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
Dynamic_Object() : m_type_name("")
|
Dynamic_Object() : m_type_name(""), m_option_explicit(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool is_explicit() const
|
||||||
|
{
|
||||||
|
return m_option_explicit;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_explicit(const bool t_explicit)
|
||||||
|
{
|
||||||
|
m_option_explicit = t_explicit;
|
||||||
|
}
|
||||||
|
|
||||||
std::string get_type_name() const
|
std::string get_type_name() const
|
||||||
{
|
{
|
||||||
return m_type_name;
|
return m_type_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const Boxed_Value &operator[](const std::string &t_attr_name) const
|
||||||
|
{
|
||||||
|
return get_attr(t_attr_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
Boxed_Value &operator[](const std::string &t_attr_name)
|
||||||
|
{
|
||||||
|
return get_attr(t_attr_name);
|
||||||
|
}
|
||||||
|
|
||||||
const Boxed_Value &get_attr(const std::string &t_attr_name) const
|
const Boxed_Value &get_attr(const std::string &t_attr_name) const
|
||||||
{
|
{
|
||||||
auto a = m_attrs.find(t_attr_name);
|
auto a = m_attrs.find(t_attr_name);
|
||||||
@@ -59,11 +91,19 @@ namespace chaiscript
|
|||||||
|
|
||||||
Boxed_Value &method_missing(const std::string &t_method_name)
|
Boxed_Value &method_missing(const std::string &t_method_name)
|
||||||
{
|
{
|
||||||
|
if (m_option_explicit && m_attrs.find(t_method_name) == m_attrs.end()) {
|
||||||
|
throw option_explicit_set(t_method_name);
|
||||||
|
}
|
||||||
|
|
||||||
return get_attr(t_method_name);
|
return get_attr(t_method_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
const Boxed_Value &method_missing(const std::string &t_method_name) const
|
const Boxed_Value &method_missing(const std::string &t_method_name) const
|
||||||
{
|
{
|
||||||
|
if (m_option_explicit && m_attrs.find(t_method_name) == m_attrs.end()) {
|
||||||
|
throw option_explicit_set(t_method_name);
|
||||||
|
}
|
||||||
|
|
||||||
return get_attr(t_method_name);
|
return get_attr(t_method_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -75,6 +115,7 @@ namespace chaiscript
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
std::string m_type_name;
|
std::string m_type_name;
|
||||||
|
bool m_option_explicit;
|
||||||
|
|
||||||
std::map<std::string, Boxed_Value> m_attrs;
|
std::map<std::string, Boxed_Value> m_attrs;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -232,7 +232,7 @@ namespace chaiscript
|
|||||||
protected:
|
protected:
|
||||||
virtual Boxed_Value do_call(const std::vector<Boxed_Value> ¶ms, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
|
virtual Boxed_Value do_call(const std::vector<Boxed_Value> ¶ms, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
|
||||||
{
|
{
|
||||||
auto bv = var(Dynamic_Object(m_type_name));
|
auto bv = Boxed_Value(Dynamic_Object(m_type_name), true);
|
||||||
std::vector<Boxed_Value> new_params{bv};
|
std::vector<Boxed_Value> new_params{bv};
|
||||||
new_params.insert(new_params.end(), params.begin(), params.end());
|
new_params.insert(new_params.end(), params.begin(), params.end());
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
#include "boxed_cast.hpp"
|
#include "boxed_cast.hpp"
|
||||||
#include "function_call_detail.hpp"
|
#include "function_call_detail.hpp"
|
||||||
#include "proxy_functions.hpp"
|
#include "proxy_functions.hpp"
|
||||||
|
#include "callable_traits.hpp"
|
||||||
|
|
||||||
namespace chaiscript {
|
namespace chaiscript {
|
||||||
class Boxed_Value;
|
class Boxed_Value;
|
||||||
@@ -37,6 +38,15 @@ namespace chaiscript
|
|||||||
std::function<FunctionType>
|
std::function<FunctionType>
|
||||||
functor(const std::vector<Const_Proxy_Function> &funcs, const Type_Conversions *t_conversions)
|
functor(const std::vector<Const_Proxy_Function> &funcs, const Type_Conversions *t_conversions)
|
||||||
{
|
{
|
||||||
|
const bool has_arity_match = std::any_of(funcs.begin(), funcs.end(),
|
||||||
|
[](const Const_Proxy_Function &f) {
|
||||||
|
return f->get_arity() == -1 || size_t(f->get_arity()) == chaiscript::dispatch::detail::Arity<FunctionType>::arity;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!has_arity_match) {
|
||||||
|
throw exception::bad_boxed_cast(user_type<Const_Proxy_Function>(), typeid(std::function<FunctionType>));
|
||||||
|
}
|
||||||
|
|
||||||
FunctionType *p=nullptr;
|
FunctionType *p=nullptr;
|
||||||
return detail::build_function_caller_helper(p, funcs, t_conversions);
|
return detail::build_function_caller_helper(p, funcs, t_conversions);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -211,7 +211,7 @@ namespace chaiscript
|
|||||||
if (ti.is_undef()
|
if (ti.is_undef()
|
||||||
|| ti.bare_equal(user_type<Boxed_Value>())
|
|| ti.bare_equal(user_type<Boxed_Value>())
|
||||||
|| (!bv.get_type_info().is_undef()
|
|| (!bv.get_type_info().is_undef()
|
||||||
&& (ti.bare_equal(user_type<Boxed_Number>())
|
&& ( (ti.bare_equal(user_type<Boxed_Number>()) && bv.get_type_info().is_arithmetic())
|
||||||
|| ti.bare_equal(bv.get_type_info())
|
|| ti.bare_equal(bv.get_type_info())
|
||||||
|| bv.get_type_info().bare_equal(user_type<std::shared_ptr<const Proxy_Function_Base> >())
|
|| bv.get_type_info().bare_equal(user_type<std::shared_ptr<const Proxy_Function_Base> >())
|
||||||
|| t_conversions.converts(ti, bv.get_type_info())
|
|| t_conversions.converts(ti, bv.get_type_info())
|
||||||
@@ -248,7 +248,7 @@ namespace chaiscript
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static bool compare_types(const std::vector<Type_Info> &tis, const std::vector<Boxed_Value> &bvs)
|
static bool compare_types(const std::vector<Type_Info> &tis, const std::vector<Boxed_Value> &bvs, const Type_Conversions &t_conversions)
|
||||||
{
|
{
|
||||||
if (tis.size() - 1 != bvs.size())
|
if (tis.size() - 1 != bvs.size())
|
||||||
{
|
{
|
||||||
@@ -257,10 +257,7 @@ namespace chaiscript
|
|||||||
const size_t size = bvs.size();
|
const size_t size = bvs.size();
|
||||||
for (size_t i = 0; i < size; ++i)
|
for (size_t i = 0; i < size; ++i)
|
||||||
{
|
{
|
||||||
if (!(tis[i+1].bare_equal(bvs[i].get_type_info()) && tis[i+1].is_const() >= bvs[i].get_type_info().is_const() ))
|
if (!compare_type_to_param(tis[i + 1], bvs[i], t_conversions)) { return false; }
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@@ -578,7 +575,7 @@ namespace chaiscript
|
|||||||
|
|
||||||
virtual bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
|
virtual bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
|
||||||
{
|
{
|
||||||
return static_cast<int>(vals.size()) == get_arity() && (compare_types(m_types, vals) || compare_types_with_cast(vals, t_conversions));
|
return static_cast<int>(vals.size()) == get_arity() && (compare_types(m_types, vals, t_conversions) && compare_types_with_cast(vals, t_conversions));
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual bool compare_types_with_cast(const std::vector<Boxed_Value> &vals, const Type_Conversions &t_conversions) const = 0;
|
virtual bool compare_types_with_cast(const std::vector<Boxed_Value> &vals, const Type_Conversions &t_conversions) const = 0;
|
||||||
@@ -763,6 +760,14 @@ namespace chaiscript
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dispatch_error(std::vector<Boxed_Value> t_parameters,
|
||||||
|
std::vector<Const_Proxy_Function> t_functions,
|
||||||
|
const std::string &t_desc)
|
||||||
|
: std::runtime_error(t_desc), parameters(std::move(t_parameters)), functions(std::move(t_functions))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
dispatch_error(const dispatch_error &) = default;
|
dispatch_error(const dispatch_error &) = default;
|
||||||
virtual ~dispatch_error() CHAISCRIPT_NOEXCEPT {}
|
virtual ~dispatch_error() CHAISCRIPT_NOEXCEPT {}
|
||||||
|
|
||||||
|
|||||||
@@ -32,17 +32,17 @@ namespace chaiscript
|
|||||||
CHAISCRIPT_CONSTEXPR Type_Info(bool t_is_const, bool t_is_reference, bool t_is_pointer, bool t_is_void,
|
CHAISCRIPT_CONSTEXPR Type_Info(bool t_is_const, bool t_is_reference, bool t_is_pointer, bool t_is_void,
|
||||||
bool t_is_arithmetic, const std::type_info *t_ti, const std::type_info *t_bare_ti)
|
bool t_is_arithmetic, const std::type_info *t_ti, const std::type_info *t_bare_ti)
|
||||||
: m_type_info(t_ti), m_bare_type_info(t_bare_ti),
|
: m_type_info(t_ti), m_bare_type_info(t_bare_ti),
|
||||||
m_is_const(t_is_const), m_is_reference(t_is_reference), m_is_pointer(t_is_pointer),
|
m_flags((t_is_const << is_const_flag)
|
||||||
m_is_void(t_is_void), m_is_arithmetic(t_is_arithmetic),
|
+ (t_is_reference << is_reference_flag)
|
||||||
m_is_undef(false)
|
+ (t_is_pointer << is_pointer_flag)
|
||||||
|
+ (t_is_void << is_void_flag)
|
||||||
|
+ (t_is_arithmetic << is_arithmetic_flag))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
CHAISCRIPT_CONSTEXPR Type_Info()
|
CHAISCRIPT_CONSTEXPR Type_Info()
|
||||||
: m_type_info(nullptr), m_bare_type_info(nullptr),
|
: m_type_info(nullptr), m_bare_type_info(nullptr),
|
||||||
m_is_const(false), m_is_reference(false), m_is_pointer(false),
|
m_flags(1 << is_undef_flag)
|
||||||
m_is_void(false), m_is_arithmetic(false),
|
|
||||||
m_is_undef(true)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -83,12 +83,12 @@ namespace chaiscript
|
|||||||
&& (*m_bare_type_info) == ti;
|
&& (*m_bare_type_info) == ti;
|
||||||
}
|
}
|
||||||
|
|
||||||
CHAISCRIPT_CONSTEXPR bool is_const() const CHAISCRIPT_NOEXCEPT { return m_is_const; }
|
CHAISCRIPT_CONSTEXPR bool is_const() const CHAISCRIPT_NOEXCEPT { return m_flags & (1 << is_const_flag); }
|
||||||
CHAISCRIPT_CONSTEXPR bool is_reference() const CHAISCRIPT_NOEXCEPT { return m_is_reference; }
|
CHAISCRIPT_CONSTEXPR bool is_reference() const CHAISCRIPT_NOEXCEPT { return m_flags & (1 << is_reference_flag); }
|
||||||
CHAISCRIPT_CONSTEXPR bool is_void() const CHAISCRIPT_NOEXCEPT { return m_is_void; }
|
CHAISCRIPT_CONSTEXPR bool is_void() const CHAISCRIPT_NOEXCEPT { return m_flags & (1 << is_void_flag); }
|
||||||
CHAISCRIPT_CONSTEXPR bool is_arithmetic() const CHAISCRIPT_NOEXCEPT { return m_is_arithmetic; }
|
CHAISCRIPT_CONSTEXPR bool is_arithmetic() const CHAISCRIPT_NOEXCEPT { return m_flags & (1 << is_arithmetic_flag); }
|
||||||
CHAISCRIPT_CONSTEXPR bool is_undef() const CHAISCRIPT_NOEXCEPT { return m_is_undef; }
|
CHAISCRIPT_CONSTEXPR bool is_undef() const CHAISCRIPT_NOEXCEPT { return m_flags & (1 << is_undef_flag); }
|
||||||
CHAISCRIPT_CONSTEXPR bool is_pointer() const CHAISCRIPT_NOEXCEPT { return m_is_pointer; }
|
CHAISCRIPT_CONSTEXPR bool is_pointer() const CHAISCRIPT_NOEXCEPT { return m_flags & (1 << is_pointer_flag); }
|
||||||
|
|
||||||
std::string name() const
|
std::string name() const
|
||||||
{
|
{
|
||||||
@@ -118,12 +118,13 @@ namespace chaiscript
|
|||||||
private:
|
private:
|
||||||
const std::type_info *m_type_info;
|
const std::type_info *m_type_info;
|
||||||
const std::type_info *m_bare_type_info;
|
const std::type_info *m_bare_type_info;
|
||||||
bool m_is_const;
|
unsigned int m_flags;
|
||||||
bool m_is_reference;
|
static const int is_const_flag = 0;
|
||||||
bool m_is_pointer;
|
static const int is_reference_flag = 1;
|
||||||
bool m_is_void;
|
static const int is_pointer_flag = 2;
|
||||||
bool m_is_arithmetic;
|
static const int is_void_flag = 3;
|
||||||
bool m_is_undef;
|
static const int is_arithmetic_flag = 4;
|
||||||
|
static const int is_undef_flag = 5;
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace detail
|
namespace detail
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ namespace chaiscript
|
|||||||
/// Types of AST nodes available to the parser and eval
|
/// Types of AST nodes available to the parser and eval
|
||||||
class AST_Node_Type {
|
class AST_Node_Type {
|
||||||
public:
|
public:
|
||||||
enum Type { Error, Int, Float, Id, Char, Str, Eol, Fun_Call, Inplace_Fun_Call, Arg_List, Variable, Equation, Var_Decl,
|
enum Type { Error, Int, Float, Id, Char, Str, Eol, Fun_Call, Arg_List, Variable, Equation, Var_Decl,
|
||||||
Comparison, Addition, Subtraction, Multiplication, Division, Modulus, Array_Call, Dot_Access, Quoted_String, Single_Quoted_String,
|
Comparison, Addition, Subtraction, Multiplication, Division, Modulus, Array_Call, Dot_Access, Quoted_String, Single_Quoted_String,
|
||||||
Lambda, Block, Def, While, If, For, Inline_Array, Inline_Map, Return, File, Prefix, Break, Continue, Map_Pair, Value_Range,
|
Lambda, Block, Def, While, If, For, Inline_Array, Inline_Map, Return, File, Prefix, Break, Continue, Map_Pair, Value_Range,
|
||||||
Inline_Range, Annotation, Try, Catch, Finally, Method, Attr_Decl, Shift, Equality, Bitwise_And, Bitwise_Xor, Bitwise_Or,
|
Inline_Range, Annotation, Try, Catch, Finally, Method, Attr_Decl, Shift, Equality, Bitwise_And, Bitwise_Xor, Bitwise_Or,
|
||||||
@@ -47,7 +47,7 @@ namespace chaiscript
|
|||||||
|
|
||||||
/// Helper lookup to get the name of each node type
|
/// Helper lookup to get the name of each node type
|
||||||
const char *ast_node_type_to_string(int ast_node_type) {
|
const char *ast_node_type_to_string(int ast_node_type) {
|
||||||
const char *ast_node_types[] = { "Internal Parser Error", "Int", "Float", "Id", "Char", "Str", "Eol", "Fun_Call", "Inplace_Fun_Call", "Arg_List", "Variable", "Equation", "Var_Decl",
|
const char *ast_node_types[] = { "Internal Parser Error", "Int", "Float", "Id", "Char", "Str", "Eol", "Fun_Call", "Arg_List", "Variable", "Equation", "Var_Decl",
|
||||||
"Comparison", "Addition", "Subtraction", "Multiplication", "Division", "Modulus", "Array_Call", "Dot_Access", "Quoted_String", "Single_Quoted_String",
|
"Comparison", "Addition", "Subtraction", "Multiplication", "Division", "Modulus", "Array_Call", "Dot_Access", "Quoted_String", "Single_Quoted_String",
|
||||||
"Lambda", "Block", "Def", "While", "If", "For", "Inline_Array", "Inline_Map", "Return", "File", "Prefix", "Break", "Continue", "Map_Pair", "Value_Range",
|
"Lambda", "Block", "Def", "While", "If", "For", "Inline_Array", "Inline_Map", "Return", "File", "Prefix", "Break", "Continue", "Map_Pair", "Value_Range",
|
||||||
"Inline_Range", "Annotation", "Try", "Catch", "Finally", "Method", "Attr_Decl", "Shift", "Equality", "Bitwise_And", "Bitwise_Xor", "Bitwise_Or",
|
"Inline_Range", "Annotation", "Try", "Catch", "Finally", "Method", "Attr_Decl", "Shift", "Equality", "Bitwise_And", "Bitwise_Xor", "Bitwise_Or",
|
||||||
|
|||||||
@@ -36,7 +36,9 @@
|
|||||||
#else
|
#else
|
||||||
#ifdef CHAISCRIPT_WINDOWS
|
#ifdef CHAISCRIPT_WINDOWS
|
||||||
#define VC_EXTRA_LEAN
|
#define VC_EXTRA_LEAN
|
||||||
|
#if !defined(WIN32_LEAN_AND_MEAN)
|
||||||
#define WIN32_LEAN_AND_MEAN
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#endif
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
@@ -284,14 +286,7 @@ namespace chaiscript
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
const Boxed_Value internal_eval_ast(const AST_NodePtr &t_ast)
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
return t_ast->eval(m_engine);
|
|
||||||
} catch (const exception::eval_error &t_ee) {
|
|
||||||
throw Boxed_Value(t_ee);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Evaluates the given file and looks in the 'use' paths
|
/// Evaluates the given file and looks in the 'use' paths
|
||||||
const Boxed_Value internal_eval_file(const std::string &t_filename) {
|
const Boxed_Value internal_eval_file(const std::string &t_filename) {
|
||||||
@@ -396,7 +391,8 @@ namespace chaiscript
|
|||||||
m_engine.add(fun([this](const std::string &t_file){ return use(t_file); }), "use");
|
m_engine.add(fun([this](const std::string &t_file){ return use(t_file); }), "use");
|
||||||
m_engine.add(fun([this](const std::string &t_file){ return internal_eval_file(t_file); }), "eval_file");
|
m_engine.add(fun([this](const std::string &t_file){ return internal_eval_file(t_file); }), "eval_file");
|
||||||
m_engine.add(fun([this](const std::string &t_str){ return internal_eval(t_str); }), "eval");
|
m_engine.add(fun([this](const std::string &t_str){ return internal_eval(t_str); }), "eval");
|
||||||
m_engine.add(fun([this](const AST_NodePtr &t_ast){ return internal_eval_ast(t_ast); }), "eval");
|
m_engine.add(fun([this](const AST_NodePtr &t_ast){ return eval(t_ast); }), "eval");
|
||||||
|
m_engine.add(fun(&parse), "parse");
|
||||||
|
|
||||||
m_engine.add(fun(&ChaiScript::version_major), "version_major");
|
m_engine.add(fun(&ChaiScript::version_major), "version_major");
|
||||||
m_engine.add(fun(&ChaiScript::version_minor), "version_minor");
|
m_engine.add(fun(&ChaiScript::version_minor), "version_minor");
|
||||||
@@ -517,6 +513,28 @@ namespace chaiscript
|
|||||||
build_eval_system(ModulePtr());
|
build_eval_system(ModulePtr());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const Boxed_Value eval(const AST_NodePtr &t_ast)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
return t_ast->eval(m_engine);
|
||||||
|
} catch (const exception::eval_error &t_ee) {
|
||||||
|
throw Boxed_Value(t_ee);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static AST_NodePtr parse(const std::string &t_input)
|
||||||
|
{
|
||||||
|
parser::ChaiScript_Parser parser;
|
||||||
|
if (parser.parse(t_input, "PARSE")) {
|
||||||
|
//parser.show_match_stack();
|
||||||
|
return parser.optimized_ast();
|
||||||
|
} else {
|
||||||
|
throw chaiscript::exception::eval_error("Unknown error while parsing");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static int version_major()
|
static int version_major()
|
||||||
{
|
{
|
||||||
return chaiscript::version_major;
|
return chaiscript::version_major;
|
||||||
|
|||||||
@@ -44,16 +44,33 @@ namespace chaiscript
|
|||||||
namespace detail
|
namespace detail
|
||||||
{
|
{
|
||||||
/// Helper function that will set up the scope around a function call, including handling the named function parameters
|
/// 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>()) {
|
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=nullptr) {
|
||||||
chaiscript::detail::Dispatch_State state(t_ss);
|
chaiscript::detail::Dispatch_State state(t_ss);
|
||||||
chaiscript::eval::detail::Scope_Push_Pop spp(state);
|
|
||||||
|
|
||||||
for (const auto &local : t_locals) {
|
const Boxed_Value *thisobj = [&]() -> const Boxed_Value *{
|
||||||
t_ss.add_object(local.first, local.second);
|
auto &stack = t_ss.get_stack_data(state.stack_holder()).back();
|
||||||
|
if (!stack.empty() && stack.back().first == "__this") {
|
||||||
|
return &stack.back().second;
|
||||||
|
} else if (!t_vals.empty()) {
|
||||||
|
return &t_vals[0];
|
||||||
|
} else {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}();
|
||||||
|
|
||||||
|
chaiscript::eval::detail::Stack_Push_Pop tpp(state);
|
||||||
|
if (thisobj) state.add_object("this", *thisobj);
|
||||||
|
|
||||||
|
if (t_locals) {
|
||||||
|
for (const auto &local : *t_locals) {
|
||||||
|
state.add_object(local.first, local.second);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < t_param_names.size(); ++i) {
|
for (size_t i = 0; i < t_param_names.size(); ++i) {
|
||||||
t_ss.add_object(t_param_names[i], t_vals[i]);
|
if (t_param_names[i] != "this") {
|
||||||
|
state.add_object(t_param_names[i], t_vals[i]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -73,9 +90,9 @@ namespace chaiscript
|
|||||||
|
|
||||||
virtual ~Binary_Operator_AST_Node() {}
|
virtual ~Binary_Operator_AST_Node() {}
|
||||||
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &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,
|
auto lhs = this->children[0]->eval(t_ss);
|
||||||
this->children[0]->eval(t_ss),
|
auto rhs = this->children[1]->eval(t_ss);
|
||||||
this->children[1]->eval(t_ss));
|
return do_oper(t_ss, m_oper, text, lhs, rhs);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual std::string pretty_print() const CHAISCRIPT_OVERRIDE
|
virtual std::string pretty_print() const CHAISCRIPT_OVERRIDE
|
||||||
@@ -101,8 +118,7 @@ namespace chaiscript
|
|||||||
} else {
|
} else {
|
||||||
chaiscript::eval::detail::Function_Push_Pop fpp(t_ss);
|
chaiscript::eval::detail::Function_Push_Pop fpp(t_ss);
|
||||||
fpp.save_params({t_lhs, t_rhs});
|
fpp.save_params({t_lhs, t_rhs});
|
||||||
chaiscript::eval::detail::Stack_Push_Pop spp(t_ss);
|
return t_ss->call_function(t_oper_string, m_loc, {t_lhs, t_rhs});
|
||||||
return t_ss->call_function(t_oper_string, t_lhs, t_rhs);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch(const exception::dispatch_error &e){
|
catch(const exception::dispatch_error &e){
|
||||||
@@ -112,13 +128,14 @@ namespace chaiscript
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
Operators::Opers m_oper;
|
Operators::Opers m_oper;
|
||||||
|
mutable std::atomic_uint_fast32_t m_loc;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Int_AST_Node : public AST_Node {
|
struct Int_AST_Node : public AST_Node {
|
||||||
public:
|
public:
|
||||||
Int_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, Boxed_Value t_bv) :
|
Int_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, Boxed_Value t_bv) :
|
||||||
AST_Node(std::move(t_ast_node_text), AST_Node_Type::Int, std::move(t_loc)),
|
AST_Node(std::move(t_ast_node_text), AST_Node_Type::Int, std::move(t_loc)),
|
||||||
m_value(std::move(t_bv)) { }
|
m_value(std::move(t_bv)) { assert(text != ""); }
|
||||||
virtual ~Int_AST_Node() {}
|
virtual ~Int_AST_Node() {}
|
||||||
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &) const CHAISCRIPT_OVERRIDE{
|
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &) const CHAISCRIPT_OVERRIDE{
|
||||||
return m_value;
|
return m_value;
|
||||||
@@ -236,7 +253,6 @@ namespace chaiscript
|
|||||||
Boxed_Value fn(this->children[0]->eval(t_ss));
|
Boxed_Value fn(this->children[0]->eval(t_ss));
|
||||||
|
|
||||||
try {
|
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){
|
catch(const exception::dispatch_error &e){
|
||||||
@@ -286,73 +302,6 @@ namespace chaiscript
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// Used in the context of in-string ${} evals, so that no new scope is created
|
|
||||||
struct Inplace_Fun_Call_AST_Node : public AST_Node {
|
|
||||||
public:
|
|
||||||
Inplace_Fun_Call_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_NodePtr> t_children) :
|
|
||||||
AST_Node(t_ast_node_text, AST_Node_Type::Inplace_Fun_Call, std::move(t_loc), std::move(t_children))
|
|
||||||
{ assert(children.size() == 2); }
|
|
||||||
|
|
||||||
virtual ~Inplace_Fun_Call_AST_Node() {}
|
|
||||||
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));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Const_Proxy_Function fn;
|
|
||||||
try {
|
|
||||||
Boxed_Value bv = this->children[0]->eval(t_ss);
|
|
||||||
try {
|
|
||||||
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());
|
|
||||||
}
|
|
||||||
catch(const exception::dispatch_error &e){
|
|
||||||
throw exception::eval_error(std::string(e.what()) + " with function '" + this->children[0]->text + "'", e.parameters, e.functions, false, *t_ss);
|
|
||||||
}
|
|
||||||
catch(const exception::bad_boxed_cast &){
|
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
catch(const exception::arity_error &e){
|
|
||||||
throw exception::eval_error(std::string(e.what()) + " with function '" + this->children[0]->text + "'");
|
|
||||||
}
|
|
||||||
catch(const exception::guard_error &e){
|
|
||||||
throw exception::eval_error(std::string(e.what()) + " with function '" + this->children[0]->text + "'");
|
|
||||||
}
|
|
||||||
catch(detail::Return_Value &rv) {
|
|
||||||
return rv.retval;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual std::string pretty_print() const CHAISCRIPT_OVERRIDE
|
|
||||||
{
|
|
||||||
std::ostringstream oss;
|
|
||||||
int count = 0;
|
|
||||||
for (const auto &child : this->children) {
|
|
||||||
oss << child->pretty_print();
|
|
||||||
|
|
||||||
if (count == 0)
|
|
||||||
{
|
|
||||||
oss << "(";
|
|
||||||
}
|
|
||||||
++count;
|
|
||||||
}
|
|
||||||
|
|
||||||
oss << ")";
|
|
||||||
|
|
||||||
return oss.str();
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Arg_AST_Node : public AST_Node {
|
struct Arg_AST_Node : public AST_Node {
|
||||||
public:
|
public:
|
||||||
Arg_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_NodePtr> t_children) :
|
Arg_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector<AST_NodePtr> t_children) :
|
||||||
@@ -448,6 +397,8 @@ namespace chaiscript
|
|||||||
{ assert(children.size() == 3); }
|
{ assert(children.size() == 3); }
|
||||||
|
|
||||||
Operators::Opers m_oper;
|
Operators::Opers m_oper;
|
||||||
|
mutable std::atomic_uint_fast32_t m_loc;
|
||||||
|
mutable std::atomic_uint_fast32_t m_clone_loc;
|
||||||
|
|
||||||
virtual ~Equation_AST_Node() {}
|
virtual ~Equation_AST_Node() {}
|
||||||
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE {
|
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE {
|
||||||
@@ -483,14 +434,14 @@ namespace chaiscript
|
|||||||
} else {
|
} else {
|
||||||
if (!rhs.is_return_value())
|
if (!rhs.is_return_value())
|
||||||
{
|
{
|
||||||
rhs = t_ss->call_function("clone", rhs);
|
rhs = t_ss->call_function("clone", m_clone_loc, {rhs});
|
||||||
}
|
}
|
||||||
rhs.reset_return_value();
|
rhs.reset_return_value();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return t_ss->call_function(this->children[1]->text, std::move(lhs), rhs);
|
return t_ss->call_function(this->children[1]->text, m_loc, {std::move(lhs), rhs});
|
||||||
}
|
}
|
||||||
catch(const exception::dispatch_error &e){
|
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);
|
||||||
@@ -503,13 +454,14 @@ namespace chaiscript
|
|||||||
else if (this->children[1]->text == ":=") {
|
else if (this->children[1]->text == ":=") {
|
||||||
if (lhs.is_undef() || Boxed_Value::type_match(lhs, rhs)) {
|
if (lhs.is_undef() || Boxed_Value::type_match(lhs, rhs)) {
|
||||||
lhs.assign(rhs);
|
lhs.assign(rhs);
|
||||||
|
lhs.reset_return_value();
|
||||||
} else {
|
} else {
|
||||||
throw exception::eval_error("Mismatched types in equation");
|
throw exception::eval_error("Mismatched types in equation");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
try {
|
try {
|
||||||
return t_ss->call_function(this->children[1]->text, std::move(lhs), rhs);
|
return t_ss->call_function(this->children[1]->text, m_loc, {std::move(lhs), rhs});
|
||||||
} catch(const exception::dispatch_error &e){
|
} 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);
|
||||||
}
|
}
|
||||||
@@ -560,7 +512,7 @@ namespace chaiscript
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
Boxed_Value bv;
|
Boxed_Value bv;
|
||||||
t_ss->add_object(idname, bv);
|
t_ss.add_object(idname, bv);
|
||||||
return bv;
|
return bv;
|
||||||
}
|
}
|
||||||
catch (const exception::reserved_word_error &) {
|
catch (const exception::reserved_word_error &) {
|
||||||
@@ -591,9 +543,8 @@ namespace chaiscript
|
|||||||
std::vector<Boxed_Value> params{children[0]->eval(t_ss), children[1]->eval(t_ss)};
|
std::vector<Boxed_Value> params{children[0]->eval(t_ss), children[1]->eval(t_ss)};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
chaiscript::eval::detail::Stack_Push_Pop spp(t_ss);
|
|
||||||
fpp.save_params(params);
|
fpp.save_params(params);
|
||||||
return t_ss->call_function("[]", params);
|
return t_ss->call_function("[]", m_loc, params);
|
||||||
}
|
}
|
||||||
catch(const exception::dispatch_error &e){
|
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 );
|
||||||
@@ -615,6 +566,8 @@ namespace chaiscript
|
|||||||
|
|
||||||
return oss.str();
|
return oss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mutable std::atomic_uint_fast32_t m_loc;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Dot_Access_AST_Node : public AST_Node {
|
struct Dot_Access_AST_Node : public AST_Node {
|
||||||
@@ -629,6 +582,7 @@ namespace chaiscript
|
|||||||
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &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);
|
chaiscript::eval::detail::Function_Push_Pop fpp(t_ss);
|
||||||
|
|
||||||
|
|
||||||
Boxed_Value retval = children[0]->eval(t_ss);
|
Boxed_Value retval = children[0]->eval(t_ss);
|
||||||
std::vector<Boxed_Value> params{retval};
|
std::vector<Boxed_Value> params{retval};
|
||||||
|
|
||||||
@@ -643,9 +597,7 @@ namespace chaiscript
|
|||||||
fpp.save_params(params);
|
fpp.save_params(params);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
chaiscript::eval::detail::Stack_Push_Pop spp(t_ss);
|
retval = t_ss->call_member(m_fun_name, m_loc, 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){
|
catch(const exception::dispatch_error &e){
|
||||||
if (e.functions.empty())
|
if (e.functions.empty())
|
||||||
@@ -661,7 +613,7 @@ namespace chaiscript
|
|||||||
|
|
||||||
if (this->children[2]->identifier == AST_Node_Type::Array_Call) {
|
if (this->children[2]->identifier == AST_Node_Type::Array_Call) {
|
||||||
try {
|
try {
|
||||||
retval = t_ss->call_function("[]", retval, this->children[2]->children[1]->eval(t_ss));
|
retval = t_ss->call_function("[]", m_array_loc, {retval, this->children[2]->children[1]->eval(t_ss)});
|
||||||
}
|
}
|
||||||
catch(const exception::dispatch_error &e){
|
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);
|
||||||
@@ -672,6 +624,8 @@ namespace chaiscript
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
mutable std::atomic_uint_fast32_t m_loc;
|
||||||
|
mutable std::atomic_uint_fast32_t m_array_loc;
|
||||||
std::string m_fun_name;
|
std::string m_fun_name;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -745,7 +699,7 @@ namespace chaiscript
|
|||||||
dispatch::make_dynamic_proxy_function(
|
dispatch::make_dynamic_proxy_function(
|
||||||
[engine, lambda_node, param_names, captures](const std::vector<Boxed_Value> &t_params)
|
[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);
|
return detail::eval_function(engine, lambda_node, param_names, t_params, &captures);
|
||||||
},
|
},
|
||||||
static_cast<int>(numparams), lambda_node, param_types
|
static_cast<int>(numparams), lambda_node, param_types
|
||||||
)
|
)
|
||||||
@@ -876,7 +830,7 @@ namespace chaiscript
|
|||||||
|
|
||||||
/// \todo do this better
|
/// \todo do this better
|
||||||
// put class name in current scope so it can be looked up by the attrs and methods
|
// 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);
|
children[1]->eval(t_ss);
|
||||||
|
|
||||||
@@ -985,7 +939,7 @@ namespace chaiscript
|
|||||||
if (this->children[currentCase]->identifier == AST_Node_Type::Case) {
|
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.
|
//This is a little odd, but because want to see both the switch and the case simultaneously, I do a downcast here.
|
||||||
try {
|
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("==", m_loc, {match_value, this->children[currentCase]->children[0]->eval(t_ss)}))) {
|
||||||
this->children[currentCase]->eval(t_ss);
|
this->children[currentCase]->eval(t_ss);
|
||||||
hasMatched = true;
|
hasMatched = true;
|
||||||
}
|
}
|
||||||
@@ -996,7 +950,7 @@ namespace chaiscript
|
|||||||
}
|
}
|
||||||
else if (this->children[currentCase]->identifier == AST_Node_Type::Default) {
|
else if (this->children[currentCase]->identifier == AST_Node_Type::Default) {
|
||||||
this->children[currentCase]->eval(t_ss);
|
this->children[currentCase]->eval(t_ss);
|
||||||
breaking = true;
|
hasMatched = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (detail::Break_Loop &) {
|
catch (detail::Break_Loop &) {
|
||||||
@@ -1006,6 +960,8 @@ namespace chaiscript
|
|||||||
}
|
}
|
||||||
return Boxed_Value();
|
return Boxed_Value();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mutable std::atomic_uint_fast32_t m_loc;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Case_AST_Node : public AST_Node {
|
struct Case_AST_Node : public AST_Node {
|
||||||
@@ -1052,7 +1008,7 @@ namespace chaiscript
|
|||||||
for (const auto &child : children[0]->children) {
|
for (const auto &child : children[0]->children) {
|
||||||
auto obj = child->eval(t_ss);
|
auto obj = child->eval(t_ss);
|
||||||
if (!obj.is_return_value()) {
|
if (!obj.is_return_value()) {
|
||||||
vec.push_back(t_ss->call_function("clone", obj));
|
vec.push_back(t_ss->call_function("clone", m_loc, {obj}));
|
||||||
} else {
|
} else {
|
||||||
vec.push_back(std::move(obj));
|
vec.push_back(std::move(obj));
|
||||||
}
|
}
|
||||||
@@ -1069,6 +1025,8 @@ namespace chaiscript
|
|||||||
{
|
{
|
||||||
return "[" + AST_Node::pretty_print() + "]";
|
return "[" + AST_Node::pretty_print() + "]";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mutable std::atomic_uint_fast32_t m_loc;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Inline_Map_AST_Node : public AST_Node {
|
struct Inline_Map_AST_Node : public AST_Node {
|
||||||
@@ -1083,7 +1041,7 @@ namespace chaiscript
|
|||||||
for (const auto &child : children[0]->children) {
|
for (const auto &child : children[0]->children) {
|
||||||
auto obj = child->children[1]->eval(t_ss);
|
auto obj = child->children[1]->eval(t_ss);
|
||||||
if (!obj.is_return_value()) {
|
if (!obj.is_return_value()) {
|
||||||
obj = t_ss->call_function("clone", obj);
|
obj = t_ss->call_function("clone", m_loc, {obj});
|
||||||
}
|
}
|
||||||
|
|
||||||
retval[t_ss->boxed_cast<std::string>(child->children[0]->eval(t_ss))] = std::move(obj);
|
retval[t_ss->boxed_cast<std::string>(child->children[0]->eval(t_ss))] = std::move(obj);
|
||||||
@@ -1096,6 +1054,7 @@ namespace chaiscript
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mutable std::atomic_uint_fast32_t m_loc;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Return_AST_Node : public AST_Node {
|
struct Return_AST_Node : public AST_Node {
|
||||||
@@ -1148,7 +1107,7 @@ namespace chaiscript
|
|||||||
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE{
|
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE{
|
||||||
try {
|
try {
|
||||||
Boxed_Value bv;
|
Boxed_Value bv;
|
||||||
t_ss->add_object(this->children[0]->text, bv);
|
t_ss.add_object(this->children[0]->text, bv);
|
||||||
return bv;
|
return bv;
|
||||||
}
|
}
|
||||||
catch (const exception::reserved_word_error &) {
|
catch (const exception::reserved_word_error &) {
|
||||||
@@ -1177,9 +1136,8 @@ namespace chaiscript
|
|||||||
return Boxed_Number::do_oper(m_oper, bv);
|
return Boxed_Number::do_oper(m_oper, bv);
|
||||||
} else {
|
} else {
|
||||||
chaiscript::eval::detail::Function_Push_Pop fpp(t_ss);
|
chaiscript::eval::detail::Function_Push_Pop fpp(t_ss);
|
||||||
chaiscript::eval::detail::Stack_Push_Pop spp(t_ss);
|
|
||||||
fpp.save_params({bv});
|
fpp.save_params({bv});
|
||||||
return t_ss->call_function(children[0]->text, std::move(bv));
|
return t_ss->call_function(children[0]->text, m_loc, {std::move(bv)});
|
||||||
}
|
}
|
||||||
} catch (const exception::dispatch_error &e) {
|
} 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);
|
||||||
@@ -1188,6 +1146,7 @@ namespace chaiscript
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
Operators::Opers m_oper;
|
Operators::Opers m_oper;
|
||||||
|
mutable std::atomic_uint_fast32_t m_loc;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Break_AST_Node : public AST_Node {
|
struct Break_AST_Node : public AST_Node {
|
||||||
@@ -1248,15 +1207,16 @@ namespace chaiscript
|
|||||||
virtual ~Inline_Range_AST_Node() {}
|
virtual ~Inline_Range_AST_Node() {}
|
||||||
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE{
|
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE{
|
||||||
try {
|
try {
|
||||||
return t_ss->call_function("generate_range",
|
auto oper1 = children[0]->children[0]->children[0]->eval(t_ss);
|
||||||
children[0]->children[0]->children[0]->eval(t_ss),
|
auto oper2 = children[0]->children[0]->children[1]->eval(t_ss);
|
||||||
children[0]->children[0]->children[1]->eval(t_ss));
|
return t_ss->call_function("generate_range", m_loc, {oper1, oper2});
|
||||||
}
|
}
|
||||||
catch (const exception::dispatch_error &e) {
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mutable std::atomic_uint_fast32_t m_loc;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Annotation_AST_Node : public AST_Node {
|
struct Annotation_AST_Node : public AST_Node {
|
||||||
@@ -1296,7 +1256,7 @@ namespace chaiscript
|
|||||||
std::vector<std::pair<std::string, Type_Info>>{Arg_List_AST_Node::get_arg_type(catch_block->children[0], t_ss)}
|
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) {
|
if (catch_block->children.size() == 2) {
|
||||||
//Variable capture, no guards
|
//Variable capture, no guards
|
||||||
@@ -1433,7 +1393,7 @@ namespace chaiscript
|
|||||||
if (guardnode) {
|
if (guardnode) {
|
||||||
guard = dispatch::make_dynamic_proxy_function(
|
guard = dispatch::make_dynamic_proxy_function(
|
||||||
[engine, t_param_names, guardnode](const std::vector<Boxed_Value> &t_params) {
|
[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>());
|
return chaiscript::eval::detail::eval_function(engine, guardnode, t_param_names, t_params);
|
||||||
},
|
},
|
||||||
static_cast<int>(numparams), guardnode);
|
static_cast<int>(numparams), guardnode);
|
||||||
}
|
}
|
||||||
@@ -1450,7 +1410,7 @@ namespace chaiscript
|
|||||||
std::make_shared<dispatch::detail::Dynamic_Object_Constructor>(class_name,
|
std::make_shared<dispatch::detail::Dynamic_Object_Constructor>(class_name,
|
||||||
dispatch::make_dynamic_proxy_function(
|
dispatch::make_dynamic_proxy_function(
|
||||||
[engine, t_param_names, node](const std::vector<Boxed_Value> &t_params) {
|
[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>());
|
return chaiscript::eval::detail::eval_function(engine, node, t_param_names, t_params);
|
||||||
},
|
},
|
||||||
static_cast<int>(numparams), node, param_types, l_annotation, guard
|
static_cast<int>(numparams), node, param_types, l_annotation, guard
|
||||||
)
|
)
|
||||||
@@ -1466,7 +1426,7 @@ namespace chaiscript
|
|||||||
t_ss->add(std::make_shared<dispatch::detail::Dynamic_Object_Function>(class_name,
|
t_ss->add(std::make_shared<dispatch::detail::Dynamic_Object_Function>(class_name,
|
||||||
dispatch::make_dynamic_proxy_function(
|
dispatch::make_dynamic_proxy_function(
|
||||||
[engine, t_param_names, node](const std::vector<Boxed_Value> &t_params) {
|
[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>());
|
return chaiscript::eval::detail::eval_function(engine, node, t_param_names, t_params);
|
||||||
},
|
},
|
||||||
static_cast<int>(numparams), node, param_types, l_annotation, guard), type),
|
static_cast<int>(numparams), node, param_types, l_annotation, guard), type),
|
||||||
function_name);
|
function_name);
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -41,25 +41,25 @@ def new(x) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
def clone(double x) {
|
def clone(double x) {
|
||||||
double(x).copy_var_attrs(x)
|
double(x).clone_var_attrs(x)
|
||||||
}
|
}
|
||||||
|
|
||||||
def clone(string x) {
|
def clone(string x) {
|
||||||
string(x).copy_var_attrs(x)
|
string(x).clone_var_attrs(x)
|
||||||
}
|
}
|
||||||
|
|
||||||
def clone(vector x) {
|
def clone(vector x) {
|
||||||
vector(x).copy_var_attrs(x)
|
vector(x).clone_var_attrs(x)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def clone(int x) {
|
def clone(int x) {
|
||||||
int(x).copy_var_attrs(x)
|
int(x).clone_var_attrs(x)
|
||||||
}
|
}
|
||||||
|
|
||||||
def clone(x) : function_exists(type_name(x)) && call_exists(eval(type_name(x)), x)
|
def clone(x) : function_exists(type_name(x)) && call_exists(eval(type_name(x)), x)
|
||||||
{
|
{
|
||||||
eval(type_name(x))(x).copy_var_attrs(x);
|
eval(type_name(x))(x).clone_var_attrs(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -145,11 +145,6 @@ def reverse(container) {
|
|||||||
retval;
|
retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
# Return a range from a range
|
|
||||||
def range(r) : call_exists(empty, r) && call_exists(pop_front, r) && call_exists(pop_back, r) && call_exists(back, r) && call_exists(front, r)
|
|
||||||
{
|
|
||||||
clone(r);
|
|
||||||
}
|
|
||||||
|
|
||||||
def range(r) : call_exists(range_internal, r)
|
def range(r) : call_exists(range_internal, r)
|
||||||
{
|
{
|
||||||
@@ -158,6 +153,13 @@ def range(r) : call_exists(range_internal, r)
|
|||||||
ri;
|
ri;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Return a range from a range
|
||||||
|
def range(r) : call_exists(empty, r) && call_exists(pop_front, r) && call_exists(pop_back, r) && call_exists(back, r) && call_exists(front, r)
|
||||||
|
{
|
||||||
|
clone(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
# The retro attribute that contains the underlying range
|
# The retro attribute that contains the underlying range
|
||||||
attr retro::m_range;
|
attr retro::m_range;
|
||||||
|
|
||||||
|
|||||||
647
include/chaiscript/utility/json.hpp
Normal file
647
include/chaiscript/utility/json.hpp
Normal file
@@ -0,0 +1,647 @@
|
|||||||
|
// From github.com/nbsdx/SimpleJSON.
|
||||||
|
// Released under the DWTFYW PL
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef SIMPLEJSON_HPP
|
||||||
|
#define SIMPLEJSON_HPP
|
||||||
|
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <cmath>
|
||||||
|
#include <cctype>
|
||||||
|
#include <string>
|
||||||
|
#include <deque>
|
||||||
|
#include <map>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <initializer_list>
|
||||||
|
#include <ostream>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
namespace json {
|
||||||
|
|
||||||
|
using std::map;
|
||||||
|
using std::deque;
|
||||||
|
using std::string;
|
||||||
|
using std::enable_if;
|
||||||
|
using std::initializer_list;
|
||||||
|
using std::is_same;
|
||||||
|
using std::is_convertible;
|
||||||
|
using std::is_integral;
|
||||||
|
using std::is_floating_point;
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
string json_escape( const string &str ) {
|
||||||
|
string output;
|
||||||
|
for( unsigned i = 0; i < str.length(); ++i )
|
||||||
|
switch( str[i] ) {
|
||||||
|
case '\"': output += "\\\""; break;
|
||||||
|
case '\\': output += "\\\\"; break;
|
||||||
|
case '\b': output += "\\b"; break;
|
||||||
|
case '\f': output += "\\f"; break;
|
||||||
|
case '\n': output += "\\n"; break;
|
||||||
|
case '\r': output += "\\r"; break;
|
||||||
|
case '\t': output += "\\t"; break;
|
||||||
|
default : output += str[i]; break;
|
||||||
|
}
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class JSON
|
||||||
|
{
|
||||||
|
union BackingData {
|
||||||
|
BackingData( double d ) : Float( d ){}
|
||||||
|
BackingData( long l ) : Int( l ){}
|
||||||
|
BackingData( bool b ) : Bool( b ){}
|
||||||
|
BackingData( string s ) : String( new string( s ) ){}
|
||||||
|
BackingData() : Int( 0 ){}
|
||||||
|
|
||||||
|
deque<JSON> *List;
|
||||||
|
map<string,JSON> *Map;
|
||||||
|
string *String;
|
||||||
|
double Float;
|
||||||
|
long Int;
|
||||||
|
bool Bool;
|
||||||
|
} Internal;
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum class Class {
|
||||||
|
Null,
|
||||||
|
Object,
|
||||||
|
Array,
|
||||||
|
String,
|
||||||
|
Floating,
|
||||||
|
Integral,
|
||||||
|
Boolean
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Container>
|
||||||
|
class JSONWrapper {
|
||||||
|
Container *object;
|
||||||
|
|
||||||
|
public:
|
||||||
|
JSONWrapper( Container *val ) : object( val ) {}
|
||||||
|
JSONWrapper( std::nullptr_t ) : object( nullptr ) {}
|
||||||
|
|
||||||
|
typename Container::iterator begin() { return object ? object->begin() : typename Container::iterator(); }
|
||||||
|
typename Container::iterator end() { return object ? object->end() : typename Container::iterator(); }
|
||||||
|
typename Container::const_iterator begin() const { return object ? object->begin() : typename Container::iterator(); }
|
||||||
|
typename Container::const_iterator end() const { return object ? object->end() : typename Container::iterator(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Container>
|
||||||
|
class JSONConstWrapper {
|
||||||
|
const Container *object;
|
||||||
|
|
||||||
|
public:
|
||||||
|
JSONConstWrapper( const Container *val ) : object( val ) {}
|
||||||
|
JSONConstWrapper( std::nullptr_t ) : object( nullptr ) {}
|
||||||
|
|
||||||
|
typename Container::const_iterator begin() const { return object ? object->begin() : typename Container::const_iterator(); }
|
||||||
|
typename Container::const_iterator end() const { return object ? object->end() : typename Container::const_iterator(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
JSON() : Internal(), Type( Class::Null ){}
|
||||||
|
|
||||||
|
explicit JSON(Class type)
|
||||||
|
: Internal(), Type(Class::Null)
|
||||||
|
{
|
||||||
|
SetType( type );
|
||||||
|
}
|
||||||
|
|
||||||
|
JSON( initializer_list<JSON> list )
|
||||||
|
: Internal(), Type(Class::Null)
|
||||||
|
{
|
||||||
|
SetType( Class::Object );
|
||||||
|
for( auto i = list.begin(), e = list.end(); i != e; ++i, ++i )
|
||||||
|
operator[]( i->ToString() ) = *std::next( i );
|
||||||
|
}
|
||||||
|
|
||||||
|
JSON( JSON&& other )
|
||||||
|
: Internal( other.Internal )
|
||||||
|
, Type( other.Type )
|
||||||
|
{ other.Type = Class::Null; other.Internal.Map = nullptr; }
|
||||||
|
|
||||||
|
JSON& operator=( JSON&& other ) {
|
||||||
|
Internal = other.Internal;
|
||||||
|
Type = other.Type;
|
||||||
|
other.Internal.Map = nullptr;
|
||||||
|
other.Type = Class::Null;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSON( const JSON &other ) {
|
||||||
|
switch( other.Type ) {
|
||||||
|
case Class::Object:
|
||||||
|
Internal.Map =
|
||||||
|
new map<string,JSON>( other.Internal.Map->begin(),
|
||||||
|
other.Internal.Map->end() );
|
||||||
|
break;
|
||||||
|
case Class::Array:
|
||||||
|
Internal.List =
|
||||||
|
new deque<JSON>( other.Internal.List->begin(),
|
||||||
|
other.Internal.List->end() );
|
||||||
|
break;
|
||||||
|
case Class::String:
|
||||||
|
Internal.String =
|
||||||
|
new string( *other.Internal.String );
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Internal = other.Internal;
|
||||||
|
}
|
||||||
|
Type = other.Type;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSON& operator=( const JSON &other ) {
|
||||||
|
if (&other == this) return *this;
|
||||||
|
|
||||||
|
switch( other.Type ) {
|
||||||
|
case Class::Object:
|
||||||
|
Internal.Map =
|
||||||
|
new map<string,JSON>( other.Internal.Map->begin(),
|
||||||
|
other.Internal.Map->end() );
|
||||||
|
break;
|
||||||
|
case Class::Array:
|
||||||
|
Internal.List =
|
||||||
|
new deque<JSON>( other.Internal.List->begin(),
|
||||||
|
other.Internal.List->end() );
|
||||||
|
break;
|
||||||
|
case Class::String:
|
||||||
|
Internal.String =
|
||||||
|
new string( *other.Internal.String );
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Internal = other.Internal;
|
||||||
|
}
|
||||||
|
Type = other.Type;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
~JSON() {
|
||||||
|
switch( Type ) {
|
||||||
|
case Class::Array:
|
||||||
|
delete Internal.List;
|
||||||
|
break;
|
||||||
|
case Class::Object:
|
||||||
|
delete Internal.Map;
|
||||||
|
break;
|
||||||
|
case Class::String:
|
||||||
|
delete Internal.String;
|
||||||
|
break;
|
||||||
|
default:;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
JSON( T b, typename enable_if<is_same<T,bool>::value>::type* = 0 ) : Internal( b ), Type( Class::Boolean ){}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
JSON( T i, typename enable_if<is_integral<T>::value && !is_same<T,bool>::value>::type* = 0 ) : Internal( long(i) ), Type( Class::Integral ){}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
JSON( T f, typename enable_if<is_floating_point<T>::value>::type* = 0 ) : Internal( double(f) ), Type( Class::Floating ){}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
JSON( T s, typename enable_if<is_convertible<T,string>::value>::type* = 0 ) : Internal( string( s ) ), Type( Class::String ){}
|
||||||
|
|
||||||
|
JSON( std::nullptr_t ) : Internal(), Type( Class::Null ){}
|
||||||
|
|
||||||
|
static JSON Make( Class type ) {
|
||||||
|
return JSON(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
static JSON Load( const string & );
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void append( T arg ) {
|
||||||
|
SetType( Class::Array ); Internal.List->emplace_back( arg );
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename... U>
|
||||||
|
void append( T arg, U... args ) {
|
||||||
|
append( arg ); append( args... );
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
typename enable_if<is_same<T,bool>::value, JSON&>::type operator=( T b ) {
|
||||||
|
SetType( Class::Boolean ); Internal.Bool = b; return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
typename enable_if<is_integral<T>::value && !is_same<T,bool>::value, JSON&>::type operator=( T i ) {
|
||||||
|
SetType( Class::Integral ); Internal.Int = i; return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
typename enable_if<is_floating_point<T>::value, JSON&>::type operator=( T f ) {
|
||||||
|
SetType( Class::Floating ); Internal.Float = f; return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
typename enable_if<is_convertible<T,string>::value, JSON&>::type operator=( T s ) {
|
||||||
|
SetType( Class::String ); *Internal.String = string( s ); return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSON& operator[]( const string &key ) {
|
||||||
|
SetType( Class::Object ); return Internal.Map->operator[]( key );
|
||||||
|
}
|
||||||
|
|
||||||
|
JSON& operator[]( const size_t index ) {
|
||||||
|
SetType( Class::Array );
|
||||||
|
if( index >= Internal.List->size() ) Internal.List->resize( index + 1 );
|
||||||
|
return Internal.List->operator[]( index );
|
||||||
|
}
|
||||||
|
|
||||||
|
JSON &at( const string &key ) {
|
||||||
|
return operator[]( key );
|
||||||
|
}
|
||||||
|
|
||||||
|
const JSON &at( const string &key ) const {
|
||||||
|
return Internal.Map->at( key );
|
||||||
|
}
|
||||||
|
|
||||||
|
JSON &at( unsigned index ) {
|
||||||
|
return operator[]( index );
|
||||||
|
}
|
||||||
|
|
||||||
|
const JSON &at( unsigned index ) const {
|
||||||
|
return Internal.List->at( index );
|
||||||
|
}
|
||||||
|
|
||||||
|
int length() const {
|
||||||
|
if( Type == Class::Array )
|
||||||
|
return static_cast<int>(Internal.List->size());
|
||||||
|
else
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hasKey( const string &key ) const {
|
||||||
|
if( Type == Class::Object )
|
||||||
|
return Internal.Map->find( key ) != Internal.Map->end();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int size() const {
|
||||||
|
if( Type == Class::Object )
|
||||||
|
return static_cast<int>(Internal.Map->size());
|
||||||
|
else if( Type == Class::Array )
|
||||||
|
return static_cast<int>(Internal.List->size());
|
||||||
|
else
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Class JSONType() const { return Type; }
|
||||||
|
|
||||||
|
/// Functions for getting primitives from the JSON object.
|
||||||
|
bool IsNull() const { return Type == Class::Null; }
|
||||||
|
|
||||||
|
string ToString() const { bool b; return ToString( b ); }
|
||||||
|
string ToString( bool &ok ) const {
|
||||||
|
ok = (Type == Class::String);
|
||||||
|
return ok ? *Internal.String : string("");
|
||||||
|
}
|
||||||
|
|
||||||
|
double ToFloat() const { bool b; return ToFloat( b ); }
|
||||||
|
double ToFloat( bool &ok ) const {
|
||||||
|
ok = (Type == Class::Floating);
|
||||||
|
return ok ? Internal.Float : 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
long ToInt() const { bool b; return ToInt( b ); }
|
||||||
|
long ToInt( bool &ok ) const {
|
||||||
|
ok = (Type == Class::Integral);
|
||||||
|
return ok ? Internal.Int : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ToBool() const { bool b; return ToBool( b ); }
|
||||||
|
bool ToBool( bool &ok ) const {
|
||||||
|
ok = (Type == Class::Boolean);
|
||||||
|
return ok ? Internal.Bool : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSONWrapper<map<string,JSON>> ObjectRange() {
|
||||||
|
if( Type == Class::Object )
|
||||||
|
return JSONWrapper<map<string,JSON>>( Internal.Map );
|
||||||
|
return JSONWrapper<map<string,JSON>>( nullptr );
|
||||||
|
}
|
||||||
|
|
||||||
|
JSONWrapper<deque<JSON>> ArrayRange() {
|
||||||
|
if( Type == Class::Array )
|
||||||
|
return JSONWrapper<deque<JSON>>( Internal.List );
|
||||||
|
return JSONWrapper<deque<JSON>>( nullptr );
|
||||||
|
}
|
||||||
|
|
||||||
|
JSONConstWrapper<map<string,JSON>> ObjectRange() const {
|
||||||
|
if( Type == Class::Object )
|
||||||
|
return JSONConstWrapper<map<string,JSON>>( Internal.Map );
|
||||||
|
return JSONConstWrapper<map<string,JSON>>( nullptr );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
JSONConstWrapper<deque<JSON>> ArrayRange() const {
|
||||||
|
if( Type == Class::Array )
|
||||||
|
return JSONConstWrapper<deque<JSON>>( Internal.List );
|
||||||
|
return JSONConstWrapper<deque<JSON>>( nullptr );
|
||||||
|
}
|
||||||
|
|
||||||
|
string dump( int depth = 1, string tab = " ") const {
|
||||||
|
switch( Type ) {
|
||||||
|
case Class::Null:
|
||||||
|
return "null";
|
||||||
|
case Class::Object: {
|
||||||
|
string pad = "";
|
||||||
|
for( int i = 0; i < depth; ++i, pad += tab );
|
||||||
|
|
||||||
|
string s = "{\n";
|
||||||
|
bool skip = true;
|
||||||
|
for( auto &p : *Internal.Map ) {
|
||||||
|
if( !skip ) s += ",\n";
|
||||||
|
s += ( pad + "\"" + p.first + "\" : " + p.second.dump( depth + 1, tab ) );
|
||||||
|
skip = false;
|
||||||
|
}
|
||||||
|
s += ( "\n" + pad.erase( 0, 2 ) + "}" ) ;
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
case Class::Array: {
|
||||||
|
string s = "[";
|
||||||
|
bool skip = true;
|
||||||
|
for( auto &p : *Internal.List ) {
|
||||||
|
if( !skip ) s += ", ";
|
||||||
|
s += p.dump( depth + 1, tab );
|
||||||
|
skip = false;
|
||||||
|
}
|
||||||
|
s += "]";
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
case Class::String:
|
||||||
|
return "\"" + json_escape( *Internal.String ) + "\"";
|
||||||
|
case Class::Floating:
|
||||||
|
return std::to_string( Internal.Float );
|
||||||
|
case Class::Integral:
|
||||||
|
return std::to_string( Internal.Int );
|
||||||
|
case Class::Boolean:
|
||||||
|
return Internal.Bool ? "true" : "false";
|
||||||
|
}
|
||||||
|
|
||||||
|
throw std::runtime_error("Unhandled JSON type");
|
||||||
|
}
|
||||||
|
|
||||||
|
friend std::ostream& operator<<( std::ostream&, const JSON & );
|
||||||
|
|
||||||
|
private:
|
||||||
|
void SetType( Class type ) {
|
||||||
|
if( type == Type )
|
||||||
|
return;
|
||||||
|
|
||||||
|
switch( Type ) {
|
||||||
|
case Class::Object: delete Internal.Map; break;
|
||||||
|
case Class::Array: delete Internal.List; break;
|
||||||
|
case Class::String: delete Internal.String; break;
|
||||||
|
default:;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch( type ) {
|
||||||
|
case Class::Null: Internal.Map = nullptr; break;
|
||||||
|
case Class::Object: Internal.Map = new map<string,JSON>(); break;
|
||||||
|
case Class::Array: Internal.List = new deque<JSON>(); break;
|
||||||
|
case Class::String: Internal.String = new string(); break;
|
||||||
|
case Class::Floating: Internal.Float = 0.0; break;
|
||||||
|
case Class::Integral: Internal.Int = 0; break;
|
||||||
|
case Class::Boolean: Internal.Bool = false; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
Type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
Class Type;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline JSON Array() {
|
||||||
|
return JSON::Make( JSON::Class::Array );
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename... T>
|
||||||
|
inline JSON Array( T... args ) {
|
||||||
|
JSON arr = JSON::Make( JSON::Class::Array );
|
||||||
|
arr.append( args... );
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline JSON Object() {
|
||||||
|
return JSON::Make( JSON::Class::Object );
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::ostream& operator<<( std::ostream &os, const JSON &json ) {
|
||||||
|
os << json.dump();
|
||||||
|
return os;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
JSON parse_next( const string &, size_t & );
|
||||||
|
|
||||||
|
void consume_ws( const string &str, size_t &offset ) {
|
||||||
|
while( isspace( str[offset] ) ) ++offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSON parse_object( const string &str, size_t &offset ) {
|
||||||
|
JSON Object = JSON::Make( JSON::Class::Object );
|
||||||
|
|
||||||
|
++offset;
|
||||||
|
consume_ws( str, offset );
|
||||||
|
if( str[offset] == '}' ) {
|
||||||
|
++offset; return Object;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (;offset<str.size();) {
|
||||||
|
JSON Key = parse_next( str, offset );
|
||||||
|
consume_ws( str, offset );
|
||||||
|
if( str[offset] != ':' ) {
|
||||||
|
throw std::runtime_error(std::string("JSON ERROR: Object: Expected colon, found '") + str[offset] + "'\n");
|
||||||
|
}
|
||||||
|
consume_ws( str, ++offset );
|
||||||
|
JSON Value = parse_next( str, offset );
|
||||||
|
Object[Key.ToString()] = Value;
|
||||||
|
|
||||||
|
consume_ws( str, offset );
|
||||||
|
if( str[offset] == ',' ) {
|
||||||
|
++offset; continue;
|
||||||
|
}
|
||||||
|
else if( str[offset] == '}' ) {
|
||||||
|
++offset; break;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw std::runtime_error(std::string("JSON ERROR: Object: Expected comma, found '") + str[offset] + "'\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Object;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSON parse_array( const string &str, size_t &offset ) {
|
||||||
|
JSON Array = JSON::Make( JSON::Class::Array );
|
||||||
|
unsigned index = 0;
|
||||||
|
|
||||||
|
++offset;
|
||||||
|
consume_ws( str, offset );
|
||||||
|
if( str[offset] == ']' ) {
|
||||||
|
++offset; return Array;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (;offset < str.size();) {
|
||||||
|
Array[index++] = parse_next( str, offset );
|
||||||
|
consume_ws( str, offset );
|
||||||
|
|
||||||
|
if( str[offset] == ',' ) {
|
||||||
|
++offset; continue;
|
||||||
|
}
|
||||||
|
else if( str[offset] == ']' ) {
|
||||||
|
++offset; break;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw std::runtime_error(std::string("JSON ERROR: Array: Expected ',' or ']', found '") + str[offset] + "'\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Array;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSON parse_string( const string &str, size_t &offset ) {
|
||||||
|
string val;
|
||||||
|
for( char c = str[++offset]; c != '\"' ; c = str[++offset] ) {
|
||||||
|
if( c == '\\' ) {
|
||||||
|
switch( str[ ++offset ] ) {
|
||||||
|
case '\"': val += '\"'; break;
|
||||||
|
case '\\': val += '\\'; break;
|
||||||
|
case '/' : val += '/' ; break;
|
||||||
|
case 'b' : val += '\b'; break;
|
||||||
|
case 'f' : val += '\f'; break;
|
||||||
|
case 'n' : val += '\n'; break;
|
||||||
|
case 'r' : val += '\r'; break;
|
||||||
|
case 't' : val += '\t'; break;
|
||||||
|
case 'u' : {
|
||||||
|
val += "\\u" ;
|
||||||
|
for( unsigned i = 1; i <= 4; ++i ) {
|
||||||
|
c = str[offset+i];
|
||||||
|
if( (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F') )
|
||||||
|
val += c;
|
||||||
|
else {
|
||||||
|
throw std::runtime_error(std::string("JSON ERROR: String: Expected hex character in unicode escape, found '") + c + "'");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
offset += 4;
|
||||||
|
} break;
|
||||||
|
default : val += '\\'; break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
val += c;
|
||||||
|
}
|
||||||
|
++offset;
|
||||||
|
return JSON(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
JSON parse_number( const string &str, size_t &offset ) {
|
||||||
|
JSON Number;
|
||||||
|
string val, exp_str;
|
||||||
|
char c = '\0';
|
||||||
|
bool isDouble = false;
|
||||||
|
long exp = 0;
|
||||||
|
for (; offset < str.size() ;) {
|
||||||
|
c = str[offset++];
|
||||||
|
if( (c == '-') || (c >= '0' && c <= '9') )
|
||||||
|
val += c;
|
||||||
|
else if( c == '.' ) {
|
||||||
|
val += c;
|
||||||
|
isDouble = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if( offset < str.size() && (c == 'E' || c == 'e' )) {
|
||||||
|
c = str[ offset++ ];
|
||||||
|
if( c == '-' ) { exp_str += '-';}
|
||||||
|
else if( c == '+' ) { }
|
||||||
|
else --offset;
|
||||||
|
|
||||||
|
for (; offset < str.size() ;) {
|
||||||
|
c = str[ offset++ ];
|
||||||
|
if( c >= '0' && c <= '9' )
|
||||||
|
exp_str += c;
|
||||||
|
else if( !isspace( c ) && c != ',' && c != ']' && c != '}' ) {
|
||||||
|
throw std::runtime_error(std::string("JSON ERROR: Number: Expected a number for exponent, found '") + c + "'");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
exp = std::stol( exp_str );
|
||||||
|
}
|
||||||
|
else if( offset < str.size() && (!isspace( c ) && c != ',' && c != ']' && c != '}' )) {
|
||||||
|
throw std::runtime_error(std::string("JSON ERROR: Number: unexpected character '") + c + "'");
|
||||||
|
}
|
||||||
|
--offset;
|
||||||
|
|
||||||
|
if( isDouble )
|
||||||
|
Number = std::stod( val ) * std::pow( 10, exp );
|
||||||
|
else {
|
||||||
|
if( !exp_str.empty() )
|
||||||
|
Number = std::stol( val ) * std::pow( 10, exp );
|
||||||
|
else
|
||||||
|
Number = std::stol( val );
|
||||||
|
}
|
||||||
|
return Number;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSON parse_bool( const string &str, size_t &offset ) {
|
||||||
|
JSON Bool;
|
||||||
|
if( str.substr( offset, 4 ) == "true" ) {
|
||||||
|
offset += 4;
|
||||||
|
Bool = true;
|
||||||
|
} else if( str.substr( offset, 5 ) == "false" ) {
|
||||||
|
offset += 5;
|
||||||
|
Bool = false;
|
||||||
|
} else {
|
||||||
|
throw std::runtime_error(std::string("JSON ERROR: Bool: Expected 'true' or 'false', found '") + str.substr( offset, 5 ) + "'");
|
||||||
|
}
|
||||||
|
return Bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSON parse_null( const string &str, size_t &offset ) {
|
||||||
|
if( str.substr( offset, 4 ) != "null" ) {
|
||||||
|
throw std::runtime_error(std::string("JSON ERROR: Null: Expected 'null', found '") + str.substr( offset, 4 ) + "'");
|
||||||
|
}
|
||||||
|
offset += 4;
|
||||||
|
return JSON();
|
||||||
|
}
|
||||||
|
|
||||||
|
JSON parse_next( const string &str, size_t &offset ) {
|
||||||
|
char value;
|
||||||
|
consume_ws( str, offset );
|
||||||
|
value = str[offset];
|
||||||
|
switch( value ) {
|
||||||
|
case '[' : return parse_array( str, offset );
|
||||||
|
case '{' : return parse_object( str, offset );
|
||||||
|
case '\"': return parse_string( str, offset );
|
||||||
|
case 't' :
|
||||||
|
case 'f' : return parse_bool( str, offset );
|
||||||
|
case 'n' : return parse_null( str, offset );
|
||||||
|
default : if( ( value <= '9' && value >= '0' ) || value == '-' )
|
||||||
|
return parse_number( str, offset );
|
||||||
|
}
|
||||||
|
throw std::runtime_error(std::string("JSON ERROR: Parse: Unexpected starting character '") + value + "'");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline JSON JSON::Load( const string &str ) {
|
||||||
|
size_t offset = 0;
|
||||||
|
return parse_next( str, offset );
|
||||||
|
}
|
||||||
|
|
||||||
|
} // End Namespace json
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
158
include/chaiscript/utility/json_wrap.hpp
Normal file
158
include/chaiscript/utility/json_wrap.hpp
Normal file
@@ -0,0 +1,158 @@
|
|||||||
|
#ifndef CHAISCRIPT_SIMPLEJSON_WRAP_HPP
|
||||||
|
#define CHAISCRIPT_SIMPLEJSON_WRAP_HPP
|
||||||
|
|
||||||
|
#include "json.hpp"
|
||||||
|
|
||||||
|
namespace chaiscript
|
||||||
|
{
|
||||||
|
class json_wrap
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
static ModulePtr library(ModulePtr m = std::make_shared<Module>())
|
||||||
|
{
|
||||||
|
|
||||||
|
m->add(chaiscript::fun([](const std::string &t_str) { return from_json(t_str); }), "from_json");
|
||||||
|
m->add(chaiscript::fun(&json_wrap::to_json), "to_json");
|
||||||
|
|
||||||
|
return m;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
static Boxed_Value from_json(const json::JSON &t_json)
|
||||||
|
{
|
||||||
|
switch( t_json.JSONType() ) {
|
||||||
|
case json::JSON::Class::Null:
|
||||||
|
return Boxed_Value();
|
||||||
|
case json::JSON::Class::Object:
|
||||||
|
{
|
||||||
|
std::map<std::string, Boxed_Value> m;
|
||||||
|
|
||||||
|
for (const auto &p : t_json.ObjectRange())
|
||||||
|
{
|
||||||
|
m.insert(std::make_pair(p.first, from_json(p.second)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return Boxed_Value(m);
|
||||||
|
}
|
||||||
|
case json::JSON::Class::Array:
|
||||||
|
{
|
||||||
|
std::vector<Boxed_Value> vec;
|
||||||
|
|
||||||
|
for (const auto &p : t_json.ArrayRange())
|
||||||
|
{
|
||||||
|
vec.emplace_back(from_json(p));
|
||||||
|
}
|
||||||
|
|
||||||
|
return Boxed_Value(vec);
|
||||||
|
}
|
||||||
|
case json::JSON::Class::String:
|
||||||
|
return Boxed_Value(t_json.ToString());
|
||||||
|
case json::JSON::Class::Floating:
|
||||||
|
return Boxed_Value(t_json.ToFloat());
|
||||||
|
case json::JSON::Class::Integral:
|
||||||
|
return Boxed_Value(t_json.ToInt());
|
||||||
|
case json::JSON::Class::Boolean:
|
||||||
|
return Boxed_Value(t_json.ToBool());
|
||||||
|
}
|
||||||
|
|
||||||
|
throw std::runtime_error("Unknown JSON type");
|
||||||
|
}
|
||||||
|
|
||||||
|
static Boxed_Value from_json(const std::string &t_json)
|
||||||
|
{
|
||||||
|
return from_json( json::JSON::Load(t_json) );
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string to_json(const Boxed_Value &t_bv)
|
||||||
|
{
|
||||||
|
return to_json_object(t_bv).dump();
|
||||||
|
}
|
||||||
|
|
||||||
|
static json::JSON to_json_object(const Boxed_Value &t_bv)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
const std::map<std::string, Boxed_Value> m = chaiscript::boxed_cast<const std::map<std::string, Boxed_Value> &>(t_bv);
|
||||||
|
|
||||||
|
json::JSON obj;
|
||||||
|
for (const auto &o : m)
|
||||||
|
{
|
||||||
|
obj[o.first] = to_json_object(o.second);
|
||||||
|
}
|
||||||
|
return obj;
|
||||||
|
} catch (const chaiscript::exception::bad_boxed_cast &) {
|
||||||
|
// not a map
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const std::vector<Boxed_Value> v = chaiscript::boxed_cast<const std::vector<Boxed_Value> &>(t_bv);
|
||||||
|
|
||||||
|
json::JSON obj;
|
||||||
|
for (size_t i = 0; i < v.size(); ++i)
|
||||||
|
{
|
||||||
|
obj[i] = to_json_object(v[i]);
|
||||||
|
}
|
||||||
|
return obj;
|
||||||
|
} catch (const chaiscript::exception::bad_boxed_cast &) {
|
||||||
|
// not a vector
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
try {
|
||||||
|
Boxed_Number bn(t_bv);
|
||||||
|
json::JSON obj;
|
||||||
|
if (Boxed_Number::is_floating_point(t_bv))
|
||||||
|
{
|
||||||
|
obj = bn.get_as<double>();
|
||||||
|
} else {
|
||||||
|
obj = bn.get_as<long>();
|
||||||
|
}
|
||||||
|
return obj;
|
||||||
|
} catch (const chaiscript::detail::exception::bad_any_cast &) {
|
||||||
|
// not a number
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
bool b = boxed_cast<bool>(t_bv);
|
||||||
|
json::JSON obj;
|
||||||
|
obj = b;
|
||||||
|
return obj;
|
||||||
|
} catch (const chaiscript::exception::bad_boxed_cast &) {
|
||||||
|
// not a bool
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
std::string s = boxed_cast<std::string>(t_bv);
|
||||||
|
json::JSON obj;
|
||||||
|
obj = s;
|
||||||
|
return obj;
|
||||||
|
} catch (const chaiscript::exception::bad_boxed_cast &) {
|
||||||
|
// not a string
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
try {
|
||||||
|
const chaiscript::dispatch::Dynamic_Object &o = boxed_cast<const dispatch::Dynamic_Object &>(t_bv);
|
||||||
|
|
||||||
|
json::JSON obj;
|
||||||
|
for (const auto &attr : o.get_attrs())
|
||||||
|
{
|
||||||
|
obj[attr.first] = to_json_object(attr.second);
|
||||||
|
}
|
||||||
|
return obj;
|
||||||
|
} catch (const chaiscript::exception::bad_boxed_cast &) {
|
||||||
|
// not a dynamic object
|
||||||
|
}
|
||||||
|
|
||||||
|
throw std::runtime_error("Unknown object type to convert to JSON");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -8,12 +8,14 @@
|
|||||||
#define CHAISCRIPT_UTILITY_UTILITY_HPP_
|
#define CHAISCRIPT_UTILITY_UTILITY_HPP_
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <type_traits>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "../chaiscript.hpp"
|
#include "../chaiscript.hpp"
|
||||||
#include "../dispatchkit/proxy_functions.hpp"
|
#include "../dispatchkit/proxy_functions.hpp"
|
||||||
#include "../dispatchkit/type_info.hpp"
|
#include "../dispatchkit/type_info.hpp"
|
||||||
|
#include "../dispatchkit/operators.hpp"
|
||||||
|
|
||||||
|
|
||||||
namespace chaiscript
|
namespace chaiscript
|
||||||
@@ -62,6 +64,32 @@ namespace chaiscript
|
|||||||
t_module.add(fun.first, fun.second);
|
t_module.add(fun.first, fun.second);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename Enum, typename ModuleType>
|
||||||
|
typename std::enable_if<std::is_enum<Enum>::value, void>::type
|
||||||
|
add_class(ModuleType &t_module,
|
||||||
|
const std::string &t_class_name,
|
||||||
|
const std::vector<std::pair<typename std::underlying_type<Enum>::type, std::string>> &t_constants)
|
||||||
|
{
|
||||||
|
t_module.add(chaiscript::user_type<Enum>(), t_class_name);
|
||||||
|
|
||||||
|
t_module.add(chaiscript::constructor<Enum ()>(), t_class_name);
|
||||||
|
t_module.add(chaiscript::constructor<Enum (const Enum &)>(), t_class_name);
|
||||||
|
|
||||||
|
t_module.add([](){
|
||||||
|
// add some comparison and assignment operators
|
||||||
|
using namespace chaiscript::bootstrap::operators;
|
||||||
|
return assign<Enum>(not_equal<Enum>(equal<Enum>()));
|
||||||
|
}());
|
||||||
|
|
||||||
|
t_module.add(chaiscript::fun([](const Enum &e, const typename std::underlying_type<Enum>::type &i) { return e == i; }), "==");
|
||||||
|
t_module.add(chaiscript::fun([](const typename std::underlying_type<Enum>::type &i, const Enum &e) { return i == e; }), "==");
|
||||||
|
|
||||||
|
for (const auto &constant : t_constants)
|
||||||
|
{
|
||||||
|
t_module.add_global_const(chaiscript::const_var(Enum(constant.first)), constant.second);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
103
samples/factory.cpp
Normal file
103
samples/factory.cpp
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
#include <chaiscript/chaiscript.hpp>
|
||||||
|
#include <chaiscript/chaiscript_stdlib.hpp>
|
||||||
|
|
||||||
|
class Entity
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
int width;
|
||||||
|
int height;
|
||||||
|
int x;
|
||||||
|
int y;
|
||||||
|
std::string name;
|
||||||
|
|
||||||
|
std::function<void (Entity &)> updater;
|
||||||
|
|
||||||
|
Entity(const int t_width, const int t_height, const int t_x, const int t_y, std::string t_name)
|
||||||
|
: width(t_width), height(t_height), x(t_x), y(t_y), name(std::move(t_name))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class Factory
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// we may as well pass the parameters for the entity to the factory method, this does the initialization
|
||||||
|
// in one step.
|
||||||
|
Entity *make_entity(const int width, const int height, const int x, const int y, const std::string &name)
|
||||||
|
{
|
||||||
|
auto entity = entities.insert({name, Entity{width, height, x, y, name}});
|
||||||
|
return &(entity.first->second);
|
||||||
|
}
|
||||||
|
|
||||||
|
Entity *get_entity(const std::string &name)
|
||||||
|
{
|
||||||
|
return &entities.at(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// loop over all entities and all their updater function (if it exists)
|
||||||
|
void update_entities()
|
||||||
|
{
|
||||||
|
for (auto &entity : entities)
|
||||||
|
{
|
||||||
|
if (entity.second.updater) {
|
||||||
|
entity.second.updater(entity.second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
// we cannot store the entities in a std::vector if we want to return a pointer to them,
|
||||||
|
// because a vector automatically resizing itself can invalidate the pointer that was returned.
|
||||||
|
// using a map guarantees that the memory assigned to the entity will never change, plus
|
||||||
|
// lets us easily look up an entity by name
|
||||||
|
std::map<std::string, Entity> entities;
|
||||||
|
};
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
chaiscript::ChaiScript chai(chaiscript::Std_Lib::library());
|
||||||
|
|
||||||
|
chai.add(chaiscript::fun(&Entity::width), "width");
|
||||||
|
chai.add(chaiscript::fun(&Entity::height), "height");
|
||||||
|
chai.add(chaiscript::fun(&Entity::x), "x");
|
||||||
|
chai.add(chaiscript::fun(&Entity::y), "y");
|
||||||
|
chai.add(chaiscript::fun(&Entity::name), "name");
|
||||||
|
chai.add(chaiscript::fun(&Entity::updater), "updater");
|
||||||
|
chai.add(chaiscript::user_type<Entity>(), "Entity"); // this isn't strictly necessary but makes error messages nicer
|
||||||
|
|
||||||
|
chai.add(chaiscript::fun(&Factory::make_entity), "make_entity");
|
||||||
|
chai.add(chaiscript::fun(&Factory::get_entity), "get_entity");
|
||||||
|
chai.add(chaiscript::fun(&Factory::update_entities), "update_entities");
|
||||||
|
chai.add(chaiscript::user_type<Factory>(), "Factory"); // this isn't strictly necessary but makes error messages nicer
|
||||||
|
|
||||||
|
|
||||||
|
Factory f;
|
||||||
|
chai.add(chaiscript::var(&f), "f");
|
||||||
|
|
||||||
|
std::string script = R""(
|
||||||
|
f.make_entity(10,10,1,1,"entity1").updater = fun(e){ e.x += 1; e.y += 1 };
|
||||||
|
f.make_entity(10,10,10,10,"entity2").updater = fun(e){ e.x += 2; e.y += 2 };
|
||||||
|
f.make_entity(10,10,20,20,"entity3");
|
||||||
|
|
||||||
|
print(f.get_entity("entity1").x == 1)
|
||||||
|
print(f.get_entity("entity2").x == 10)
|
||||||
|
print(f.get_entity("entity3").x == 20)
|
||||||
|
|
||||||
|
f.update_entities(); // this runs the function objects we set in the previous lines
|
||||||
|
// we should now see the updated values
|
||||||
|
|
||||||
|
print(f.get_entity("entity1").x == 2)
|
||||||
|
print(f.get_entity("entity2").x == 12)
|
||||||
|
print(f.get_entity("entity3").x == 20) // this one has no updater, so it stays the same
|
||||||
|
)"";
|
||||||
|
|
||||||
|
|
||||||
|
chai.eval(script);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
32
samples/test_num_exceptions.cpp
Normal file
32
samples/test_num_exceptions.cpp
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
#include <chaiscript/chaiscript.hpp>
|
||||||
|
#include <chaiscript/chaiscript_stdlib.hpp>
|
||||||
|
#include <chaiscript/dispatchkit/bootstrap_stl.hpp>
|
||||||
|
#include <chaiscript/dispatchkit/function_call.hpp>
|
||||||
|
|
||||||
|
int main( int /*argc*/ , char * /*argv*/[] )
|
||||||
|
{
|
||||||
|
chaiscript::ChaiScript ch( chaiscript::Std_Lib::library( ) );
|
||||||
|
|
||||||
|
static const char script[ ] =
|
||||||
|
R""(
|
||||||
|
|
||||||
|
class Rectangle
|
||||||
|
{
|
||||||
|
def Rectangle() { }
|
||||||
|
}
|
||||||
|
|
||||||
|
var rect = Rectangle( );
|
||||||
|
|
||||||
|
)"";
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ch.eval( script );
|
||||||
|
}
|
||||||
|
catch ( const std::exception &e )
|
||||||
|
{
|
||||||
|
printf( " >>> Exception thrown: %s \n" , e.what( ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
12
unittests/bool_comparisons.chai
Normal file
12
unittests/bool_comparisons.chai
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
|
||||||
|
assert_true(true == true)
|
||||||
|
assert_false(true == false)
|
||||||
|
assert_true(true != false)
|
||||||
|
assert_true(false != true)
|
||||||
|
assert_true(false || true)
|
||||||
|
assert_true(true || false)
|
||||||
|
assert_false(true && false)
|
||||||
|
assert_false(false && true)
|
||||||
|
assert_true(!false)
|
||||||
|
assert_false(!true)
|
||||||
|
|
||||||
@@ -13,9 +13,9 @@ bool run_test_type_conversion(const Boxed_Value &bv, bool expectedpass)
|
|||||||
try {
|
try {
|
||||||
To ret = chaiscript::boxed_cast<To>(bv);
|
To ret = chaiscript::boxed_cast<To>(bv);
|
||||||
use(ret);
|
use(ret);
|
||||||
} catch (const chaiscript::exception::bad_boxed_cast &/*e*/) {
|
} catch (const chaiscript::exception::bad_boxed_cast &e) {
|
||||||
if (expectedpass) {
|
if (expectedpass) {
|
||||||
// std::cerr << "Failure in run_test_type_conversion: " << e.what() << '\n';
|
std::cerr << "Failure in run_test_type_conversion: " << e.what() << '\n';
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
// caught in other cpp files if chaiscript causes them
|
// caught in other cpp files if chaiscript causes them
|
||||||
|
|
||||||
#include <chaiscript/utility/utility.hpp>
|
#include <chaiscript/utility/utility.hpp>
|
||||||
|
#include <chaiscript/dispatchkit/bootstrap_stl.hpp>
|
||||||
|
|
||||||
#ifdef CHAISCRIPT_MSVC
|
#ifdef CHAISCRIPT_MSVC
|
||||||
#pragma warning(push)
|
#pragma warning(push)
|
||||||
@@ -518,6 +519,65 @@ TEST_CASE("Utility_Test utility class wrapper")
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
enum Utility_Test_Numbers
|
||||||
|
{
|
||||||
|
ONE,
|
||||||
|
TWO,
|
||||||
|
THREE
|
||||||
|
};
|
||||||
|
|
||||||
|
void do_something_with_enum_vector(const std::vector<Utility_Test_Numbers> &v)
|
||||||
|
{
|
||||||
|
CHECK(v.size() == 3);
|
||||||
|
CHECK(v[0] == ONE);
|
||||||
|
CHECK(v[1] == THREE);
|
||||||
|
CHECK(v[2] == TWO);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Utility_Test utility class wrapper for enum")
|
||||||
|
{
|
||||||
|
|
||||||
|
chaiscript::ModulePtr m = chaiscript::ModulePtr(new chaiscript::Module());
|
||||||
|
|
||||||
|
using namespace chaiscript;
|
||||||
|
|
||||||
|
chaiscript::utility::add_class<Utility_Test_Numbers>(*m,
|
||||||
|
"Utility_Test_Numbers",
|
||||||
|
{ { ONE, "ONE" },
|
||||||
|
{ TWO, "TWO" },
|
||||||
|
{ THREE, "THREE" }
|
||||||
|
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
chaiscript::ChaiScript chai;
|
||||||
|
chai.add(m);
|
||||||
|
|
||||||
|
CHECK(chai.eval<Utility_Test_Numbers>("ONE ") == 0);
|
||||||
|
CHECK(chai.eval<Utility_Test_Numbers>("TWO ") == 1);
|
||||||
|
CHECK(chai.eval<Utility_Test_Numbers>("THREE ") == 2);
|
||||||
|
|
||||||
|
CHECK(chai.eval<bool>("ONE == 0"));
|
||||||
|
|
||||||
|
chai.add(chaiscript::fun(&do_something_with_enum_vector), "do_something_with_enum_vector");
|
||||||
|
chai.add(chaiscript::vector_conversion<std::vector<Utility_Test_Numbers>>());
|
||||||
|
CHECK_NOTHROW(chai.eval("var a = [ONE, TWO, THREE]"));
|
||||||
|
CHECK_NOTHROW(chai.eval("do_something_with_enum_vector([ONE, THREE, TWO])"));
|
||||||
|
CHECK_NOTHROW(chai.eval("[ONE]"));
|
||||||
|
|
||||||
|
const auto v = chai.eval<std::vector<Utility_Test_Numbers>>("a");
|
||||||
|
CHECK(v.size() == 3);
|
||||||
|
CHECK(v.at(1) == TWO);
|
||||||
|
|
||||||
|
CHECK(chai.eval<bool>("ONE == ONE"));
|
||||||
|
CHECK(chai.eval<bool>("ONE != TWO"));
|
||||||
|
CHECK_NOTHROW(chai.eval("var o = ONE; o = TWO"));
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
////// Object copy count test
|
////// Object copy count test
|
||||||
|
|
||||||
class Object_Copy_Count_Test
|
class Object_Copy_Count_Test
|
||||||
@@ -743,3 +803,113 @@ TEST_CASE("Test Derived->Base with non-polymorphic classes")
|
|||||||
chai.add(chaiscript::fun(&myfunction), "myfunction");
|
chai.add(chaiscript::fun(&myfunction), "myfunction");
|
||||||
CHECK(chai.eval<int>("myfunction(d)") == 2);
|
CHECK(chai.eval<int>("myfunction(d)") == 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct TestCppVariableScope
|
||||||
|
{
|
||||||
|
void print()
|
||||||
|
{
|
||||||
|
std::cout << "Printed" << std::endl;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST_CASE("Variable Scope When Calling From C++")
|
||||||
|
{
|
||||||
|
chaiscript::ChaiScript chai;
|
||||||
|
chai.add(chaiscript::user_type<TestCppVariableScope>(), "Test");
|
||||||
|
chai.add(chaiscript::constructor<TestCppVariableScope()>(), "Test");
|
||||||
|
chai.add(chaiscript::fun(&TestCppVariableScope::print), "print");
|
||||||
|
chai.eval(R"(var t := Test();
|
||||||
|
|
||||||
|
def func()
|
||||||
|
{
|
||||||
|
t.print();
|
||||||
|
}
|
||||||
|
|
||||||
|
)");
|
||||||
|
|
||||||
|
CHECK_THROWS(chai.eval("func()"));
|
||||||
|
|
||||||
|
chai.eval("dump_object(t)");
|
||||||
|
|
||||||
|
auto func = chai.eval<std::function<void()>>("func");
|
||||||
|
CHECK_THROWS(func());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Variable Scope When Calling From C++ 2")
|
||||||
|
{
|
||||||
|
chaiscript::ChaiScript chai;
|
||||||
|
chai.eval("var obj = 2;");
|
||||||
|
auto func = chai.eval<std::function<void()>>("fun(){ return obj; }");
|
||||||
|
CHECK_THROWS(func());
|
||||||
|
}
|
||||||
|
|
||||||
|
void ulonglong(unsigned long long i) {
|
||||||
|
std::cout << i << '\n';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void longlong(long long i) {
|
||||||
|
std::cout << i << '\n';
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Test long long dispatch")
|
||||||
|
{
|
||||||
|
chaiscript::ChaiScript chai;
|
||||||
|
chai.add(chaiscript::fun(&longlong), "longlong");
|
||||||
|
chai.add(chaiscript::fun(&ulonglong), "ulonglong");
|
||||||
|
chai.eval("longlong(15)");
|
||||||
|
chai.eval("ulonglong(15)");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct Returned_Converted_Config
|
||||||
|
{
|
||||||
|
int num_iterations;
|
||||||
|
int something_else;
|
||||||
|
std::string a_string;
|
||||||
|
std::function<int (const std::string &)> a_function;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
TEST_CASE("Return of converted type from script")
|
||||||
|
{
|
||||||
|
chaiscript::ChaiScript chai;
|
||||||
|
|
||||||
|
chai.add(chaiscript::constructor<Returned_Converted_Config ()>(), "Returned_Converted_Config");
|
||||||
|
chai.add(chaiscript::fun(&Returned_Converted_Config::num_iterations), "num_iterations");
|
||||||
|
chai.add(chaiscript::fun(&Returned_Converted_Config::something_else), "something_else");
|
||||||
|
chai.add(chaiscript::fun(&Returned_Converted_Config::a_string), "a_string");
|
||||||
|
chai.add(chaiscript::fun(&Returned_Converted_Config::a_function), "a_function");
|
||||||
|
chai.add(chaiscript::vector_conversion<std::vector<Returned_Converted_Config>>());
|
||||||
|
|
||||||
|
auto c = chai.eval<std::vector<Returned_Converted_Config>>(R"(
|
||||||
|
var c = Returned_Converted_Config();
|
||||||
|
|
||||||
|
c.num_iterations = 5;
|
||||||
|
c.something_else = c.num_iterations * 2;
|
||||||
|
c.a_string = "string";
|
||||||
|
c.a_function = fun(s) { s.size(); }
|
||||||
|
|
||||||
|
print("making vector");
|
||||||
|
var v = [];
|
||||||
|
print("adding config item");
|
||||||
|
v.push_back_ref(c);
|
||||||
|
print("returning vector");
|
||||||
|
v;
|
||||||
|
|
||||||
|
)");
|
||||||
|
|
||||||
|
|
||||||
|
std::cout << typeid(decltype(c)).name() << std::endl;
|
||||||
|
|
||||||
|
std::cout << "Info: " << c.size() << " " << &c[0] << std::endl;
|
||||||
|
|
||||||
|
std::cout << "num_iterations " << c[0].num_iterations << '\n'
|
||||||
|
<< "something_else " << c[0].something_else << '\n'
|
||||||
|
<< "a_string " << c[0].a_string << '\n'
|
||||||
|
<< "a_function " << c[0].a_function("bob") << '\n';
|
||||||
|
|
||||||
|
chai.add(chaiscript::user_type<Returned_Converted_Config>(), "Returned_Converted_Config");
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
14
unittests/dynamic_object_dynamic_attrs_explicit.chai
Normal file
14
unittests/dynamic_object_dynamic_attrs_explicit.chai
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
|
||||||
|
class MyClass {
|
||||||
|
def MyClass()
|
||||||
|
{
|
||||||
|
this.set_explicit(true);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var o = MyClass();
|
||||||
|
|
||||||
|
assert_true(o.is_explicit());
|
||||||
|
|
||||||
|
assert_throws("error", fun[o](){o.x = 2})
|
||||||
|
|
||||||
Binary file not shown.
7
unittests/hex_escapes.chai
Normal file
7
unittests/hex_escapes.chai
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
|
||||||
|
assert_equal("\x39", "9")
|
||||||
|
assert_equal("\x39ec", "9ec")
|
||||||
|
assert_equal("\x39g", "9g")
|
||||||
|
assert_equal("b\x39g", "b9g")
|
||||||
|
assert_equal("\x39\x38g", "98g")
|
||||||
|
|
||||||
@@ -5,9 +5,10 @@
|
|||||||
template<typename T>
|
template<typename T>
|
||||||
bool test_literal(T val, const std::string &str)
|
bool test_literal(T val, const std::string &str)
|
||||||
{
|
{
|
||||||
|
std::cout << "Comparing : " << val;
|
||||||
chaiscript::ChaiScript chai;
|
chaiscript::ChaiScript chai;
|
||||||
T val2 = chai.eval<T>(str);
|
T val2 = chai.eval<T>(str);
|
||||||
std::cout << "Comparing : " << val << " " << val2 << '\n';
|
std::cout << " " << val2 << '\n';
|
||||||
return val == val2;
|
return val == val2;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,6 +75,39 @@ int main()
|
|||||||
&& TEST_LITERAL(177777777777777777)
|
&& TEST_LITERAL(177777777777777777)
|
||||||
&& TEST_LITERAL(1777777777777777777)
|
&& TEST_LITERAL(1777777777777777777)
|
||||||
|
|
||||||
|
&& test_literal(0xF, "0b1111")
|
||||||
|
&& test_literal(0xFF, "0b11111111")
|
||||||
|
&& test_literal(0xFFF, "0b111111111111")
|
||||||
|
&& test_literal(0xFFFF, "0b1111111111111111")
|
||||||
|
&& test_literal(0xFFFFF, "0b11111111111111111111")
|
||||||
|
&& test_literal(0xFFFFFF, "0b111111111111111111111111")
|
||||||
|
&& test_literal(0xFFFFFFF, "0b1111111111111111111111111111")
|
||||||
|
&& test_literal(0xFFFFFFFF, "0b11111111111111111111111111111111")
|
||||||
|
&& test_literal(0xFFFFFFFFF, "0b111111111111111111111111111111111111")
|
||||||
|
&& test_literal(0xFFFFFFFFFF, "0b1111111111111111111111111111111111111111")
|
||||||
|
&& test_literal(0xFFFFFFFFFFF, "0b11111111111111111111111111111111111111111111")
|
||||||
|
&& test_literal(0xFFFFFFFFFFFF, "0b111111111111111111111111111111111111111111111111")
|
||||||
|
&& test_literal(0xFFFFFFFFFFFFF, "0b1111111111111111111111111111111111111111111111111111")
|
||||||
|
&& test_literal(0xFFFFFFFFFFFFFF, "0b11111111111111111111111111111111111111111111111111111111")
|
||||||
|
&& test_literal(0xFFFFFFFFFFFFFFF, "0b111111111111111111111111111111111111111111111111111111111111")
|
||||||
|
&& test_literal(0xFFFFFFFFFFFFFFFF, "0b1111111111111111111111111111111111111111111111111111111111111111")
|
||||||
|
|
||||||
|
&& test_literal(0x7, "0b111")
|
||||||
|
&& test_literal(0x7F, "0b1111111")
|
||||||
|
&& test_literal(0x7FF, "0b11111111111")
|
||||||
|
&& test_literal(0x7FFF, "0b111111111111111")
|
||||||
|
&& test_literal(0x7FFFF, "0b1111111111111111111")
|
||||||
|
&& test_literal(0x7FFFFF, "0b11111111111111111111111")
|
||||||
|
&& test_literal(0x7FFFFFF, "0b111111111111111111111111111")
|
||||||
|
&& test_literal(0x7FFFFFFF, "0b1111111111111111111111111111111")
|
||||||
|
&& test_literal(0x7FFFFFFFF, "0b11111111111111111111111111111111111")
|
||||||
|
&& test_literal(0x7FFFFFFFFF, "0b111111111111111111111111111111111111111")
|
||||||
|
&& test_literal(0x7FFFFFFFFFF, "0b1111111111111111111111111111111111111111111")
|
||||||
|
&& test_literal(0x7FFFFFFFFFFF, "0b11111111111111111111111111111111111111111111111")
|
||||||
|
&& test_literal(0x7FFFFFFFFFFFF, "0b111111111111111111111111111111111111111111111111111")
|
||||||
|
&& test_literal(0x7FFFFFFFFFFFFF, "0b1111111111111111111111111111111111111111111111111111111")
|
||||||
|
&& test_literal(0x7FFFFFFFFFFFFFF, "0b11111111111111111111111111111111111111111111111111111111111")
|
||||||
|
&& test_literal(0x7FFFFFFFFFFFFFFF, "0b111111111111111111111111111111111111111111111111111111111111111")
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
|
|||||||
3
unittests/json_1.chai
Normal file
3
unittests/json_1.chai
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
|
||||||
|
|
||||||
|
assert_true(from_json("null").is_var_null())
|
||||||
1
unittests/json_10.chai
Normal file
1
unittests/json_10.chai
Normal file
@@ -0,0 +1 @@
|
|||||||
|
assert_equal(from_json("\"This is a\\n\\nMultiline string\""), "This is a\n\nMultiline string")
|
||||||
14
unittests/json_11.chai
Normal file
14
unittests/json_11.chai
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
assert_equal(from_json(
|
||||||
|
"{\n" +
|
||||||
|
" \"T1\" : \"Value With a Quote : \\\"\",\n" +
|
||||||
|
" \"T2\" : \"Value With a Rev Solidus : \\/\",\n" +
|
||||||
|
" \"T3\" : \"Value with a Solidus : \\\\\",\n" +
|
||||||
|
" \"T4\" : \"Value with a Backspace : \\b\",\n" +
|
||||||
|
" \"T5\" : \"Value with a Formfeed : \\f\",\n" +
|
||||||
|
" \"T6\" : \"Value with a Newline : \\n\",\n" +
|
||||||
|
" \"T7\" : \"Value with a Carriage Return : \\r\",\n" +
|
||||||
|
" \"T8\" : \"Value with a Horizontal Tab : \\t\"\n" +
|
||||||
|
"}"), [ "T1" : "Value With a Quote : \"", "T2" : "Value With a Rev Solidus : /", "T3" : "Value with a Solidus : \\", "T4" : "Value with a Backspace : \b", "T5" : "Value with a Formfeed : \f", "T6" : "Value with a Newline : \n", "T7" : "Value with a Carriage Return : \r", "T8" : "Value with a Horizontal Tab : \t" ]);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
1
unittests/json_12.chai
Normal file
1
unittests/json_12.chai
Normal file
@@ -0,0 +1 @@
|
|||||||
|
assert_equal(from_json("\"\""), "")
|
||||||
1
unittests/json_13.chai
Normal file
1
unittests/json_13.chai
Normal file
@@ -0,0 +1 @@
|
|||||||
|
assert_equal(from_json("1.20E+2"), 1.20e2)
|
||||||
3
unittests/json_2.chai
Normal file
3
unittests/json_2.chai
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
|
||||||
|
assert_true(from_json("true"))
|
||||||
|
|
||||||
1
unittests/json_3.chai
Normal file
1
unittests/json_3.chai
Normal file
@@ -0,0 +1 @@
|
|||||||
|
assert_equal(from_json("100"), 100)
|
||||||
1
unittests/json_4.chai
Normal file
1
unittests/json_4.chai
Normal file
@@ -0,0 +1 @@
|
|||||||
|
assert_equal(from_json("1.234"), 1.234)
|
||||||
1
unittests/json_5.chai
Normal file
1
unittests/json_5.chai
Normal file
@@ -0,0 +1 @@
|
|||||||
|
assert_equal(from_json("\"StringTest\""), "StringTest")
|
||||||
1
unittests/json_6.chai
Normal file
1
unittests/json_6.chai
Normal file
@@ -0,0 +1 @@
|
|||||||
|
assert_equal(from_json("{}"), Map())
|
||||||
4
unittests/json_7.chai
Normal file
4
unittests/json_7.chai
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
assert_equal(from_json("\n" +
|
||||||
|
"{\n" +
|
||||||
|
" \"Key\" : \"Value\"\n" +
|
||||||
|
"}\n"), ["Key":"Value"])
|
||||||
1
unittests/json_8.chai
Normal file
1
unittests/json_8.chai
Normal file
@@ -0,0 +1 @@
|
|||||||
|
assert_equal(from_json("[]"), [])
|
||||||
2
unittests/json_9.chai
Normal file
2
unittests/json_9.chai
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
assert_equal(from_json("[1,2,3]"), [1,2,3])
|
||||||
|
|
||||||
6
unittests/json_roundtrip.chai
Normal file
6
unittests/json_roundtrip.chai
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
|
||||||
|
var m = ["a" : 1, "b" : [ 1, 2, 3 ], "c" : [1, "a string", ["d" : 15.4]]]
|
||||||
|
|
||||||
|
assert_equal(from_json(to_json(m)), m)
|
||||||
|
|
||||||
|
|
||||||
@@ -6,3 +6,9 @@ x.push_back("A")
|
|||||||
|
|
||||||
assert_equal(3, x.front());
|
assert_equal(3, x.front());
|
||||||
assert_equal("A", x.back());
|
assert_equal("A", x.back());
|
||||||
|
|
||||||
|
|
||||||
|
// push_back newly constructed return value that's non-copyable
|
||||||
|
x.push_back(async(fun(){}))
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -6,3 +6,8 @@ x.push_front("A")
|
|||||||
|
|
||||||
assert_equal("A", x.front());
|
assert_equal("A", x.front());
|
||||||
assert_equal(3, x.back());
|
assert_equal(3, x.back());
|
||||||
|
|
||||||
|
// push_back newly constructed return value that's non-copyable
|
||||||
|
x.push_front(async(fun(){}))
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ assert_equal(true, int_type.bare_equal(1.get_type_info()))
|
|||||||
assert_equal(true, unsigned_int_type.bare_equal(1u.get_type_info()))
|
assert_equal(true, unsigned_int_type.bare_equal(1u.get_type_info()))
|
||||||
assert_equal(true, unsigned_long_type.bare_equal(1lu.get_type_info()))
|
assert_equal(true, unsigned_long_type.bare_equal(1lu.get_type_info()))
|
||||||
assert_equal(true, long_type.bare_equal(1l.get_type_info()))
|
assert_equal(true, long_type.bare_equal(1l.get_type_info()))
|
||||||
assert_equal(true, int64_t_type.bare_equal(1ll.get_type_info()))
|
assert_equal(true, long_long_type.bare_equal(1ll.get_type_info()))
|
||||||
assert_equal(true, uint64_t_type.bare_equal(1ull.get_type_info()))
|
assert_equal(true, unsigned_long_long_type.bare_equal(1ull.get_type_info()))
|
||||||
|
|
||||||
assert_equal(true, double_type.bare_equal(1.6.get_type_info()))
|
assert_equal(true, double_type.bare_equal(1.6.get_type_info()))
|
||||||
assert_equal(true, float_type.bare_equal(1.6f.get_type_info()))
|
assert_equal(true, float_type.bare_equal(1.6f.get_type_info()))
|
||||||
|
|||||||
7
unittests/octal_escapes.chai
Normal file
7
unittests/octal_escapes.chai
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
|
||||||
|
assert_equal("\71", "9")
|
||||||
|
assert_equal("\071", "9")
|
||||||
|
assert_equal("\71a", "9a")
|
||||||
|
assert_equal("b\71a", "b9a")
|
||||||
|
assert_equal("\71\70a", "98a")
|
||||||
|
|
||||||
7
unittests/operator_overload3.chai
Normal file
7
unittests/operator_overload3.chai
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
|
||||||
|
|
||||||
|
def string::`/=`(double d) { this = "${this}/=${d}"; return this; }
|
||||||
|
|
||||||
|
var s = "Hello World"
|
||||||
|
s /= 2
|
||||||
|
|
||||||
6
unittests/operator_overload4.chai
Normal file
6
unittests/operator_overload4.chai
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
|
||||||
|
|
||||||
|
def string::`*`(double d) { return "${this} * ${d}"; }
|
||||||
|
|
||||||
|
"Hello World" * 2
|
||||||
|
|
||||||
4
unittests/operator_parsing.chai
Normal file
4
unittests/operator_parsing.chai
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
assert_true(2>-1);
|
||||||
|
assert_false(3<-2);
|
||||||
|
assert_true(-1==-1);
|
||||||
|
|
||||||
7
unittests/order_of_operations.chai
Normal file
7
unittests/order_of_operations.chai
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
|
||||||
|
|
||||||
|
var s = ""
|
||||||
|
|
||||||
|
s += to_string(fun[s](){ s += "3"; 3}() % fun[s](){ s += "2"; 2}());
|
||||||
|
|
||||||
|
assert_equal(s, "321");
|
||||||
10
unittests/parser_test.chai
Normal file
10
unittests/parser_test.chai
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
auto p = parse("5 + 4");
|
||||||
|
|
||||||
|
try {
|
||||||
|
assert_equal(eval(p), 9)
|
||||||
|
} catch (e) {
|
||||||
|
print(e.pretty_print());
|
||||||
|
assert_true(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
18
unittests/switch_default_2.chai
Normal file
18
unittests/switch_default_2.chai
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
var total = 0;
|
||||||
|
|
||||||
|
switch(2) {
|
||||||
|
case (1) {
|
||||||
|
total += 1;
|
||||||
|
}
|
||||||
|
default {
|
||||||
|
total += 16;
|
||||||
|
}
|
||||||
|
case (3) {
|
||||||
|
total += 4;
|
||||||
|
}
|
||||||
|
case (4) {
|
||||||
|
total += 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_equal(total, 28)
|
||||||
18
unittests/vector_assignment.chai
Normal file
18
unittests/vector_assignment.chai
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
var v = []
|
||||||
|
v.push_back(3.4);
|
||||||
|
v.push_back(1);
|
||||||
|
v.push_back("bob");
|
||||||
|
|
||||||
|
assert_true(v[0] == 3.4)
|
||||||
|
assert_true(v[1] == 1)
|
||||||
|
assert_true(v[2] == "bob")
|
||||||
|
|
||||||
|
v[0] = 2.9
|
||||||
|
v[1] = 3
|
||||||
|
v[2] = "tom"
|
||||||
|
|
||||||
|
assert_true(v[0] == 2.9)
|
||||||
|
assert_true(v[1] == 3)
|
||||||
|
assert_true(v[2] == "tom")
|
||||||
|
|
||||||
|
|
||||||
5
unittests/vector_assignment_3.chai
Normal file
5
unittests/vector_assignment_3.chai
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
|
||||||
|
var v = []
|
||||||
|
v.push_back(int(1));
|
||||||
|
v[0] = 3;
|
||||||
|
|
||||||
@@ -11,3 +11,10 @@ auto uint16v = u16vector();
|
|||||||
uint16v.push_back(1u);
|
uint16v.push_back(1u);
|
||||||
assert_equal(1, uint16v.front());
|
assert_equal(1, uint16v.front());
|
||||||
|
|
||||||
|
|
||||||
|
// push_back newly constructed return value that's non-copyable
|
||||||
|
|
||||||
|
var v = []
|
||||||
|
v.push_back(async(fun(){}))
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user